1 package DBUtil; 2 # 3 # $RCSfile: DBUtil.pm,v $ 4 # $Date: 2011/12/16 00:04:11 $ 5 # $Revision: 1.28 $ 6 # 7 # Author: Manish Sud <msud@san.rr.com> 8 # 9 # Copyright (C) 2004-2012 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 strict; 30 use Exporter; 31 use Carp; 32 use DBI; 33 use TextUtil; 34 35 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 36 37 @ISA = qw(Exporter); 38 @EXPORT = qw(DBConnect DBDisconnect DBFetchSchemaTableNames DBSetupDescribeSQL DBSetupSelectSQL DBSQLToTextFile); 39 @EXPORT_OK = qw(); 40 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); 41 42 # Connect to a specified database... 43 sub DBConnect { 44 my($DBDriver, $DBName, $DBHost, $DBUser, $DBPassword) = @_; 45 my($DBHandle, $DataSource); 46 47 if ($DBDriver eq "Oracle") { 48 $DataSource = ($DBName && $DBHost) ? (qq(DBI:$DBDriver:sid=$DBName;host=$DBHost)) : (qq(DBI:$DBDriver:$DBHost)); 49 } 50 else { 51 $DataSource = qq(DBI:$DBDriver:database=$DBName); 52 if ($DBHost) { 53 $DataSource .= qq(;host=$DBHost); 54 } 55 } 56 57 # Don't raise the error; otherwise, DBI functions termiates on encountering an error. 58 # All terminations decisions are made outside of DBI functions... 59 $DBHandle = DBI->connect($DataSource, $DBUser, $DBPassword, { RaiseError => 0, AutoCommit => 0 }) or croak "Couldn't connect to database..."; 60 61 return $DBHandle; 62 } 63 64 # Disconnect from a database... 65 sub DBDisconnect { 66 my($DBHandle) = @_; 67 68 $DBHandle->disconnect or carp "Couldn't disconnect from a database..."; 69 } 70 71 # Fetch all table name for a database schema... 72 sub DBFetchSchemaTableNames { 73 my($DBDriver, $DBHandle, $SchemaName) = @_; 74 my(@SchemaTableNames, $SQL, $SQLHandle); 75 76 @SchemaTableNames = (); 77 78 $SchemaName = (defined $SchemaName && length $SchemaName) ? uc $SchemaName : ""; 79 80 if ($DBDriver eq "mysql") { 81 # Switch schemas... 82 $SQL = qq(USE $SchemaName); 83 $SQLHandle = $DBHandle->prepare($SQL) or return @SchemaTableNames; 84 $SQLHandle->execute or return @SchemaTableNames; 85 $SQLHandle->finish or return @SchemaTableNames; 86 87 # Setup to fetch table names... 88 $SQL = qq(SHOW TABLES); 89 } 90 elsif ($DBDriver eq "Oracle") { 91 $SQL = qq(SELECT SEGMENT_NAME FROM DBA_SEGMENTS WHERE OWNER = '$SchemaName' AND SEGMENT_TYPE = 'TABLE' ORDER BY SEGMENT_NAME); 92 } 93 $SQLHandle = $DBHandle->prepare($SQL) or return @SchemaTableNames; 94 $SQLHandle->execute or return @SchemaTableNames; 95 96 my(@RowValues, $TableName); 97 while (@RowValues = $SQLHandle->fetchrow_array) { 98 $TableName = uc $RowValues[0]; 99 if (defined $TableName && length $TableName) { 100 push @SchemaTableNames, $TableName; 101 } 102 } 103 $SQLHandle->finish or return @SchemaTableNames; 104 105 return @SchemaTableNames; 106 } 107 108 # Setup describe SQL statement... 109 sub DBSetupDescribeSQL { 110 my($DBDriver, $TableName, $SchemaName); 111 my($DescribeSQL); 112 113 $DBDriver = ""; $TableName = ""; $SchemaName = ""; 114 if (@_ == 3) { 115 ($DBDriver, $TableName, $SchemaName) = @_; 116 } 117 else { 118 ($DBDriver, $TableName) = @_; 119 } 120 $TableName = (defined $TableName && length $TableName) ? uc $TableName : ""; 121 $SchemaName = (defined $SchemaName && length $SchemaName) ? uc $SchemaName : ""; 122 123 $DescribeSQL = ($SchemaName) ? ("DESCRIBE " . "$SchemaName" . ".$TableName") : "DESCRIBE $TableName"; 124 125 if ($DBDriver eq "Oracle") { 126 $DescribeSQL = qq(SELECT COLUMN_NAME "Column_Name", DECODE(NULLABLE, 'N','Not Null','Y','Null') "Null", DATA_TYPE "Data_Type", DATA_LENGTH "Data_Length", DATA_PRECISION "Data_Precision" FROM DBA_TAB_COLUMNS WHERE TABLE_NAME = '$TableName'); 127 if ($SchemaName) { 128 $DescribeSQL .= qq( AND OWNER = '$SchemaName'); 129 } 130 $DescribeSQL .= qq( ORDER BY COLUMN_ID); 131 } 132 133 return $DescribeSQL; 134 } 135 136 # Setup describe SQL statement... 137 sub DBSetupSelectSQL { 138 my($DBDriver, $TableName, $SchemaName); 139 my($SelectSQL); 140 141 $DBDriver = ""; $TableName = ""; $SchemaName = ""; 142 if (@_ == 3) { 143 ($DBDriver, $TableName, $SchemaName) = @_; 144 } 145 else { 146 ($DBDriver, $TableName) = @_; 147 } 148 $TableName = (defined $TableName && length $TableName) ? uc $TableName : ""; 149 $SchemaName = (defined $SchemaName && length $SchemaName) ? uc $SchemaName : ""; 150 151 $SelectSQL = ($SchemaName) ? ("SELECT * FROM " . "$SchemaName" . ".$TableName") : "SELECT * FROM $TableName"; 152 153 return $SelectSQL; 154 } 155 156 # Prepare and execute a SQL statement and write out results into 157 # a text file. 158 sub DBSQLToTextFile { 159 my($DBHandle, $SQL, $TextFile, $OutDelim, $OutQuote, $ExportDataLabels, $ExportLOBs, $ReplaceNullStr); 160 my($SQLHandle, $Status); 161 162 $Status = 1; 163 $ExportDataLabels = 1; 164 $ExportLOBs = 0; 165 $ReplaceNullStr = ""; 166 if (@_ == 8) { 167 ($DBHandle, $SQL, $TextFile, $OutDelim, $OutQuote, $ExportDataLabels, $ExportLOBs, $ReplaceNullStr) = @_; 168 } 169 elsif (@_ == 7) { 170 ($DBHandle, $SQL, $TextFile, $OutDelim, $OutQuote, $ExportDataLabels, $ExportLOBs) = @_; 171 } 172 elsif (@_ == 6) { 173 ($DBHandle, $SQL, $TextFile, $OutDelim, $OutQuote, $ExportDataLabels) = @_; 174 } 175 else { 176 ($DBHandle, $SQL, $TextFile, $OutDelim, $OutQuote) = @_; 177 } 178 179 # Execute SQL statement... 180 $SQLHandle = $DBHandle->prepare($SQL) or return $Status; 181 $SQLHandle->execute() or return $Status; 182 183 my($FieldsNum, @FieldNames, @RowValues, @ColNumsToExport, @ColLabels, $ColNum, $ColLabelsLine, @Values, $Value, $ValuesLine); 184 185 $Status = 0; 186 # Figure out which column numbers need to be exported... 187 $FieldsNum = $SQLHandle->{NUM_OF_FIELDS}; 188 @FieldNames = @{$SQLHandle->{NAME}}; 189 @ColNumsToExport = (); 190 if ($ExportLOBs) { 191 @ColNumsToExport = (0 .. $#FieldNames); 192 } 193 else { 194 my(@FieldTypes, @FieldTypeNames, $Type, $TypeName); 195 @FieldTypes = @{$SQLHandle->{TYPE}}; 196 @FieldTypeNames = map { scalar $DBHandle->type_info($_)->{TYPE_NAME} } @FieldTypes; 197 for $ColNum (0 .. $#FieldNames) { 198 if ($FieldTypeNames[$ColNum] !~ /lob/i ) { 199 push @ColNumsToExport, $ColNum; 200 } 201 } 202 } 203 204 if ($ExportDataLabels) { 205 # Print out column labels... 206 @ColLabels = (); 207 for $ColNum (@ColNumsToExport) { 208 push @ColLabels, $FieldNames[$ColNum]; 209 } 210 $ColLabelsLine = JoinWords(\@ColLabels, $OutDelim, $OutQuote); 211 print $TextFile "$ColLabelsLine\n"; 212 } 213 # Print out row values... 214 while (@RowValues = $SQLHandle->fetchrow_array) { 215 @Values = (); 216 for $ColNum (@ColNumsToExport) { 217 if (defined($RowValues[$ColNum]) && length($RowValues[$ColNum])) { 218 $Value = $RowValues[$ColNum]; 219 } 220 else { 221 $Value = $ReplaceNullStr ? $ReplaceNullStr : ""; 222 } 223 push @Values, $Value; 224 } 225 $ValuesLine = JoinWords(\@Values, $OutDelim, $OutQuote); 226 print $TextFile "$ValuesLine\n"; 227 } 228 $SQLHandle->finish or return $Status; 229 $Status = 0; 230 231 return $Status; 232 } 233