#!/usr/local/bin/perl ############################################################ ### Program Name: archive_data.pl ### Author: Darryl Priest ### Date: 2002 ### Description: This program will archive data from the ### passed database and table to archive ### files based on unique values in the ### selection column. ############################################################ $| =1; use DBI; use Getopt::Std; use lib q{/custom/perl/modules/bin}; use GenLib qw(commify_integer); use vars qw($opt_a $opt_c $opt_d $opt_k $opt_o $opt_s $opt_t $opt_v $opt_w $opt_u $opt_x); my $Usage = qq# Usage: $0 [ -d Database -t Table ] [< -k File Split Column Key >] [< -c Column -o Operator -v Threshold Value >] [< -s Output Directory -a Append Existing Files >] [< -w Where -u Save Deletes -x Experimental Delete >] -d Database Name -t Database Table To Be Archived -k Key Column Used To Split Output Files -c Column Name To Key Archive Selection -o Operator To Determine Which Data To Keep -v Threshold Value For The Key Column -a Append To Existing Output Files -s Directory To Save The Archived Data -w Optional Additional Where Clause -u Save Deleted Rows In Unload Type Files -x Experimental, Don't Actually Delete, Just Count #; ############################################################ ### Define Usage Variables And Get From Passed Options ############################################################ my ($Append, $Column, $Database, $SplitKey, $Operator, $Table); my ($Threshold, $Where, $Directory, $Delete, $Write); getopts('ac:d:k:o:s:t:v:w:ux'); ############################################################ ### Make Sure The Table And Database Are Passed ############################################################ if ( defined $opt_d ) { $Database = $opt_d; } else { print $Usage; exit; } if ( defined $opt_t ) { $Table = $opt_t; } else { print $Usage; exit; } ############################################################ ### Get Optional Where Clause ############################################################ if ( defined $opt_w ) { $Where = $opt_w; } ############################################################ ### Get Optional Save Deletes Option ############################################################ if ( defined $opt_u ) { $Write = 1; } else { $Write = 0; } ############################################################ ### Get Output File Split Key ############################################################ if ( defined $opt_k ) { $SplitKey = $opt_k; } ############################################################ ### If Column Selection Criteria Is Passed, Make Sure The ### Correct Pieces Have All Been Passed ############################################################ if ( defined $opt_c ) { $Column = $opt_c; } if ( defined $opt_o ) { $Operator = $opt_o; } elsif ( defined $Column ) { $Operator = "="; } if ( defined $opt_v ) { $Threshold = $opt_v; ######################################################### ### If The Threshold Has Non Digits, Quote It, Unless ### It's Already Been Quoted ######################################################### if ( $Threshold =~ /\D/ ) { if ( $Threshold !~ /[\"\']/ ) { $Threshold = qq#"$Threshold"#; } } } ############################################################ ### Get Optional Output Directory ############################################################ if ( defined $opt_s ) { $Directory = $opt_s; $Write = 1; } else { $Directory = $Table; } ############################################################ ### Get Optional X Options, Doesn't Actually Delete Data ############################################################ if ( defined $opt_x ) { $Delete = 0; } else { $Delete = 1; } ############################################################ ### Get Append Option, If Exists, Otherwise Default To Not Append ############################################################ if ( defined $opt_a ) { $Append = 1; $Write = 1; } else { $Append = 0; } ############################################################ ### Display Passed Options Back To User ############################################################ print "\n\n", '>' x 60, "\n"; print "Preparing To Archive Data From ${Database}:${Table} ...\n"; if ( $Write ) { print "Data Rows To Be Deleted Will Be Saved In Directory $Directory\n"; } else { print "Deleted Data Rows Will Not Be Written To Files\n"; } if ( $Append ) { print "Existing Output Files Will Be Appended To\n"; } ############################################################ ### Build SQL To Select Data Rows To Be Archived ############################################################ my ($sql, $SC, $WC); $SC = qq#select#; if ( defined $SplitKey ) { print "Output Files Will Be Split By Key $SplitKey\n"; $SC .= qq# $SplitKey,#; } $SC .= qq# rowid, * from $Table#; if ( defined $Operator and defined $Threshold ) { print "Limiting Data Selection By $Column $Operator $Threshold\n"; $WC = qq#$Column $Operator $Threshold#; } if ( defined $Where ) { print "Further Restricted By: $Where\n"; if ( defined $WC ) { $WC .= qq# and#; } $WC .= qq# $Where#; } if ( defined $WC ) { $sql = qq#$SC where $WC#; } else { $sql = $SC; } print "\nSelect Data Rows With SQL:\n$sql\n"; if ( ! $Delete ) { print "\nOnly Unloading Data, No Rows Will Be Deleted!!!\n"; } ############################################################ ### Verify Input Selections, If Running Interactively ############################################################ if ( -t STDIN and -t STDOUT ) { print "\nPress Any Key To Continue Or Control-C To Cancel\n"; my $Continue = getc(); } ############################################################ ### Make Directory To Write The Archived Data Out To ############################################################ if ( $Write ) { if ( ! -d $Directory ) { print "Creating Directory $Directory For Output Files At ", `date +'%D %r'`; mkdir ($Directory, 0777) or die "Error Creating Directory For Output $Directory, $!\n"; } } ############################################################ ### Open The Select Connection To The Database ############################################################ my $dbh = DBI->connect("DBI:Informix:$Database") or die "$Database Database Open Error: $DBI::errstr\n"; $dbh->{ChopBlanks} = 1; $dbh->{AutoCommit} = 1; $dbh->{PrintError} = 1; $dbh->{RaiseError} = 1; ############################################################ ### Set The Database Lock Mode ############################################################ $dbh->do("set lock mode to wait 300"); ############################################################ ### Build Statement Handle To Select Rows To Be Deleted ############################################################ my $select_sth = $dbh->prepare($sql); $select_sth->execute(); ############################################################ ### Get Current Row Count From The Table ############################################################ $sql = qq#select count(*) from $Table#; my $count_sth = $dbh->prepare($sql); $count_sth->execute(); my ($OrigCount) = $count_sth->fetchrow_array(); print "\n\nBefore Deletions $Table Has ", commify_integer($OrigCount), " Rows\n"; ############################################################ ### Get Current Max Rowid From The Table ############################################################ $sql = qq#select max(rowid) from $Table#; my ($OrigMaxRowId) = $dbh->selectrow_array($sql); print "Max RowId In $Table Is ", commify_integer($OrigMaxRowId), " \n\n"; ############################################################ ### Prepare Delete Handle, Deleting By Rowid ############################################################ $sql = qq#delete from $Table where rowid = ?#; my $del_sth = $dbh->prepare($sql); ############################################################ ### Process Rows To Be Deleted Writing To Key Driven Output ### Files And Save The Rowids To Delete Later ############################################################ my (@DataRow, $KeyValue, $RowId, %Files, $FileHandle, $NewFile); my $DelRows = 0; while ( @DataRow = $select_sth->fetchrow_array() ) { if ( $DelRows > 0 and ( $DelRows % 10000 ) == 0 ) { print commify_integer($DelRows), " Rows Read For Delete At ", `date +'%D %r'`; } ######################################################### ### If Archiving Using A Column Get That Column From The ### Results, Otherwise Use Set To A Default Values, Also ### Get The Rowid From The Fetch Array ######################################################### if ( defined $SplitKey ) { $KeyValue = shift(@DataRow); } else { $KeyValue = "all"; } $RowId = shift(@DataRow); ######################################################### ### If The Key Data Column Is Not Defined Skip The Row ######################################################### if ( ! defined $KeyValue ) { next; } ######################################################### ### If This Key Has Not Been Processed Yet, Open A New ### Output File For This Key ######################################################### if ( ! defined $Files{$KeyValue}{Key} ) { $Files{$KeyValue}{Key} = $KeyValue; $Files{$KeyValue}{FileName} = "${Directory}/${Table}_${KeyValue}.unl"; ###################################################### ### If Deleted Rows Are To Be Written, Check For Existing ### Files, And Open The Appropriate File Handle ###################################################### if ( $Write ) { ################################################### ### If The File Already Exists & We're Not Appending ### Move The Old File To A .old File ################################################### if ( -f $Files{$KeyValue}{FileName} ) { $NewFile = "$Files{$KeyValue}{FileName}.old"; if ( ! $Append ) { rename $Files{$KeyValue}{FileName}, $NewFile; } } ################################################### ### Open The New File ################################################### $Files{$KeyValue}{Handle} = $KeyValue; open ($Files{$KeyValue}{Handle}, ">> $Files{$KeyValue}{FileName}") or die "Error Opening $Files{$KeyValue}{FileName}, $!\n"; } } ######################################################### ### If Deletes Are Being Saved, Clean Up The Data & ### Write It To The Correct File ######################################################### if ( $Write ) { ###################################################### ### Convert NULLs Into Empty Strings ###################################################### map { $_ = "" unless defined $_ } @DataRow; ###################################################### ### Write This Row To The Appropriate File, If Deletes ### Are Being Saved ###################################################### $FileHandle = $Files{$KeyValue}{Handle}; print $FileHandle join('|', @DataRow), "|\n"; } $Files{$KeyValue}{Count}++; ######################################################### ### Actually Delete The Row ######################################################### if ( $Delete ) { $del_sth->execute($RowId); } $DelRows++; } print "\nProcessed ", commify_integer($DelRows), " Rows From $Table At ", `date +'%D %r'`; ############################################################ ### Close All Output Files ############################################################ my ($x); print "\n"; if ( $Write ) { print "Closing Output Files At ", `date +'%D %r'`; } foreach $x ( sort keys %Files ) { if ( $x ne "all" ) { print "Found ", commify_integer($Files{$x}{Count}), " Rows For $SplitKey = $x\n"; } if ( $Write ) { $FileHandle = $Files{$x}{Handle}; close $FileHandle; } } ############################################################ ### Recheck The Row Count From The Table ############################################################ $count_sth->execute(); my ($NewCount) = $count_sth->fetchrow_array(); print "\nThe Table $Table Now Has ", commify_integer($NewCount), " Rows\n"; ############################################################ ### Check For Rows With RowIds Greater Than The Max From ### When The Program Started ############################################################ $sql = qq#select count(*) from $Table where rowid > $OrigMaxRowId#; my ($NewRows) = $dbh->selectrow_array($sql); print "Found ", commify_integer($NewRows), " With RowIds > ", commify_integer($OrigMaxRowId), "\n"; ############################################################ ### Display Warnings If Row Count Or Row Id Checks Fail ############################################################ if ( $Delete ) { if ( ( $OrigCount - $DelRows != $NewCount ) or $NewRows > 0 ) { print "\n\n", '!' x 60, "\n"; print "Potential Deletion Problems\n"; print "Table $Table Had ", commify_integer($OrigCount), " Rows, ", commify_integer($DelRows), " Were To Be Deleted, But Count Is ", commify_integer($NewCount), "\n"; print "Found ", commify_integer($NewRows), " With RowIds > ", commify_integer($OrigMaxRowId), "\n"; print '!' x 60, "\n"; } else { print "Appears To Have Processed Correctly\n"; } } ############################################################ ### Disconnect From Databases ############################################################ $dbh->disconnect(); print "\n", '>' x 60, "\n"; print "Finished Archiving ${Database}:${Table} At ", `date +'%D %r'`;