# $Id: //depot/tilpasninger/dbd-ingres/Ingres.pm#17 $ $DateTime: 2004/01/12 12:10:18 $ $Revision: #17 $ # # Copyright (c) 1996-2000 Henrik Tougaard # # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the Perl README file. require 5.004; =head1 NAME DBD::Ingres - DBI driver for Ingres database systems =head1 SYNOPSIS $dbh = DBI->connect("DBI:Ingres:$dbname", $user, $options, {AutoCommit=>0}) $sth = $dbh->prepare($statement) $sth = $dbh->prepare($statement, {ing_readonly=>1}) $sth->execute @row = $sth->fetchrow $sth->finish $dbh->commit $dbh->rollback $dbh->disconnect ...and many more =cut # The POD text continues at the end of the file. { package DBD::Ingres; use DBI 1.00; use DynaLoader (); @ISA = qw(DynaLoader); $VERSION = '0.53'; my $Revision = substr(q$Change: 18308 $, 8)/100; bootstrap DBD::Ingres $VERSION; $err = 0; # holds error code for DBI::err $errstr = ""; # holds error string for DBI::errstr $drh = undef; # holds driver handle once initialised sub driver{ return $drh if $drh; my($class, $attr) = @_; $class .= "::dr"; # not a 'my' since we use it above to prevent multiple drivers $drh = DBI::_new_drh($class, { 'Name' => 'Ingres', 'Version' => $VERSION, 'Err' => \$DBD::Ingres::err, 'Errstr' => \$DBD::Ingres::errstr, 'Attribution' => 'Ingres DBD by Henrik Tougaard', }); $drh; } 1; } { package DBD::Ingres::dr; # ====== DRIVER ====== use strict; sub connect { my($drh, $dbname, $user, $auth)= @_; # create a 'blank' dbh my $this = DBI::_new_dbh($drh, { 'Name' => $dbname, 'USER' => $user, 'CURRENT_USER' => $user, }); unless ($ENV{'II_SYSTEM'}) { warn("II_SYSTEM not set. Ingres may fail\n") if $drh->{Warn}; } unless (-d "$ENV{'II_SYSTEM'}/ingres") { warn("No ingres directory in \$II_SYSTEM. Ingres may fail\n") if $drh->{Warn}; } $user = "" unless defined $user; $auth = "" unless defined $auth; # Connect to the database.. DBD::Ingres::db::_login($this, $dbname, $user, $auth) or return undef; $this; } sub data_sources { my ($drh) = @_; warn("\$drh->data_sources() not defined for Ingres\n") if $drh->{"warn"}; ""; } } { package DBD::Ingres::db; # ====== DATABASE ====== use strict; #EXPERIMENTAL! Do not use it! sub datatype_helper { my ($dbh, $schema, $tablename, $columnname) = @_; my $href = undef; my $sth = $dbh->column_info('',$schema, $tablename,$columnname); return until $href = $sth->fetchrow_hashref; if (${$href}{type_name} =~ /LONG VARCHAR/ ) { return DBI::SQL_LONGVARCHAR; } elsif (${$href}{type_name} =~ /LONG BYTE/ ) { return DBI::SQL_LONGVARBINARY; } elsif (${$href}{type_name} =~ /DECIMAL/ ) { return DBI::SQL_DECIMAL; } elsif (${$href}{type_name} =~ /INT/ ) { return DBI::SQL_INTEGER; } else { return DBI::SQL_VARCHAR; } } sub do { my ($dbh, $statement, $attribs, @params) = @_; Carp::carp "DBD::Ingres::\$dbh->do() attribs unused\n" if $attribs; if ( (lc($statement) =~ /^insert/) or (lc($statement) =~ /^update/) or (lc($statement) =~ /^delete/) ) { my $sth = $dbh->prepare($statement) or return undef; my $cnt = 0; foreach (@params) { ++$cnt; if ( defined) { $sth->bind_param($cnt, $_); } else { $sth->bind_param($cnt, $_, { TYPE => DBI::SQL_VARCHAR }); } #dummy type, not used } my $numrows = $sth->execute() or return undef; $sth->finish; return $numrows; #return $sth->rows; should bring the same result, but doesnt } else { delete $dbh->{Statement}; my $numrows = DBD::Ingres::db::_do($dbh, $statement); return $numrows ; } } sub prepare { my($dbh, $statement, $attribs)= @_; my $ing_readonly = defined($attribs->{ing_readonly}) ? $attribs->{ing_readonly} : scalar $statement !~ /select.*for\s+(?:deferred\s+|direct\s+)?update/is; # create a 'blank' sth my $sth = DBI::_new_sth($dbh, { Statement => $statement, ing_statement => $statement, ing_readonly => $ing_readonly, }); DBD::Ingres::st::_prepare($sth, $statement, $attribs) or return undef; $sth; } sub table_info { my ($dbh, $catalog, $schema, $table, $type) = @_; $schema = ($schema) ? $schema : q/%/; $table = ($table) ? $table : q/%/; my $sth = $dbh->prepare(" SELECT VARCHAR(null) AS TABLE_CAT, table_owner AS TABLE_SCHEM, table_name, 'TABLE' AS TABLE_TYPE FROM iitables WHERE table_type='T' AND VARCHAR(table_owner) LIKE '$schema' AND VARCHAR(table_name) LIKE '$table'"); # my $sth = $dbh->prepare(" # SELECT VARCHAR(null) AS TABLE_CAT, table_owner AS TABLE_SCHEM, table_name, 'TABLE' AS TABLE_TYPE # FROM IITABLES # WHERE table_type='T' # UNION # SELECT null, table_owner, table_name, 'VIEW' # FROM IITABLES # WHERE table_type ='V'"); return unless $sth; $sth->execute; $sth; } sub column_info { my ($dbh, $catalog, $schema, $table, $column) = @_; $schema = ($schema) ? $schema : q/%/; $table = ($table) ? $table : q/%/; $column = ($column) ? $column : q/%/; my $sth = $dbh->prepare(" SELECT VARCHAR(null) AS TABLE_CAT, table_owner AS TABLE_SCHEM, table_name AS TABLE_NAME, column_name AS COLUMN_NAME, column_ingdatatype AS DATA_TYPE, column_datatype AS TYPE_NAME, column_length AS COLUMN_SIZE, INT(0) AS BUFFER_LENGTH, column_scale AS DECIMAL_DIGITS, INT(0) AS NUM_PREC_RADIX, column_nulls AS NULLABLE, VARCHAR('') AS REMARKS, column_default_val AS COLUMN_DEF, column_datatype AS SQL_DATA_TYPE, VARCHAR(null) AS SQL_DATETIME_SUB, INT(0) AS CHAR_OCTET_LENGTH, column_sequence AS ORDINAL_POSITION, column_nulls as IS_NULLABLE FROM iicolumns WHERE VARCHAR(table_owner) LIKE '$schema' AND VARCHAR(table_name) LIKE '$table' AND VARCHAR(column_name) LIKE '$column' ORDER BY table_owner, table_name, column_sequence"); return unless $sth; $sth->execute; $sth; } sub get_info { my ($dbh, $ident) = @_; my $info = ''; return unless $ident; if ($ident == 17 ) { return "Ingres"; } elsif ($ident == 18) { $info = "_version"; } elsif ($ident == 29) { return "'"; } elsif ($ident == 41) { return "."; } else { return; } my $sth = $dbh->prepare("SELECT dbmsinfo('$info')"); return unless $sth; $sth->execute; my $version = $sth->fetchrow; if ($version =~ /II 9\.3\.0/) { return "9.3"; } elsif ($version =~ /II 9\.2\.0/) { return "2006 R3"; } elsif ($version =~ /II 9\.1\.0/) { return "2006 R2"; } elsif ($version =~ /II 9\.0\.4/) { return "2006"; } else { return "unknown";} # return $version; } sub ping { my($dbh) = @_; # we know that DBD::Ingres prepare does a describe so this will # actually talk to the server and is this a valid and cheap test. return 1 if $dbh->prepare("select * from iitables"); return 0; } sub type_info_all { my ($dbh) = @_; my $ti = [ { TYPE_NAME => 0, DATA_TYPE => 1, COLUMN_SIZE => 2, LITERAL_PREFIX => 3, LITERAL_SUFFIX => 4, CREATE_PARAMS => 5, NULLABLE => 6, CASE_SENSITIVE => 7, SEARCHABLE => 8, UNSIGNED_ATTRIBUTE=> 9, FIXED_PREC_SCALE=> 10, AUTO_UNIQUE_VALUE=> 11, LOCAL_TYPE_NAME => 12, MINIMUM_SCALE => 13, MAXIMUM_SCALE => 14, SQL_DATA_TYPE => 15, SQL_DATETIME_SUB=> 16, NUM_PREC_RADIX => 17, INTERVAL_PRECISIO=> 18, }, [ 'SMALLINT', DBI::SQL_SMALLINT, undef, "","", undef, 1, 0, 2, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'INTEGER', DBI::SQL_INTEGER, undef, "","", "size=1,2,4", 1, 0, 2, 0, 0 ,0 ,undef ,0 ,0, undef, undef, undef, undef ], [ 'MONEY', DBI::SQL_DECIMAL, undef, "","", undef, 1, 0, 2, 0, 1, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'FLOAT', DBI::SQL_DOUBLE, undef, "","", "size=4,8", 1, 0, 2, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'DATE', DBI::SQL_DATE, undef, "'","'", undef, 1, 0, 3, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'DECIMAL', DBI::SQL_DECIMAL, undef, "","", "precision,scale", 1, 0, 2, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'VARCHAR', DBI::SQL_VARCHAR, undef, "'","'", "max length", 1, 1, 3, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'BYTE VARYING', DBI::SQL_VARBINARY, undef, "'","'", "max length", 1, 1, 3, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'CHAR', DBI::SQL_CHAR, undef, "'","'", "length", 1, 1, 3, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'BYTE', DBI::SQL_BINARY, undef, "'","'", "length", 1, 1, 3, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'LONG VARCHAR', DBI::SQL_LONGVARCHAR, undef, undef, undef, undef, 1, 1, 0, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], [ 'LONG BYTE', DBI::SQL_LONGVARBINARY, undef, undef, undef, undef, 1, 1, 0, 0, 0, 0, undef, 0, 0, undef, undef, undef, undef ], ]; return $ti; } } { package DBD::Ingres::st; # ====== STATEMENT ====== use strict; } 1; =head1 DESCRIPTION DBD::Ingres is a database driver for the perl DBI system that allows access to Ingres databases. It is built on top of the standard DBI extension and implements the methods that DBI requires. This document describes the differences between the "generic" DBD and DBD::Ingres. =head1 EXTENSIONS/CHANGES =head2 Connect DBI->connect("DBI:Ingres:dbname[;options]"); DBI->connect("DBI:Ingres:dbname[;options]", user [, password]); DBI->connect("DBI:Ingres:dbname[;options]", user [, password], \%attr); To use DBD::Ingres call C specifying a I option beginning with I<"DBI:Ingres:">, followed by the database instance name and optionally a semi-colon followed by any Ingres connect options. Options must be given exactly as they would be given in an ESQL-connect statement, i.e., separated by blanks. The connect call will result in a connect statement like: CONNECT dbname IDENTIFIED BY user PASSWORD password OPTIONS=options E.g., =over 4 =item * local database DBI->connect("DBI:Ingres:mydb", "me", "mypassword") =item * with options and no password DBI->connect("DBI:Ingres:mydb;-Rmyrole/myrolepassword", "me") =item * Ingres/Net database DBI->connect("DBI:Ingres:thatnode::thisdb;-xw -l", "him", "hispassword") =back and so on. =head2 AutoCommit Defaults to ON B: The DBI spec defines that AutoCommit is B after connect. This is the opposite of the normal Ingres default (autocommit B). To reflect this behavior in your code, it is recommended that the C call ends with the attributes C<{ AutoCommit =E 0 }>. =head2 Returned Types The DBI docs state that: =over 4 =item * Most data is returned to the perl script as strings (null values are returned as undef). This allows arbitrary precision numeric data to be handled without loss of accuracy. Be aware that perl may not preserve the same accuracy when the string is used as a number. =back This is B the case for Ingres. Data is returned as it would be to an embedded C program: =over 4 =item * Integers are returned as integer values (IVs in perl-speak). =item * Floats and doubles are returned as numeric values (NVs in perl-speak). =item * Dates, moneys, chars, varchars and others are returned as strings (PVs in perl-speak). =back This does not cause loss of precision, because the Ingres API uses these types to return the data anyway. =head2 get_dbevent This non-DBI method calls C and C to fetch a pending database event. If called without argument a blocking C is called. A numeric argument results in a call to C. In a second step C is called to fetch the related information, wich is returned as a reference to a hash with keys C, C, C, C and C