################################################################################# # # $Header: SQLFile.pm 10-aug-2006.21:41:27 chyu Exp $ # # SQLFile.pm # # Copyright (c) 2003, 2006, Oracle. All rights reserved. # # NAME # SQLFile.pm - # # DESCRIPTION # # # NOTES # # # MODIFIED (MM/DD/YYYY) # chyu 08/10/06 - adding the condition flag # gsbhatia 12/15/05 - bug 4888848 # chyu 11/14/05 - XbranchMerge chyu_bug-4703513 from main # chyu 10/28/05 - using the EMDW_HOME for SQLFile root # tthakur 08/08/05 - adding post_data_upgrade # gsbhatia 07/26/05 - bug 4515615 # gsbhatia 07/22/05 - Add getters/setters # gsbhatia 07/19/05 - Refactor code # gsbhatia 07/16/05 - Add logging support # gsbhatia 06/26/05 - New repmgr impl # gsbhatia 04/11/05 - Adding header accessor API # gsbhatia 01/20/05 - change comparison string from migrate to upgrade # gsbhatia 01/18/05 - fill skeleton code # ktlaw 01/14/05 - add comments # ktlaw 01/13/05 - ktlaw_new_repmgr # ktlaw 01/10/05 - created ################################################################################ package SQLFile; use strict; use File::Basename; use Logger; sub log{ my ($self, $msg) = @_; $self->getLogger->infoln(qq($msg)); } sub getLogger{ my $self = shift; return $self->{'logger'}; } sub setLogger{ my ($self, $v) = @_; $self->{'logger'} = $v; } sub getIsValid{ my $self = shift; return $self->{'isValid'}; } sub setIsValid{ my ($self, $v) = @_; $self->{'isValid'} = $v; } sub getPath{ my $self = shift; return $self->{'path'}; } sub setPath{ my ($self, $v) = @_; $self->{'path'} = $v; } sub getComponentRoot{ my $self = shift; return $self->{'componentRoot'}; } sub setComponentRoot{ my ($self, $v) = @_; $self->{'componentRoot'} = $v; } sub getBasedir{ my $self = shift; return $self->{'basedir'}; } sub setBasedir{ my ($self, $v) = @_; $self->{'basedir'} = $v; } sub getPathRelativeToBasedir{ my $self = shift; return $self->{'pathRelativeToBasedir'}; } sub setPathRelativeToBasedir{ my ($self, $v) = @_; $self->{'pathRelativeToBasedir'} = $v; } sub getComponent{ my $self = shift; return $self->{'component'}; } sub setComponent{ my ($self, $v) = @_; $self->{'component'} = $v; } sub getFu{ my $self = shift; return $self->{'fu'}; } sub setFu{ my ($self, $v) = @_; $self->{'fu'} = $v; } sub getExt{ my $self = shift; return $self->{'ext'}; } sub setExt{ my ($self, $v) = @_; $self->{'ext'} = $v; } sub getDir{ my $self = shift; return $self->{'dir'}; } sub setDir{ my ($self, $v) = @_; $self->{'dir'} = $v; } sub getName{ my $self = shift; return $self->{'name'}; } sub setName{ my ($self, $v) = @_; $self->{'name'} = $v; } sub getParams{ my $self = shift; return @{$self->{'params'}}; } sub setParams{ my ($self, $v) = @_; $self->{'params'} = \$v; } sub getParamsRef{ my $self = shift; return $self->{'params'}; } sub setParamsRef{ my ($self, $v) = @_; $self->{'params'} = $v; } sub getOperation{ my $self = shift; return $self->{'operation'}; } sub setOperation{ my ($self, $v) = @_; $self->{'operation'} = $v; } sub getHeader{ my $self = shift; return $self->{'header'}; } sub setHeader{ my ($self, $v) = @_; $self->{'header'} = $v; } sub getSeq{ my $self = shift; return $self->{'seq'}; } sub setSeq{ my ($self, $v) = @_; $self->{'seq'} = $v; } sub getSequence{ my $self = shift; return $self->getSeq; } sub setSequence{ my ($self, $v) = @_; $self->setSeq($v); } sub getPos{ my $self = shift; return $self->{'pos'}; } sub setPos{ my ($self, $v) = @_; $self->{'pos'} = $v; } sub setCondition{ my ($self, $v) = @_; my %conditionHash = split(/[=;]/,$v); foreach my $k (keys %conditionHash) { $self->{'condition'}{$k} = $conditionHash{$k}; } } sub hasConditions{ my $self = shift; if (defined $self->{'condition'}) { return 1; } return 0; } sub getConditionKeys{ my $self = shift; if (defined $self->{'condition'}) { my $hash = $self->{'condition'}; return keys(%$hash); } return (); } sub getCondition{ my ($self, $v) = @_; if (defined $self->{'condition'}) { return $self->{'condition'}{$v}; } return undef; } sub getVer{ my $self = shift; return $self->{'ver'}; } sub setVer{ my ($self, $v) = @_; $self->{'ver'} = $v; } sub getVersion{ my $self = shift; return $self->getVer; } sub setVersion{ my ($self, $v) = @_; $self->setVer($v); } sub getType{ my $self = shift; return $self->{'type'}; } sub setType{ my ($self, $v) = @_; $self->{'type'} = $v; } sub getAfuDir{ my $self = shift; return $self->{'afuDir'}; } sub setAfuDir{ my ($self, $v) = @_; $self->{'afuDir'} = $v; } sub getAfuName{ my $self = shift; return $self->{'afuName'}; } sub setAfuName{ my ($self, $v) = @_; $self->{'afuName'} = $v; } sub getAfuExt{ my $self = shift; return $self->{'afuExt'}; } sub setAfuExt{ my ($self, $v) = @_; $self->{'afuExt'} = $v; } sub getAfuProcessed{ my $self = shift; return $self->{'afuProcessed'}; } sub setAfuProcessed{ my ($self, $v) = @_; $self->{'afuProcessed'} = $v; } sub new{ my ($class) = @_; my $ref = {}; bless $ref, $class; $ref->setLogger(Logger->new()); return $ref; } sub init{ my ($ref, $p) = @_; #Assume the sql is invalid by default. #If it turns out to valid, it will be marked so later. $ref->setIsValid(0); $ref->setPath($p); my $oracleHome = $ENV{'EMDW_HOME'}; if ( $oracleHome eq "" ) { $oracleHome = $ENV{'ORACLE_HOME'}; } my $sqlHome = "$oracleHome/sysman/admin/emdrep/sql"; #Get component name my $comp; if ($ref->getComponentRoot =~ m/$sqlHome\/(.+)/){ #If can't even find component home, return #In this case sql has already been marked as invalid if (!defined $1){ return;} $comp = $1; } if (!defined $comp){ return;} my $regex = qr/$sqlHome\/$comp\/(.+?)\/((?:(.+)\/)*(.+)\.(sql|plb))$/; #Consider the sql for further processing only if it matches #the file location pattern. #For instance, file must be located in this fashion: #$SQLROOT//basedir/... file can now be anywhere .. #All position attribute references are relative to the basedir #Directory immediately after base dir is the functional unit directory #Finally, at the end, we get the file under consideration if($p =~ $regex){ $ref->setBasedir($1); $ref->setPathRelativeToBasedir($2); $ref->setComponent( $comp) ; if (defined $3){ $ref->setFu($3) ; }else{ $ref->setFu(''); } $ref->setExt($5); $ref->setName(basename($p)); $ref->setDir(dirname($p)); #Initialize the afu $ref->setAfuDir($ref->createAfuDir($ref->getFu)); $ref->setAfuName($4); $ref->setAfuExt($ref->getExt); $ref->setAfuProcessed(0); #Parse the header $ref->parse; } } #This creates the afuDir data structure sub createAfuDir{ my ($self, $str) = @_; my @a = split(/\//, $str); return \@a; } sub trimLine { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } #Parse the header and fetch the details sub parse { my $ref = shift ; if(defined $ref->getPath) { if(open(F,$ref->getPath)) { while() { chomp ($_ = &trimLine($_)); #Construct the repmgr header driver regex my $headerRegex = qr/^\s*[rR][eE][mM]\s+[dD][rR][vV]\s*:\s*(.*?)\s*$/; if($_ =~ $headerRegex) { my $header = $1; #Construct the create header regex my $createRegex = qr/^<\s*create\s+type\s*=\s* (?:'|")(types|tables|indexes|procs|funcs|triggers|views|pkgdefs|pkgbodys|init|type_bodys|synonyms|post_creation|out_of_box)(?:'|") (?:\s+seq\s*=\s*(?:"|')(.+?)(?:"|'))? (?:\s+params\s*=\s*(?:"|')(.+?)(?:"|'))? (?:\s+pos\s*=\s*(?:"|')(.+?)(?:"|'))? (?:\s+condition\s*=\s*(?:"|')(.+?)(?:"|'))? \s*\/>/x; #Construct the migrate header regex my $migrateRegex=qr/^<\s*migrate\s+type\s*=\s* (?:'|")(schema_upgrade|data_upgrade|schema_downgrade|data_downgrade|pre_data_upgrade|pre_schema_upgrade|pre_schema_downgrade|pre_data_downgrade|post_data_upgrade)(?:'|") (?:\s+version\s*=\s*(?:'|")(.+?)(?:'|"))? (?:\s+seq\s*=\s*(?:'|")(.+?)(?:'|"))? (?:\s+params\s*=\s*(?:"|')(.+?)(?:"|'))? (?:\s+pos\s*=\s*(?:'|")(.+?)(?:'|"))? (?:\s+condition\s*=\s*(?:"|')(.+?)(?:"|'))? \s*\/>/x; my $paramsRegex = qr/ EM_SQL_ROOT|EM_REPOS_USER|EM_REPOS_PWD| EM_REPOS_MODE|EM_TEMP_TABLESPACE_NAME|EM_TABLESPACE_NAME| EM_DEFAULT_DATAFILE_NAME|EM_DEFAULT_DATAFILE_INIT_SIZE| EM_DEFAULT_DATAFILE_EXTEND_SIZE|EM_ECM_DEPOT_TABLESPACE| EM_ECM_DATAFILE_NAME|EM_ECM_DATAFILE_INIT_SIZE| EM_ECM_CSA_TABLESPACE_NAME|EM_ECM_CSA_DATAFILE_NAME| EM_ECM_CSA_DATAFILE_SIZE|EM_ECM_CSA_DATAFILE_EXT_SIZE| EM_ECM_DATAFILE_EXTEND_SIZE|EM_ECHO_SQL /x; #Check if header matches create's pattern if ($header =~ $createRegex){ #Now the SQL is guaranteed to be valid, mark it so. $ref->setIsValid(1); $ref->setOperation('create'); $ref->setHeader($header); $ref->setType($1); if (defined $2){ $ref->setSeq($2);} else{ $ref->setSeq(0);} my @params; #set params in the object model only if they are valid if (defined $3){ @params = split /,/, $3; for (@params){ if (!$paramsRegex){ undef @params; last; } } } if(defined @params){ $ref->setParamsRef(\@params); }else{ $ref->setParamsRef([]); } $ref->setPos($4) if (defined $4); $ref->setCondition($5) if (defined $5); last; } #Check if the header instead matches the migrate pattern elsif ($header =~ $migrateRegex){ #Default SQL to be valid, marking it so. $ref->setIsValid(1); $ref->setOperation('migrate'); $ref->setHeader($header); $ref->setType($1); if (defined $2) {$ref->setVer($2);} #only post_data_upgrade types are version neutral.O/w mark sql as invalid. if (($ref->getType() ne qw(post_data_upgrade)) && !(defined($ref->getVer()))) {$ref->setIsValid(0)}; if (defined $3){ $ref->setSeq($3);} else{ $ref->setSeq(0);} my @params; #set params in the object model only if they are valid if (defined $4){ @params = split /,/, $4; for (@params){ if (!$paramsRegex){ undef @params; last; } } } if(defined @params){ $ref->setParamsRef(\@params); }else{ $ref->setParamsRef([]); } $ref->setPos($5) if (defined $5); $ref->setCondition($6) if (defined $6); last; } } } close(F); }else { #log error and die? #$ref->getLogger->warnAndDie("Can't open file: $ref->getPath"); #Don't die but issue an error instead $ref->log("ERROR: Can't open file: $ref->getPath"); $ref->log("ERROR: Note: $ref->getPath will not be queued for execution by RepMgr"); } }else { #log error and die? #Don't die but issue an error instead $ref->log("ERROR: Doesn't exist: $ref->getPath"); } } #The sql object dump for debugging purposes sub dumpObject { my $ref = shift; $ref->log(""); if ($ref->getIsValid){ foreach my $key (keys %$ref){ my $val = $ref->{$key}; $ref->log(qq($key: $val)) if (!ref($val)); $ref->log(qq($key: @$val)) if (ref($val) eq 'ARRAY'); } }else{ $ref->log(qq($ref->getPath)); $ref->getLogger->warn("Invalid object"); } $ref->log(""); } 1;