MayaChemTools

   1 #!/usr/bin/perl -w
   2 #
   3 # $RCSfile: DBSchemaTablesToTextFiles.pl,v $
   4 # $Date: 2008/01/30 21:44:44 $
   5 # $Revision: 1.18 $
   6 #
   7 # Author: Manish Sud <msud@san.rr.com>
   8 #
   9 # Copyright (C) 2004-2008 Manish Sud. All rights reserved.
  10 #
  11 # This file is part of MayaChemTools.
  12 #
  13 # MayaChemTools is free software; you can redistribute it and/or modify it under
  14 # the terms of the GNU Lesser General Public License as published by the Free
  15 # Software Foundation; either version 3 of the License, or (at your option) any
  16 # later version.
  17 #
  18 # MayaChemTools is distributed in the hope that it will be useful, but without
  19 # any warranty; without even the implied warranty of merchantability of fitness
  20 # for a particular purpose.  See the GNU Lesser General Public License for more
  21 # details.
  22 #
  23 # You should have received a copy of the GNU Lesser General Public License
  24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
  25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
  26 # Boston, MA, 02111-1307, USA.
  27 #
  28 
  29 use 5.006;
  30 use strict;
  31 use FindBin; use lib "$FindBin::Bin/../lib";
  32 use Getopt::Long;
  33 use File::Basename;
  34 use Text::ParseWords;
  35 use Benchmark;
  36 use FileUtil;
  37 use TextUtil;
  38 use DBUtil;
  39 
  40 my($ScriptName, %Options, $StartTime, $EndTime, $TotalTime);
  41 
  42 # Autoflush STDOUT
  43 $| = 1;
  44 
  45 # Starting message...
  46 $ScriptName = basename($0);
  47 print "\n$ScriptName: Starting...\n\n";
  48 $StartTime = new Benchmark;
  49 
  50 # Get the options and setup script...
  51 SetupScriptUsage();
  52 if ($Options{help} || @ARGV < 1) {
  53   die GetUsageFromPod("$FindBin::Bin/$ScriptName");
  54 }
  55 
  56 my($DBDriver, $DBHost, $DBName, $DBUser, $DBPassword, $DBMode, $ExportDataLabels, $ExportLOBs, $OutDelim, $OutQuote, $ReplaceNullStr);
  57 ProcessOptions();
  58 
  59 # Connect to database...
  60 my($DBHandle);
  61 print "Connecting to $DBDriver:database=$DBName as $DBUser...\n";
  62 $DBHandle = DBConnect($DBDriver, $DBName, $DBHost, $DBUser, $DBPassword);
  63 
  64 # Collect input parameters information...
  65 print "Checking input parameter(s)...\n";
  66 my(@DBSchemaNames, @DBTableNames, @DBSQLStatements, @DBTextFiles, $SingleTextFileName);
  67 RetrieveDBInfo();
  68 
  69 if ($Options{numoutfiles} =~ /^single$/i ) {
  70   GenerateSingleTextFile();
  71 }
  72 else {
  73   GenerateMultipleTextFiles();
  74 }
  75 print "\nDisconnecting from  $DBDriver:database=$DBName...\n";
  76 DBDisconnect($DBHandle);
  77 
  78 print "$ScriptName:Done...\n\n";
  79 
  80 $EndTime = new Benchmark;
  81 $TotalTime = timediff ($EndTime, $StartTime);
  82 print "Total time: ", timestr($TotalTime), "\n";
  83 
  84 ###############################################################################
  85 
  86 # Generate multiple text files...
  87 sub GenerateMultipleTextFiles {
  88   my($Index, $TextFile, $SQL);
  89   if (@DBTextFiles > 1) {
  90     print "Generating text files...\n";
  91   }
  92  TEXTFILE: for $Index (0 .. $#DBTextFiles) {
  93     $TextFile = $DBTextFiles[$Index];
  94     $SQL = $DBSQLStatements[$Index];
  95 
  96     if (@DBTextFiles > 1) {
  97       print "\nGenerating text file $TextFile...\n";
  98     }
  99     else {
 100       print "Generating text file $TextFile...\n";
 101     }
 102 
 103     if (!open TEXTFILE, ">$TextFile") {
 104       warn "Warning: Abandoning $TextFile generation: Couldn't open it: $! \n";
 105       next TEXTFILE;
 106     }
 107     print "Processing SQL statement \"$SQL\"...\n";
 108 
 109     if (DBSQLToTextFile($DBHandle, $SQL, \*TEXTFILE, $OutDelim, $OutQuote, $ExportDataLabels, $ExportLOBs, $ReplaceNullStr)) {
 110       warn "Warning: Abandoning $TextFile generation...\n";
 111       next TEXTFILE;
 112     }
 113     close TEXTFILE;
 114   }
 115 }
 116 
 117 # Generate single text file...
 118 sub GenerateSingleTextFile {
 119   my($Index, $TextFile, $SQL, $SchemaName, $TableName);
 120 
 121   open TEXTFILE, ">$SingleTextFileName" or die "Couldn't open $SingleTextFileName: $! \n";
 122   print "Generating text file $SingleTextFileName...\n";
 123 
 124   SQL: for $Index (0 .. $#DBSQLStatements) {
 125     $SchemaName = $DBSchemaNames[$Index];
 126     $TableName = $DBTableNames[$Index];
 127     $SQL = $DBSQLStatements[$Index];
 128 
 129     $TableName = qq($SchemaName.$TableName);
 130     $TableName = QuoteAWord($TableName, $OutQuote);
 131     print TEXTFILE "\n\n$TableName\n";
 132 
 133     if (DBSQLToTextFile($DBHandle, $SQL, \*TEXTFILE, $OutDelim, $OutQuote, $ExportDataLabels, $ExportLOBs, $ReplaceNullStr)) {
 134       warn "Warning: Abandoning table $TableName ...\n";
 135       next SQL;
 136     }
 137   }
 138   close TEXTFILE;
 139 }
 140 
 141 # Collect input parameters information...
 142 sub RetrieveDBInfo {
 143   my($FileExt, $UserFileName, $FileDBPrefix);
 144 
 145   # Setup out file ext...
 146   $FileExt = ($Options{outdelim} =~ /^tab$/i) ? "tsv" : "csv";
 147   $FileDBPrefix = ($DBMode =~ /^exportdata$/i) ? "Export" : "Describe";
 148 
 149   # Get user specified information...
 150   $UserFileName = "";
 151   if ($Options{root} && (@ARGV == 1)) {
 152     my($RootFileDir, $RootFileName, $RootFileExt) = ParseFileName($Options{root});
 153     if ($RootFileName && $RootFileExt) {
 154       $UserFileName = $RootFileName;
 155     }
 156     else {
 157       $UserFileName = $Options{root};
 158     }
 159   }
 160   $SingleTextFileName = "";
 161   if ($Options{numoutfiles} =~ /^single$/i) {
 162     $SingleTextFileName = $UserFileName ? $UserFileName : ("$FileDBPrefix" . "SchemaTables");
 163     $SingleTextFileName .= ".$FileExt";
 164   }
 165 
 166   # For each input schema name: collect all the table names, set up appropriate
 167   # SQL statements, and output file names...
 168   #
 169   my($SchemaName, $SQL, $FileName, @SchemaTableNames, $TableName);
 170   @DBSchemaNames = ();
 171   @DBTableNames = ();
 172   @DBSQLStatements = ();
 173   @DBTextFiles = ();
 174   @SchemaTableNames = ();
 175   SCHEMANAME: for $SchemaName (@ARGV) {
 176     $SchemaName = uc $SchemaName;
 177     if (!(@SchemaTableNames = DBFetchSchemaTableNames($DBDriver, $DBHandle, $SchemaName))) {
 178       warn "Warning: Ignoring schema $SchemaName...\n";
 179       next SCHEMANAME;
 180     }
 181     # Prepare SQL statement for each table.
 182     for $TableName (@SchemaTableNames) {
 183       push @DBSchemaNames, $SchemaName;
 184       push @DBTableNames, $TableName;
 185       $SQL = ($DBMode =~ /^exportdata$/i) ? DBSetupSelectSQL($DBDriver, $TableName, $SchemaName) : DBSetupDescribeSQL($DBDriver, $TableName, $SchemaName);
 186       push @DBSQLStatements, $SQL;
 187       if ($Options{numoutfiles} =~ /^multiple$/i) {
 188 	$FileName = $UserFileName ? ("$UserFileName" . "$TableName") : ("$FileDBPrefix" . "$SchemaName" . "$TableName");
 189 	$FileName .= ".$FileExt";
 190 	if (!$Options{overwrite}) {
 191 	  if (-e $FileName) {
 192 	    die "Error: The file $FileName already exists.\n";
 193 	  }
 194 	}
 195 	push @DBTextFiles, $FileName;
 196       }
 197     }
 198   }
 199 }
 200 
 201 # Process option values...
 202 sub ProcessOptions {
 203 
 204   $DBDriver = $Options{dbdriver} ? $Options{dbdriver} : (exists $ENV{DBI_DRIVER} ? $ENV{DBI_DRIVER} : "") ;
 205   if ($DBDriver) {
 206     if ($DBDriver =~ /^oracle$/i) {
 207       $DBDriver = "Oracle";
 208     }
 209     elsif ($DBDriver =~ /^mysql$/i) {
 210       $DBDriver = "mysql";
 211     }
 212     else {
 213       if ($Options{dbdriver}) {
 214 	die "Error: The value specified, $DBDriver, for option \"-d --dbdriver\" is not valid. Allowed values: MySQL or Oracle\n";
 215       }
 216       else {
 217 	die "Error: The value specified, $DBDriver, using environment variable DBI_DRIVER not valid. Allowed values: MySQL or Oracle\n";
 218       }
 219     }
 220   }
 221   else {
 222     $DBDriver = "mysql";
 223   }
 224   $DBHost = $Options{dbhost} ? $Options{dbhost} : "127.0.0.1";
 225   $DBName = $Options{dbname} ? $Options{dbname} : "";
 226   if (!$DBName) {
 227     if ($DBDriver =~ /^mysql$/i) {
 228       $DBName = "mysql";
 229     }
 230     elsif ($DBDriver =~ /^Oracle$/i) {
 231       $DBName = exists $ENV{ORACLE_SID} ? $ENV{ORACLE_SID} : "";
 232     }
 233   }
 234   $DBUser = $Options{dbusername} ? $Options{dbusername} : (exists $ENV{DBI_USER} ? $ENV{DBI_USER} : "") ;
 235   if (!$DBUser) {
 236     die "Error: No database username specified. Use \"--dbusername\" option or environment variable DBI_USER to enter a valid value.\n";
 237   }
 238   $DBPassword = $Options{dbpassword} ? $Options{dbpassword} : (exists $ENV{DBI_PASS} ? $ENV{DBI_PASS} : "") ;
 239   if (!$DBPassword) {
 240     die "Error: No database password specified. Use \"--dbpassword\" option or environment variable DBI_PASS to enter a valid value.\n";
 241   }
 242   $DBMode = $Options{mode};
 243   $ExportLOBs = ($Options{exportlobs} =~ /^yes$/i) ? 1 : 0;
 244   $ExportDataLabels = ($DBMode =~ /^describetable$/i) ? 1 : (($Options{exportdatalabels} =~ /^yes$/i) ? 1 : 0);
 245 
 246   $OutDelim = ($Options{outdelim} =~ /^tab$/i ) ? "\t" : (($Options{outdelim} =~ /^semicolon$/i) ? "\;" : "\,");
 247   $OutQuote = ($Options{quote} =~ /^yes$/i) ? 1 : 0;
 248 
 249   $ReplaceNullStr = (defined($Options{replacenullstr}) && length($Options{replacenullstr})) ? $Options{replacenullstr} : "";
 250 }
 251 
 252 # Setup script usage  and retrieve command line arguments specified using various options...
 253 sub SetupScriptUsage {
 254 
 255   # Retrieve all the options...
 256   %Options = ();
 257   $Options{mode} = "exportdata";
 258   $Options{exportlobs} = "no";
 259   $Options{exportdatalabels} = "yes";
 260   $Options{numoutfiles} = "single";
 261   $Options{outdelim} = "comma";
 262   $Options{quote} = "yes";
 263 
 264   if (!GetOptions(\%Options, "dbdriver|d=s", "dbhost=s", "dbname=s", "dbpassword=s", "dbusername=s", "exportdatalabels=s", "exportlobs=s", "help|h", "mode|m=s", "numoutfiles|n=s", "outdelim=s", "overwrite|o", "quote|q=s", "root|r=s", "replacenullstr=s", "workingdir|w=s")) {
 265     die "\nTo get a list of valid options and their values, use \"$ScriptName -h\" or\n\"perl -S $ScriptName -h\" command and try again...\n";
 266   }
 267   if ($Options{workingdir}) {
 268     if (! -d $Options{workingdir}) {
 269       die "Error: The value specified, $Options{workingdir}, for option \"-w --workingdir\" is not a directory name.\n";
 270     }
 271     chdir $Options{workingdir} or die "Error: Couldn't chdir $Options{workingdir}: $! \n";
 272   }
 273   if ($Options{exportdatalabels} !~ /(^(yes|no)$)/i) {
 274     die "Error: The value specified, $Options{exportlobs}, for option \"--exportdatalabels\" is not valid. Allowed values: yes or no\n";
 275   }
 276   if ($Options{exportlobs} !~ /(^(yes|no)$)/i) {
 277     die "Error: The value specified, $Options{exportlobs}, for option \"--exportlobs\" is not valid. Allowed values: yes or no\n";
 278   }
 279   if ($Options{numoutfiles} !~ /(^(single|multiple)$)/i) {
 280     die "Error: The value specified, $Options{mode}, for option \"-n --numoutfiles\" is not valid. Allowed values: single or multiple\n";
 281   }
 282   if ($Options{mode} !~ /(^(exportdata|describetable)$)/i) {
 283     die "Error: The value specified, $Options{mode}, for option \"-m --mode\" is not valid. Allowed values: exportdata or describetable\n";
 284   }
 285   if ($Options{outdelim} !~ /^(comma|semicolon|tab)$/i) {
 286     die "Error: The value specified, $Options{outdelim}, for option \"--outdelim\" is not valid. Allowed values: comma, tab, or semicolon\n";
 287   }
 288   if ($Options{quote} !~ /^(yes|no)$/i) {
 289     die "Error: The value specified, $Options{quote}, for option \"-q --quote\" is not valid. Allowed values: yes or no\n";
 290   }
 291 }
 292