MayaChemTools

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