summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl/lib/Win32/ODBC.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Master/tlpkg/tlperl/lib/Win32/ODBC.pm')
-rw-r--r--Master/tlpkg/tlperl/lib/Win32/ODBC.pm1493
1 files changed, 1493 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl/lib/Win32/ODBC.pm b/Master/tlpkg/tlperl/lib/Win32/ODBC.pm
new file mode 100644
index 00000000000..a51616388ea
--- /dev/null
+++ b/Master/tlpkg/tlperl/lib/Win32/ODBC.pm
@@ -0,0 +1,1493 @@
+package Win32::ODBC;
+
+$VERSION = '0.032';
+
+# Win32::ODBC.pm
+# +==========================================================+
+# | |
+# | ODBC.PM package |
+# | --------------- |
+# | |
+# | Copyright (c) 1996, 1997 Dave Roth. All rights reserved. |
+# | This program is free software; you can redistribute |
+# | it and/or modify it under the same terms as Perl itself. |
+# | |
+# +==========================================================+
+#
+#
+# based on original code by Dan DeMaggio (dmag@umich.edu)
+#
+# Use under GNU General Public License or Larry Wall's "Artistic License"
+#
+# Check the README.TXT file that comes with this package for details about
+# it's history.
+#
+
+require Exporter;
+require DynaLoader;
+
+$ODBCPackage = "Win32::ODBC";
+$ODBCPackage::Version = 970208;
+$::ODBC = $ODBCPackage;
+$CacheConnection = 0;
+
+ # Reserve ODBC in the main namespace for US!
+*ODBC::=\%Win32::ODBC::;
+
+
+@ISA= qw( Exporter DynaLoader );
+ # Items to export into callers namespace by default. Note: do not export
+ # names by default without a very good reason. Use EXPORT_OK instead.
+ # Do not simply export all your public functions/methods/constants.
+@EXPORT = qw(
+ ODBC_ADD_DSN
+ ODBC_REMOVE_DSN
+ ODBC_CONFIG_DSN
+ ODBC_ADD_SYS_DSN
+ ODBC_REMOVE_SYS_DSN
+ ODBC_CONFIG_SYS_DSN
+
+ SQL_DONT_CLOSE
+ SQL_DROP
+ SQL_CLOSE
+ SQL_UNBIND
+ SQL_RESET_PARAMS
+
+ SQL_FETCH_NEXT
+ SQL_FETCH_FIRST
+ SQL_FETCH_LAST
+ SQL_FETCH_PRIOR
+ SQL_FETCH_ABSOLUTE
+ SQL_FETCH_RELATIVE
+ SQL_FETCH_BOOKMARK
+
+ SQL_COLUMN_COUNT
+ SQL_COLUMN_NAME
+ SQL_COLUMN_TYPE
+ SQL_COLUMN_LENGTH
+ SQL_COLUMN_PRECISION
+ SQL_COLUMN_SCALE
+ SQL_COLUMN_DISPLAY_SIZE
+ SQL_COLUMN_NULLABLE
+ SQL_COLUMN_UNSIGNED
+ SQL_COLUMN_MONEY
+ SQL_COLUMN_UPDATABLE
+ SQL_COLUMN_AUTO_INCREMENT
+ SQL_COLUMN_CASE_SENSITIVE
+ SQL_COLUMN_SEARCHABLE
+ SQL_COLUMN_TYPE_NAME
+ SQL_COLUMN_TABLE_NAME
+ SQL_COLUMN_OWNER_NAME
+ SQL_COLUMN_QUALIFIER_NAME
+ SQL_COLUMN_LABEL
+ SQL_COLATT_OPT_MAX
+ SQL_COLUMN_DRIVER_START
+ SQL_COLATT_OPT_MIN
+ SQL_ATTR_READONLY
+ SQL_ATTR_WRITE
+ SQL_ATTR_READWRITE_UNKNOWN
+ SQL_UNSEARCHABLE
+ SQL_LIKE_ONLY
+ SQL_ALL_EXCEPT_LIKE
+ SQL_SEARCHABLE
+ );
+ #The above are included for backward compatibility
+
+
+sub new
+{
+ my ($n, $self);
+ my ($type) = shift;
+ my ($DSN) = shift;
+ my (@Results) = @_;
+
+ if (ref $DSN){
+ @Results = ODBCClone($DSN->{'connection'});
+ }else{
+ @Results = ODBCConnect($DSN, @Results);
+ }
+ @Results = processError(-1, @Results);
+ if (! scalar(@Results)){
+ return undef;
+ }
+ $self = bless {};
+ $self->{'connection'} = $Results[0];
+ $ErrConn = $Results[0];
+ $ErrText = $Results[1];
+ $ErrNum = 0;
+ $self->{'DSN'} = $DSN;
+ $self;
+}
+
+####
+# Close this ODBC session (or all sessions)
+####
+sub Close
+{
+ my ($self, $Result) = shift;
+ $Result = DESTROY($self);
+ $self->{'connection'} = -1;
+ return $Result;
+}
+
+####
+# Auto-Kill an instance of this module
+####
+sub DESTROY
+{
+ my ($self) = shift;
+ my (@Results) = (0);
+ if($self->{'connection'} > -1){
+ @Results = ODBCDisconnect($self->{'connection'});
+ @Results = processError($self, @Results);
+ if ($Results[0]){
+ undef $self->{'DSN'};
+ undef @{$self->{'fnames'}};
+ undef %{$self->{'field'}};
+ undef %{$self->{'connection'}};
+ }
+ }
+ return $Results[0];
+}
+
+
+sub sql{
+ return (Sql(@_));
+}
+
+####
+# Submit an SQL Execute statement for processing
+####
+sub Sql{
+ my ($self, $Sql, @Results) = @_;
+ @Results = ODBCExecute($self->{'connection'}, $Sql);
+ return updateResults($self, @Results);
+}
+
+####
+# Retrieve data from a particular field
+####
+sub Data{
+
+ # Change by JOC 06-APR-96
+ # Altered by Dave Roth <dave@roth.net> 96.05.07
+ my($self) = shift;
+ my(@Fields) = @_;
+ my(@Results, $Results, $Field);
+
+ if ($self->{'Dirty'}){
+ GetData($self);
+ $self->{'Dirty'} = 0;
+ }
+ @Fields = @{$self->{'fnames'}} if (! scalar(@Fields));
+ foreach $Field (@Fields) {
+ if (wantarray) {
+ push(@Results, data($self, $Field));
+ } else {
+ $Results .= data($self, $Field);
+ }
+ }
+ return wantarray ? @Results : $Results;
+}
+
+sub DataHash{
+ my($self, @Results) = @_;
+ my(%Results, $Element);
+
+ if ($self->{'Dirty'}){
+ GetData($self);
+ $self->{'Dirty'} = 0;
+ }
+ @Results = @{$self->{'fnames'}} if (! scalar(@Results));
+ foreach $Element (@Results) {
+ $Results{$Element} = data($self, $Element);
+ }
+
+ return %Results;
+}
+
+####
+# Retrieve data from the data buffer
+####
+sub data
+{ $_[0]->{'data'}->{$_[1]}; }
+
+
+sub fetchrow{
+ return (FetchRow(@_));
+}
+####
+# Put a row from an ODBC data set into data buffer
+####
+sub FetchRow{
+ my ($self, @Results) = @_;
+ my ($item, $num, $sqlcode);
+ # Added by JOC 06-APR-96
+ # $num = 0;
+ $num = 0;
+ undef $self->{'data'};
+
+
+ @Results = ODBCFetch($self->{'connection'}, @Results);
+ if (! (@Results = processError($self, @Results))){
+ ####
+ # There should be an innocuous error "No records remain"
+ # This indicates no more records in the dataset
+ ####
+ return undef;
+ }
+ # Set the Dirty bit so we will go and extract data via the
+ # ODBCGetData function. Otherwise use the cache.
+ $self->{'Dirty'} = 1;
+
+ # Return the array of field Results.
+ return @Results;
+}
+
+sub GetData{
+ my($self) = @_;
+ my @Results;
+ my $num = 0;
+
+ @Results = ODBCGetData($self->{'connection'});
+ if (!(@Results = processError($self, @Results))){
+ return undef;
+ }
+ ####
+ # This is a special case. Do not call processResults
+ ####
+ ClearError();
+ foreach (@Results){
+ s/ +$// if defined $_; # HACK
+ $self->{'data'}->{ ${$self->{'fnames'}}[$num] } = $_;
+ $num++;
+ }
+ # return is a hack to interface with a assoc array.
+ return wantarray? (1, 1): 1;
+}
+
+####
+# See if any more ODBC Results Sets
+# Added by Brian Dunfordshore <Brian_Dunfordshore@bridge.com>
+# 96.07.10
+####
+sub MoreResults{
+ my ($self) = @_;
+
+ my(@Results) = ODBCMoreResults($self->{'connection'});
+ return (processError($self, @Results))[0];
+}
+
+####
+# Retrieve the catalog from the current DSN
+# NOTE: All Field names are uppercase!!!
+####
+sub Catalog{
+ my ($self) = shift;
+ my ($Qualifier, $Owner, $Name, $Type) = @_;
+ my (@Results) = ODBCTableList($self->{'connection'}, $Qualifier, $Owner, $Name, $Type);
+
+ # If there was an error return 0 else 1
+ return (updateResults($self, @Results) != 1);
+}
+
+####
+# Return an array of names from the catalog for the current DSN
+# TableList($Qualifier, $Owner, $Name, $Type)
+# Return: (array of names of tables)
+# NOTE: All Field names are uppercase!!!
+####
+sub TableList{
+ my ($self) = shift;
+ my (@Results) = @_;
+ if (! scalar(@Results)){
+ @Results = ("", "", "%", "TABLE");
+ }
+
+ if (! Catalog($self, @Results)){
+ return undef;
+ }
+ undef @Results;
+ while (FetchRow($self)){
+ push(@Results, Data($self, "TABLE_NAME"));
+ }
+ return sort(@Results);
+}
+
+
+sub fieldnames{
+ return (FieldNames(@_));
+}
+####
+# Return an array of fieldnames extracted from the current dataset
+####
+sub FieldNames { $self = shift; return @{$self->{'fnames'}}; }
+
+
+####
+# Closes this connection. This is used mostly for testing. You should
+# probably use Close().
+####
+sub ShutDown{
+ my($self) = @_;
+ print "\nClosing connection $self->{'connection'}...";
+ $self->Close();
+ print "\nDone\n";
+}
+
+####
+# Return this connection number
+####
+sub Connection{
+ my($self) = @_;
+ return $self->{'connection'};
+}
+
+####
+# Returns the current connections that are in use.
+####
+sub GetConnections{
+ return ODBCGetConnections();
+}
+
+####
+# Set the Max Buffer Size for this connection. This determines just how much
+# ram can be allocated when a fetch() is performed that requires a HUGE amount
+# of memory. The default max is 10k and the absolute max is 100k.
+# This will probably never be used but I put it in because I noticed a fetch()
+# of a MEMO field in an Access table was something like 4Gig. Maybe I did
+# something wrong, but after checking several times I decided to impliment
+# this limit thingie.
+####
+sub SetMaxBufSize{
+ my($self, $Size) = @_;
+ my(@Results) = ODBCSetMaxBufSize($self->{'connection'}, $Size);
+ return (processError($self, @Results))[0];
+}
+
+####
+# Returns the Max Buffer Size for this connection. See SetMaxBufSize().
+####
+sub GetMaxBufSize{
+ my($self) = @_;
+ my(@Results) = ODBCGetMaxBufSize($self->{'connection'});
+ return (processError($self, @Results))[0];
+}
+
+
+####
+# Returns the DSN for this connection as an associative array.
+####
+sub GetDSN{
+ my($self, $DSN) = @_;
+ if(! ref($self)){
+ $DSN = $self;
+ $self = 0;
+ }
+ if (! $DSN){
+ $self = $self->{'connection'};
+ }
+ my(@Results) = ODBCGetDSN($self, $DSN);
+ return (processError($self, @Results));
+}
+
+####
+# Returns an associative array of $XXX{'DSN'}=Description
+####
+sub DataSources{
+ my($self, $DSN) = @_;
+ if(! ref $self){
+ $DSN = $self;
+ $self = 0;
+ }
+ my(@Results) = ODBCDataSources($DSN);
+ return (processError($self, @Results));
+}
+
+####
+# Returns an associative array of $XXX{'Driver Name'}=Driver Attributes
+####
+sub Drivers{
+ my($self) = @_;
+ if(! ref $self){
+ $self = 0;
+ }
+ my(@Results) = ODBCDrivers();
+ return (processError($self, @Results));
+}
+
+####
+# Returns the number of Rows that were affected by the previous SQL command.
+####
+sub RowCount{
+ my($self, $Connection) = @_;
+ if (! ref($self)){
+ $Connection = $self;
+ $self = 0;
+ }
+ if (! $Connection){$Connection = $self->{'connection'};}
+ my(@Results) = ODBCRowCount($Connection);
+ return (processError($self, @Results))[0];
+}
+
+####
+# Returns the Statement Close Type -- how does ODBC Close a statment.
+# Types:
+# SQL_DROP
+# SQL_CLOSE
+# SQL_UNBIND
+# SQL_RESET_PARAMS
+####
+sub GetStmtCloseType{
+ my($self, $Connection) = @_;
+ if (! ref($self)){
+ $Connection = $self;
+ $self = 0;
+ }
+ if (! $Connection){$Connection = $self->{'connection'};}
+ my(@Results) = ODBCGetStmtCloseType($Connection);
+ return (processError($self, @Results));
+}
+
+####
+# Sets the Statement Close Type -- how does ODBC Close a statment.
+# Types:
+# SQL_DROP
+# SQL_CLOSE
+# SQL_UNBIND
+# SQL_RESET_PARAMS
+# Returns the newly set value.
+####
+sub SetStmtCloseType{
+ my($self, $Type, $Connection) = @_;
+ if (! ref($self)){
+ $Connection = $Type;
+ $Type = $self;
+ $self = 0;
+ }
+ if (! $Connection){$Connection = $self->{'connection'};}
+ my(@Results) = ODBCSetStmtCloseType($Connection, $Type);
+ return (processError($self, @Results))[0];
+}
+
+sub ColAttributes{
+ my($self, $Type, @Field) = @_;
+ my(%Results, @Results, $Results, $Attrib, $Connection, $Temp);
+ if (! ref($self)){
+ $Type = $Field;
+ $Field = $self;
+ $self = 0;
+ }
+ $Connection = $self->{'connection'};
+ if (! scalar(@Field)){ @Field = $self->fieldnames;}
+ foreach $Temp (@Field){
+ @Results = ODBCColAttributes($Connection, $Temp, $Type);
+ ($Attrib) = processError($self, @Results);
+ if (wantarray){
+ $Results{$Temp} = $Attrib;
+ }else{
+ $Results .= "$Temp";
+ }
+ }
+ return wantarray? %Results:$Results;
+}
+
+sub GetInfo{
+ my($self, $Type) = @_;
+ my($Connection, @Results);
+ if(! ref $self){
+ $Type = $self;
+ $self = 0;
+ $Connection = 0;
+ }else{
+ $Connection = $self->{'connection'};
+ }
+ @Results = ODBCGetInfo($Connection, $Type);
+ return (processError($self, @Results))[0];
+}
+
+sub GetConnectOption{
+ my($self, $Type) = @_;
+ my(@Results);
+ if(! ref $self){
+ $Type = $self;
+ $self = 0;
+ }
+ @Results = ODBCGetConnectOption($self->{'connection'}, $Type);
+ return (processError($self, @Results))[0];
+}
+
+sub SetConnectOption{
+ my($self, $Type, $Value) = @_;
+ if(! ref $self){
+ $Value = $Type;
+ $Type = $self;
+ $self = 0;
+ }
+ my(@Results) = ODBCSetConnectOption($self->{'connection'}, $Type, $Value);
+ return (processError($self, @Results))[0];
+}
+
+
+sub Transact{
+ my($self, $Type) = @_;
+ my(@Results);
+ if(! ref $self){
+ $Type = $self;
+ $self = 0;
+ }
+ @Results = ODBCTransact($self->{'connection'}, $Type);
+ return (processError($self, @Results))[0];
+}
+
+
+sub SetPos{
+ my($self, @Results) = @_;
+ @Results = ODBCSetPos($self->{'connection'}, @Results);
+ $self->{'Dirty'} = 1;
+ return (processError($self, @Results))[0];
+}
+
+sub ConfigDSN{
+ my($self) = shift @_;
+ my($Type, $Connection);
+ if(! ref $self){
+ $Type = $self;
+ $Connection = 0;
+ $self = 0;
+ }else{
+ $Type = shift @_;
+ $Connection = $self->{'connection'};
+ }
+ my($Driver, @Attributes) = @_;
+ @Results = ODBCConfigDSN($Connection, $Type, $Driver, @Attributes);
+ return (processError($self, @Results))[0];
+}
+
+
+sub Version{
+ my($self, @Packages) = @_;
+ my($Temp, @Results);
+ if (! ref($self)){
+ push(@Packages, $self);
+ }
+ my($ExtName, $ExtVersion) = Info();
+ if (! scalar(@Packages)){
+ @Packages = ("ODBC.PM", "ODBC.PLL");
+ }
+ foreach $Temp (@Packages){
+ if ($Temp =~ /pll/i){
+ push(@Results, "ODBC.PM:$Win32::ODBC::Version");
+ }elsif ($Temp =~ /pm/i){
+ push(@Results, "ODBC.PLL:$ExtVersion");
+ }
+ }
+ return @Results;
+}
+
+
+sub SetStmtOption{
+ my($self, $Option, $Value) = @_;
+ if(! ref $self){
+ $Value = $Option;
+ $Option = $self;
+ $self = 0;
+ }
+ my(@Results) = ODBCSetStmtOption($self->{'connection'}, $Option, $Value);
+ return (processError($self, @Results))[0];
+}
+
+sub GetStmtOption{
+ my($self, $Type) = @_;
+ if(! ref $self){
+ $Type = $self;
+ $self = 0;
+ }
+ my(@Results) = ODBCGetStmtOption($self->{'connection'}, $Type);
+ return (processError($self, @Results))[0];
+}
+
+sub GetFunctions{
+ my($self, @Results)=@_;
+ @Results = ODBCGetFunctions($self->{'connection'}, @Results);
+ return (processError($self, @Results));
+}
+
+sub DropCursor{
+ my($self) = @_;
+ my(@Results) = ODBCDropCursor($self->{'connection'});
+ return (processError($self, @Results))[0];
+}
+
+sub SetCursorName{
+ my($self, $Name) = @_;
+ my(@Results) = ODBCSetCursorName($self->{'connection'}, $Name);
+ return (processError($self, @Results))[0];
+}
+
+sub GetCursorName{
+ my($self) = @_;
+ my(@Results) = ODBCGetCursorName($self->{'connection'});
+ return (processError($self, @Results))[0];
+}
+
+sub GetSQLState{
+ my($self) = @_;
+ my(@Results) = ODBCGetSQLState($self->{'connection'});
+ return (processError($self, @Results))[0];
+}
+
+
+# ----------- R e s u l t P r o c e s s i n g F u n c t i o n s ----------
+####
+# Generic processing of data into associative arrays
+####
+sub updateResults{
+ my ($self, $Error, @Results) = @_;
+
+ undef %{$self->{'field'}};
+
+ ClearError($self);
+ if ($Error){
+ SetError($self, $Results[0], $Results[1]);
+ return ($Error);
+ }
+
+ @{$self->{'fnames'}} = @Results;
+
+ foreach (0..$#{$self->{'fnames'}}){
+ s/ +$//;
+ $self->{'field'}->{${$self->{'fnames'}}[$_]} = $_;
+ }
+ return undef;
+}
+
+# ----------------------------------------------------------------------------
+# ----------------- D e b u g g i n g F u n c t i o n s --------------------
+
+sub Debug{
+ my($self, $iDebug, $File) = @_;
+ my(@Results);
+ if (! ref($self)){
+ if (defined $self){
+ $File = $iDebug;
+ $iDebug = $self;
+ }
+ $Connection = 0;
+ $self = 0;
+ }else{
+ $Connection = $self->{'connection'};
+ }
+ push(@Results, ($Connection, $iDebug));
+ push(@Results, $File) if ($File ne "");
+ @Results = ODBCDebug(@Results);
+ return (processError($self, @Results))[0];
+}
+
+####
+# Prints out the current dataset (used mostly for testing)
+####
+sub DumpData {
+ my($self) = @_; my($f, $goo);
+
+ # Changed by JOC 06-Apr-96
+ # print "\nDumping Data for connection: $conn->{'connection'}\n";
+ print "\nDumping Data for connection: $self->{'connection'}\n";
+ print "Error: \"";
+ print $self->Error();
+ print "\"\n";
+ if (! $self->Error()){
+ foreach $f ($self->FieldNames){
+ print $f . " ";
+ $goo .= "-" x length($f);
+ $goo .= " ";
+ }
+ print "\n$goo\n";
+ while ($self->FetchRow()){
+ foreach $f ($self->FieldNames){
+ print $self->Data($f) . " ";
+ }
+ print "\n";
+ }
+ }
+}
+
+sub DumpError{
+ my($self) = @_;
+ my($ErrNum, $ErrText, $ErrConn);
+ my($Temp);
+
+ print "\n---------- Error Report: ----------\n";
+ if (ref $self){
+ ($ErrNum, $ErrText, $ErrConn) = $self->Error();
+ ($Temp = $self->GetDSN()) =~ s/.*DSN=(.*?);.*/$1/i;
+ print "Errors for \"$Temp\" on connection " . $self->{'connection'} . ":\n";
+ }else{
+ ($ErrNum, $ErrText, $ErrConn) = Error();
+ print "Errors for the package:\n";
+ }
+
+ print "Connection Number: $ErrConn\nError number: $ErrNum\nError message: \"$ErrText\"\n";
+ print "-----------------------------------\n";
+
+}
+
+####
+# Submit an SQL statement and print data about it (used mostly for testing)
+####
+sub Run{
+ my($self, $Sql) = @_;
+
+ print "\nExcecuting connection $self->{'connection'}\nsql statement: \"$Sql\"\n";
+ $self->Sql($Sql);
+ print "Error: \"";
+ print $self->error;
+ print "\"\n";
+ print "--------------------\n\n";
+}
+
+# ----------------------------------------------------------------------------
+# ----------- E r r o r P r o c e s s i n g F u n c t i o n s ------------
+
+####
+# Process Errors returned from a call to ODBCxxxx().
+# It is assumed that the Win32::ODBC function returned the following structure:
+# ($ErrorNumber, $ResultsText, ...)
+# $ErrorNumber....0 = No Error
+# >0 = Error Number
+# $ResultsText.....if no error then this is the first Results element.
+# if error then this is the error text.
+####
+sub processError{
+ my($self, $Error, @Results) = @_;
+ if ($Error){
+ SetError($self, $Results[0], $Results[1]);
+ undef @Results;
+ }
+ return @Results;
+}
+
+####
+# Return the last recorded error message
+####
+sub error{
+ return (Error(@_));
+}
+
+sub Error{
+ my($self) = @_;
+ if(ref($self)){
+ if($self->{'ErrNum'}){
+ my($State) = ODBCGetSQLState($self->{'connection'});
+ return (wantarray)? ($self->{'ErrNum'}, $self->{'ErrText'}, $self->{'connection'}, $State) :"[$self->{'ErrNum'}] [$self->{'connection'}] [$State] \"$self->{'ErrText'}\"";
+ }
+ }elsif ($ErrNum){
+ return (wantarray)? ($ErrNum, $ErrText, $ErrConn):"[$ErrNum] [$ErrConn] \"$ErrText\"";
+ }
+ return undef
+}
+
+####
+# SetError:
+# Assume that if $self is not a reference then it is just a placeholder
+# and should be ignored.
+####
+sub SetError{
+ my($self, $Num, $Text, $Conn) = @_;
+ if (ref $self){
+ $self->{'ErrNum'} = $Num;
+ $self->{'ErrText'} = $Text;
+ $Conn = $self->{'connection'} if ! $Conn;
+ }
+ $ErrNum = $Num;
+ $ErrText = $Text;
+
+ ####
+ # Test Section Begin
+ ####
+# $! = ($Num, $Text);
+ ####
+ # Test Section End
+ ####
+
+ $ErrConn = $Conn;
+}
+
+sub ClearError{
+ my($self, $Num, $Text) = @_;
+ if (ref $self){
+ undef $self->{'ErrNum'};
+ undef $self->{'ErrText'};
+ }else{
+ undef $ErrConn;
+ undef $ErrNum;
+ undef $ErrText;
+ }
+ ODBCCleanError();
+ return 1;
+}
+
+
+sub GetError{
+ my($self, $Connection) = @_;
+ my(@Results);
+ if (! ref($self)){
+ $Connection = $self;
+ $self = 0;
+ }else{
+ if (! defined($Connection)){
+ $Connection = $self->{'connection'};
+ }
+ }
+
+ @Results = ODBCGetError($Connection);
+ return @Results;
+}
+
+
+
+
+# ----------------------------------------------------------------------------
+# ------------------ A U T O L O A D F U N C T I O N -----------------------
+
+sub AUTOLOAD {
+ # This AUTOLOAD is used to 'autoload' constants from the constant()
+ # XS function. If a constant is not found then control is passed
+ # to the AUTOLOAD in AutoLoader.
+
+ my($constname);
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ #reset $! to zero to reset any current errors.
+ local $! = 0;
+ $val = constant($constname);
+
+ if ($! != 0) {
+ if ($! =~ /Invalid/) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+
+ # Added by JOC 06-APR-96
+ # $pack = 0;
+ $pack = 0;
+ ($pack,$file,$line) = caller;
+ print "Your vendor has not defined Win32::ODBC macro $constname, used in $file at line $line.";
+ }
+ }
+ eval "sub $AUTOLOAD { $val }";
+ goto &$AUTOLOAD;
+}
+
+
+ # --------------------------------------------------------------
+ #
+ #
+ # Make sure that we shutdown ODBC and free memory even if we are
+ # using perlis.dll on Win32 platform!
+END{
+# ODBCShutDown() unless $CacheConnection;
+}
+
+
+bootstrap Win32::ODBC;
+
+# Preloaded methods go here.
+
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+__END__
+
+=head1 NAME
+
+Win32::ODBC - ODBC Extension for Win32
+
+=head1 SYNOPSIS
+
+To use this module, include the following statement at the top of your
+script:
+
+ use Win32::ODBC;
+
+Next, create a data connection to your DSN:
+
+ $Data = new Win32::ODBC("MyDSN");
+
+B<NOTE>: I<MyDSN> can be either the I<DSN> as defined in the ODBC
+Administrator, I<or> it can be an honest-to-God I<DSN Connect String>.
+
+ Example: "DSN=My Database;UID=Brown Cow;PWD=Moo;"
+
+You should check to see if C<$Data> is indeed defined, otherwise there
+has been an error.
+
+You can now send SQL queries and retrieve info to your heart's
+content! See the description of the methods provided by this module
+below and also the file F<TEST.PL> as referred to in L<INSTALLATION
+NOTES> to see how it all works.
+
+Finally, B<MAKE SURE> that you close your connection when you are
+finished:
+
+ $Data->Close();
+
+=head1 DESCRIPTION
+
+=head2 Background
+
+This is a hack of Dan DeMaggio's <dmag@umich.edu> F<NTXS.C> ODBC
+implementation. I have recoded and restructured most of it including
+most of the F<ODBC.PM> package, but its very core is still based on
+Dan's code (thanks Dan!).
+
+The history of this extension is found in the file F<HISTORY.TXT> that
+comes with the original archive (see L<INSTALLATION NOTES> below).
+
+=head2 Benefits
+
+And what are the benefits of this module?
+
+=over
+
+=item *
+
+The number of ODBC connections is limited by memory and ODBC itself
+(have as many as you want!).
+
+=item *
+
+The working limit for the size of a field is 10,240 bytes, but you can
+increase that limit (if needed) to a max of 2,147,483,647 bytes. (You
+can always recompile to increase the max limit.)
+
+=item *
+
+You can open a connection by either specifing a DSN or a connection
+string!
+
+=item *
+
+You can open and close the connections in any order!
+
+=item *
+
+Other things that I can not think of right now... :)
+
+=back
+
+=head1 CONSTANTS
+
+This package defines a number of constants. You may refer to each of
+these constants using the notation C<ODBC::xxxxx>, where C<xxxxx> is
+the constant.
+
+Example:
+
+ print ODBC::SQL_SQL_COLUMN_NAME, "\n";
+
+=head1 SPECIAL NOTATION
+
+For the method documentation that follows, an B<*> following the
+method parameters indicates that that method is new or has been
+modified for this version.
+
+=head1 CONSTRUCTOR
+
+=over
+
+=item new ( ODBC_OBJECT | DSN [, (OPTION1, VALUE1), (OPTION2, VALUE2) ...] )
+*
+
+Creates a new ODBC connection based on C<DSN>, or, if you specify an
+already existing ODBC object, then a new ODBC object will be created
+but using the ODBC Connection specified by C<ODBC_OBJECT>. (The new
+object will be a new I<hstmt> using the I<hdbc> connection in
+C<ODBC_OBJECT>.)
+
+C<DSN> is I<Data Source Name> or a proper C<ODBCDriverConnect> string.
+
+You can specify SQL Connect Options that are implemented before the
+actual connection to the DSN takes place. These option/values are the
+same as specified in C<GetConnectOption>/C<SetConnectOption> (see
+below) and are defined in the ODBC API specs.
+
+Returns a handle to the database on success, or I<undef> on failure.
+
+=back
+
+=head1 METHODS
+
+=over
+
+=item Catalog ( QUALIFIER, OWNER, NAME, TYPE )
+
+Tells ODBC to create a data set that contains table information about
+the DSN. Use C<Fetch> and C<Data> or C<DataHash> to retrieve the data.
+The returned format is:
+
+ [Qualifier] [Owner] [Name] [Type]
+
+Returns I<true> on error.
+
+=item ColAttributes ( ATTRIBUTE [, FIELD_NAMES ] )
+
+Returns the attribute C<ATTRIBUTE> on each of the fields in the list
+C<FIELD_NAMES> in the current record set. If C<FIELD_NAMES> is empty,
+then all fields are assumed. The attributes are returned as an
+associative array.
+
+=item ConfigDSN ( OPTION, DRIVER, ATTRIBUTE1 [, ATTRIBUTE2, ATTRIBUTE3, ...
+] )
+
+Configures a DSN. C<OPTION> takes on one of the following values:
+
+ ODBC_ADD_DSN.......Adds a new DSN.
+ ODBC_MODIFY_DSN....Modifies an existing DSN.
+ ODBC_REMOVE_DSN....Removes an existing DSN.
+
+ ODBC_ADD_SYS_DSN.......Adds a new System DSN.
+ ODBC_MODIFY_SYS_DSN....Modifies an existing System DSN.
+ ODBC_REMOVE_SYS_DSN....Removes an existing System DSN.
+
+You must specify the driver C<DRIVER> (which can be retrieved by using
+C<DataSources> or C<Drivers>).
+
+C<ATTRIBUTE1> B<should> be I<"DSN=xxx"> where I<xxx> is the name of
+the DSN. Other attributes can be any DSN attribute such as:
+
+ "UID=Cow"
+ "PWD=Moo"
+ "Description=My little bitty Data Source Name"
+
+Returns I<true> on success, I<false> on failure.
+
+B<NOTE 1>: If you use C<ODBC_ADD_DSN>, then you must include at least
+I<"DSN=xxx"> and the location of the database.
+
+Example: For MS Access databases, you must specify the
+I<DatabaseQualifier>:
+
+ "DBQ=c:\\...\\MyDatabase.mdb"
+
+B<NOTE 2>: If you use C<ODBC_MODIFY_DSN>, then you need only specify
+the I<"DNS=xxx"> attribute. Any other attribute you include will be
+changed to what you specify.
+
+B<NOTE 3>: If you use C<ODBC_REMOVE_DSN>, then you need only specify
+the I<"DSN=xxx"> attribute.
+
+=item Connection ()
+
+Returns the connection number associated with the ODBC connection.
+
+=item Close ()
+
+Closes the ODBC connection. No return value.
+
+=item Data ( [ FIELD_NAME ] )
+
+Returns the contents of column name C<FIELD_NAME> or the current row
+(if nothing is specified).
+
+=item DataHash ( [ FIELD1, FIELD2, ... ] )
+
+Returns the contents for C<FIELD1, FIELD2, ...> or the entire row (if
+nothing is specified) as an associative array consisting of:
+
+ {Field Name} => Field Data
+
+=item DataSources ()
+
+Returns an associative array of Data Sources and ODBC remarks about them.
+They are returned in the form of:
+
+ $ArrayName{'DSN'}=Driver
+
+where I<DSN> is the Data Source Name and ODBC Driver used.
+
+=item Debug ( [ 1 | 0 ] )
+
+Sets the debug option to on or off. If nothing is specified, then
+nothing is changed.
+
+Returns the debugging value (I<1> or I<0>).
+
+=item Drivers ()
+
+Returns an associative array of ODBC Drivers and their attributes.
+They are returned in the form of:
+
+ $ArrayName{'DRIVER'}=Attrib1;Attrib2;Attrib3;...
+
+where I<DRIVER> is the ODBC Driver Name and I<AttribX> are the
+driver-defined attributes.
+
+=item DropCursor ( [ CLOSE_TYPE ] )
+
+Drops the cursor associated with the ODBC object. This forces the
+cursor to be deallocated. This overrides C<SetStmtCloseType>, but the
+ODBC object does not lose the C<StmtCloseType> setting. C<CLOSE_TYPE>
+can be any valid C<SmtpCloseType> and will perform a close on the stmt
+using the specified close type.
+
+Returns I<true> on success, I<false> on failure.
+
+=item DumpData ()
+
+Dumps to the screen the fieldnames and all records of the current data
+set. Used primarily for debugging. No return value.
+
+=item Error ()
+
+Returns the last encountered error. The returned value is context
+dependent:
+
+If called in a I<scalar> context, then a I<3-element array> is
+returned:
+
+ ( ERROR_NUMBER, ERROR_TEXT, CONNECTION_NUMBER )
+
+If called in a I<string> context, then a I<string> is returned:
+
+ "[ERROR_NUMBER] [CONNECTION_NUMBER] [ERROR_TEXT]"
+
+If debugging is on then two more variables are returned:
+
+ ( ..., FUNCTION, LEVEL )
+
+where C<FUNCTION> is the name of the function in which the error
+occurred, and C<LEVEL> represents extra information about the error
+(usually the location of the error).
+
+=item FetchRow ( [ ROW [, TYPE ] ] )
+
+Retrieves the next record from the keyset. When C<ROW> and/or C<TYPE>
+are specified, the call is made using C<SQLExtendedFetch> instead of
+C<SQLFetch>.
+
+B<NOTE 1>: If you are unaware of C<SQLExtendedFetch> and its
+implications, stay with just regular C<FetchRow> with no parameters.
+
+B<NOTE 2>: The ODBC API explicitly warns against mixing calls to
+C<SQLFetch> and C<SQLExtendedFetch>; use one or the other but not
+both.
+
+If I<ROW> is specified, it moves the keyset B<RELATIVE> C<ROW> number
+of rows.
+
+If I<ROW> is specified and C<TYPE> is B<not>, then the type used is
+B<RELATIVE>.
+
+Returns I<true> when another record is available to read, and I<false>
+when there are no more records.
+
+=item FieldNames ()
+
+Returns an array of fieldnames found in the current data set. There is
+no guarantee on order.
+
+=item GetConnections ()
+
+Returns an array of connection numbers showing what connections are
+currently open.
+
+=item GetConnectOption ( OPTION )
+
+Returns the value of the specified connect option C<OPTION>. Refer to
+ODBC documentation for more information on the options and values.
+
+Returns a string or scalar depending upon the option specified.
+
+=item GetCursorName ()
+
+Returns the name of the current cursor as a string or I<undef>.
+
+=item GetData ()
+
+Retrieves the current row from the dataset. This is not generally
+used by users; it is used internally.
+
+Returns an array of field data where the first element is either
+I<false> (if successful) and I<true> (if B<not> successful).
+
+=item getDSN ( [ DSN ] )
+
+Returns an associative array indicating the configuration for the
+specified DSN.
+
+If no DSN is specified then the current connection is used.
+
+The returned associative array consists of:
+
+ keys=DSN keyword; values=Keyword value. $Data{$Keyword}=Value
+
+=item GetFunctions ( [ FUNCTION1, FUNCTION2, ... ] )
+
+Returns an associative array indicating the ability of the ODBC Driver
+to support the specified functions. If no functions are specified,
+then a 100 element associative array is returned containing all
+possible functions and their values.
+
+C<FUNCTION> must be in the form of an ODBC API constant like
+C<SQL_API_SQLTRANSACT>.
+
+The returned array will contain the results like:
+
+ $Results{SQL_API_SQLTRANSACT}=Value
+
+Example:
+
+ $Results = $O->GetFunctions(
+ $O->SQL_API_SQLTRANSACT,
+ SQL_API_SQLSETCONNECTOPTION
+ );
+ $ConnectOption = $Results{SQL_API_SQLSETCONNECTOPTION};
+ $Transact = $Results{SQL_API_SQLTRANSACT};
+
+=item GetInfo ( OPTION )
+
+Returns a string indicating the value of the particular
+option specified.
+
+=item GetMaxBufSize ()
+
+Returns the current allocated limit for I<MaxBufSize>. For more info,
+see C<SetMaxBufSize>.
+
+=item GetSQLState () *
+
+Returns a string indicating the SQL state as reported by ODBC. The SQL
+state is a code that the ODBC Manager or ODBC Driver returns after the
+execution of a SQL function. This is helpful for debugging purposes.
+
+=item GetStmtCloseType ( [ CONNECTION ] )
+
+Returns a string indicating the type of closure that will be used
+everytime the I<hstmt> is freed. See C<SetStmtCloseType> for details.
+
+By default, the connection of the current object will be used. If
+C<CONNECTION> is a valid connection number, then it will be used.
+
+=item GetStmtOption ( OPTION )
+
+Returns the value of the specified statement option C<OPTION>. Refer
+to ODBC documentation for more information on the options and values.
+
+Returns a string or scalar depending upon the option specified.
+
+=item MoreResults ()
+
+This will report whether there is data yet to be retrieved from the
+query. This can happen if the query was a multiple select.
+
+Example:
+
+ "SELECT * FROM [foo] SELECT * FROM [bar]"
+
+B<NOTE>: Not all drivers support this.
+
+Returns I<1> if there is more data, I<undef> otherwise.
+
+=item RowCount ( CONNECTION )
+
+For I<UPDATE>, I<INSERT> and I<DELETE> statements, the returned value
+is the number of rows affected by the request or I<-1> if the number
+of affected rows is not available.
+
+B<NOTE 1>: This function is not supported by all ODBC drivers! Some
+drivers do support this but not for all statements (e.g., it is
+supported for I<UPDATE>, I<INSERT> and I<DELETE> commands but not for
+the I<SELECT> command).
+
+B<NOTE 2>: Many data sources cannot return the number of rows in a
+result set before fetching them; for maximum interoperability,
+applications should not rely on this behavior.
+
+Returns the number of affected rows, or I<-1> if not supported by the
+driver in the current context.
+
+=item Run ( SQL )
+
+Executes the SQL command B<SQL> and dumps to the screen info about
+it. Used primarily for debugging.
+
+No return value.
+
+=item SetConnectOption ( OPTION ) *
+
+Sets the value of the specified connect option B<OPTION>. Refer to
+ODBC documentation for more information on the options and values.
+
+Returns I<true> on success, I<false> otherwise.
+
+=item SetCursorName ( NAME ) *
+
+Sets the name of the current cursor.
+
+Returns I<true> on success, I<false> otherwise.
+
+=item SetPos ( ROW [, OPTION, LOCK ] ) *
+
+Moves the cursor to the row C<ROW> within the current keyset (B<not>
+the current data/result set).
+
+Returns I<true> on success, I<false> otherwise.
+
+=item SetMaxBufSize ( SIZE )
+
+This sets the I<MaxBufSize> for a particular connection. This will
+most likely never be needed but...
+
+The amount of memory that is allocated to retrieve the field data of a
+record is dynamic and changes when it need to be larger. I found that
+a memo field in an MS Access database ended up requesting 4 Gig of
+space. This was a bit much so there is an imposed limit (2,147,483,647
+bytes) that can be allocated for data retrieval.
+
+Since it is possible that someone has a database with field data
+greater than 10,240, you can use this function to increase the limit
+up to a ceiling of 2,147,483,647 (recompile if you need more).
+
+Returns the max number of bytes.
+
+=item SetStmtCloseType ( TYPE [, CONNECTION ] )
+
+Sets a particular I<hstmt> close type for the connection. This is the
+same as C<ODBCFreeStmt(hstmt, TYPE)>. By default, the connection of
+the current object will be used. If C<CONNECTION> is a valid
+connection number, then it will be used.
+
+C<TYPE> may be one of:
+
+ SQL_CLOSE
+ SQL_DROP
+ SQL_UNBIND
+ SQL_RESET_PARAMS
+
+Returns a string indicating the newly set type.
+
+=item SetStmtOption ( OPTION ) *
+
+Sets the value of the specified statement option C<OPTION>. Refer to
+ODBC documentation for more information on the options and values.
+
+Returns I<true> on success, I<false> otherwise.
+
+=item ShutDown ()
+
+Closes the ODBC connection and dumps to the screen info about
+it. Used primarily for debugging.
+
+No return value.
+
+=item Sql ( SQL_STRING )
+
+Executes the SQL command C<SQL_STRING> on the current connection.
+
+Returns I<?> on success, or an error number on failure.
+
+=item TableList ( QUALIFIER, OWNER, NAME, TYPE )
+
+Returns the catalog of tables that are available in the DSN. For an
+unknown parameter, just specify the empty string I<"">.
+
+Returns an array of table names.
+
+=item Transact ( TYPE ) *
+
+Forces the ODBC connection to perform a I<rollback> or I<commit>
+transaction.
+
+C<TYPE> may be one of:
+
+ SQL_COMMIT
+ SQL_ROLLBACK
+
+B<NOTE>: This only works with ODBC drivers that support transactions.
+Your driver supports it if I<true> is returned from:
+
+ $O->GetFunctions($O->SQL_API_SQLTRANSACT)[1]
+
+(See C<GetFunctions> for more details.)
+
+Returns I<true> on success, I<false> otherwise.
+
+=item Version ( PACKAGES )
+
+Returns an array of version numbers for the requested packages
+(F<ODBC.pm> or F<ODBC.PLL>). If the list C<PACKAGES> is empty, then
+all version numbers are returned.
+
+=back
+
+=head1 LIMITATIONS
+
+What known problems does this thing have?
+
+=over
+
+=item *
+
+If the account under which the process runs does not have write
+permission on the default directory (for the process, not the ODBC
+DSN), you will probably get a runtime error during a
+C<SQLConnection>. I don't think that this is a problem with the code,
+but more like a problem with ODBC. This happens because some ODBC
+drivers need to write a temporary file. I noticed this using the MS
+Jet Engine (Access Driver).
+
+=item *
+
+This module has been neither optimized for speed nor optimized for
+memory consumption.
+
+=back
+
+=head1 INSTALLATION NOTES
+
+If you wish to use this module with a build of Perl other than
+ActivePerl, you may wish to fetch the original source distribution for
+this module at:
+
+ ftp://ftp.roth.net:/pub/ntperl/ODBC/970208/Bin/Win32_ODBC_Build_CORE.zip
+
+or one of the other archives at that same location. See the included
+README for hints on installing this module manually, what to do if you
+get a I<parse exception>, and a pointer to a test script for this
+module.
+
+=head1 OTHER DOCUMENTATION
+
+Find a FAQ for Win32::ODBC at:
+
+ http://www.roth.net/odbc/odbcfaq.htm
+
+=head1 AUTHOR
+
+Dave Roth <rothd@roth.net>
+
+=head1 CREDITS
+
+Based on original code by Dan DeMaggio <dmag@umich.edu>
+
+=head1 DISCLAIMER
+
+I do not guarantee B<ANYTHING> with this package. If you use it you
+are doing so B<AT YOUR OWN RISK>! I may or may not support this
+depending on my time schedule.
+
+=head1 HISTORY
+
+Last Modified 1999.09.25.
+
+=head1 COPYRIGHT
+
+Copyright (c) 1996-1998 Dave Roth. All rights reserved.
+
+Courtesy of Roth Consulting: http://www.roth.net/consult/
+
+Use under GNU General Public License. Details can be found at:
+http://www.gnu.org/copyleft/gpl.html
+
+=cut