Steffen Goeldner wrote:
>
> Next, I'll try to find proper TYPE_NAME's. I think about restricting
> SchemaProviderTypes by $AdoType, $IsLong, $IsFixed. This gives:
>
> 1) 0 records, if the provider is buggy
> 2) 1 record in most cases
> 3) >1 records, e.g. for different max column sizes
>
> Case 2) is trivial.
> Case 1) may return NULL (undef) or an standard SQL name?
> Case 3) should return the first type which has a large enough
> COLUMN_SIZE
>
For your demo table, column_info() returns:
||demo| ID| 4| Long| 10| | ||0|| | 4| | | 1| NO
||demo| num1| 4| Long| 10| | ||1|| 0| 4| | | 2|YES
||demo| num2| 5| Short| 5| | ||1|| 0| 5| | | 3|YES
||demo| num3| 6| Single| 7| | ||1|| 0| 6| | | 4|YES
||demo| num4| 8| Double| 15| | ||1|| 0| 8| | | 5|YES
||demo| num5|-11| GUID| | | ||1|| |-11| | | 6|YES
||demo| num6| 2| Decimal| 18| |0||1|| 0| 2| | | 7|YES
||demo| txt1| -9| VarChar| 50|100| ||1|| | -9| |100| 8|YES
||demo| txt2| -9| VarChar|255|510| ||1|| | -9| |510| 9|YES
||demo|memo1|-10| LongText| 0| 0| ||1|| |-10| | 0|10|YES
||demo| dt1| 93| DateTime| | | ||1|| | 9|3| |11|YES
||demo| cur1| 2| Currency| 19| | ||1|| 0| 2| | |12|YES
||demo| cur2| 2| Currency| 19| | ||1|| 0| 2| | |13|YES
||demo| cur3| 2| Currency| 19| | ||1|| 0| 2| | |14|YES
||demo| cur4| 2| Currency| 19| | ||1|| 0| 2| | |15|YES
||demo| cur5| 2| Currency| 19| | ||1|| 0| 2| | |16|YES
||demo| cur6| 2| Currency| 19| | ||1|| 0| 2| | |17|YES
||demo| cur7| 2| Currency| 19| | ||1|| 0| 2| | |18|YES
||demo| an2|-11| GUID| | | ||1||GenGUID()|-11| | |19|YES
||demo| yn1| 16| Bit| 2| | ||0|| | 16| | |20| NO
||demo| yn2| 16| Bit| 2| | ||0|| | 16| | |21| NO
||demo| yn3| 16| Bit| 2| | ||0|| | 16| | |22| NO
||demo| oo1| -4|LongBinary| 0| 0| ||1|| | -4| | 0|23|YES
||demo| hl1|-10| LongText| 0| 0| ||1|| |-10| | 0|24|YES
And for this table:
create table demo3
(
cShort Short
, cLong Long
, cSingle Single
, cDouble Double
, cCurrency Currency
, cDateTime DateTime
, cBit Bit
, cByte Byte
, cGUID GUID
, cBigBinary BigBinary
, cLongBinary LongBinary
, cVarBinary VarBinary (20)
, cLongText LongText
, cVarChar VarChar (10)
, cDecimal Decimal (11,2)
)
column_info() returns:
||demo3| cShort| 5| Short| 5| | ||1||| 5| | | 1|YES
||demo3| cLong| 4| Long| 10| | ||1||| 4| | | 2|YES
||demo3| cSingle| 6| Single| 7| | ||1||| 6| | | 3|YES
||demo3| cDouble| 8| Double| 15| | ||1||| 8| | | 4|YES
||demo3| cCurrency| 2| Currency| 19| | ||1||| 2| | | 5|YES
||demo3| cDateTime| 93| DateTime| | | ||1||| 9|3| | 6|YES
||demo3| cBit| 16| Bit| 2| | ||0||| 16| | | 7| NO
||demo3| cByte| 0| Byte| 3| | ||1||| 0| | | 8|YES
||demo3| cGUID|-11| GUID| | | ||1|||-11| | | 9|YES
||demo3| cBigBinary| -3| BigBinary|4000|4000| ||1||| -3| |4000|10|YES
||demo3|cLongBinary| -4|LongBinary| 0| 0| ||1||| -4| | 0|11|YES
||demo3| cVarBinary| -3| VarBinary| 20| 20| ||1||| -3| | 20|12|YES
||demo3| cLongText|-10| LongText| 0| 0| ||1|||-10| | 0|13|YES
||demo3| cVarChar| -9| VarChar| 10| 20| ||1||| -9| | 20|14|YES
||demo3| cDecimal| 2| Decimal| 11| |2||1||| 2| | |15|YES
Steffen
*** F:\tmp\DBD-ADO\lib\DBD\ADO.pm Mon Nov 26 21:48:40 2001
--- W:\info\lang\perl\test\DBI\DBD\ADO.pm Sat Dec 08 21:55:57 2001
***************
*** 95,100 ****
--- 95,101 ----
my %connect_options;
my $myado_types_supported = ();
+ my $myado_types_supported2 = ();
***************
*** 114,121 ****
use constant DBPROPVAL_TC_NONE => 0;
use constant SQL_GUID
=> -11;
! use constant SQL_BIGINT
=> - 6;
use constant SQL_UNKNOWN_TYPE
=> 0;
use constant SQL_BIT => 14;
use constant SQL_BIT_VARYING => 15;
use constant SQL_BOOLEAN => 16;
--- 115,132 ----
use constant DBPROPVAL_TC_NONE => 0;
use constant SQL_GUID => -11;
! use constant SQL_WLONGVARCHAR => -10;
! use constant SQL_WVARCHAR => -9;
! use constant SQL_WCHAR => -8;
! use constant SQL_BIT => -7;
! use constant SQL_TINYINT => -6;
! use constant SQL_BIGINT => -5;
! use constant SQL_LONGVARBINARY => -4;
! use constant SQL_VARBINARY => -3;
! use constant SQL_BINARY => -2;
! use constant SQL_LONGVARCHAR => -1;
use constant SQL_UNKNOWN_TYPE => 0;
+
use constant SQL_BIT => 14;
use constant SQL_BIT_VARYING => 15;
use constant SQL_BOOLEAN => 16;
***************
*** 162,167 ****
--- 173,198 ----
$VT_I4_BYREF = Win32::OLE::Variant::VT_I4()
| Win32::OLE::Variant::VT_BYREF();
+
+ $myado_types_supported2 = {
+ # AdoType IsLong IsFixed => SqlType
+ $ado_consts->{adBinary } => { 0 => { 0 => SQL_VARBINARY
+ , 1 => SQL_BINARY }
+ , 1 => { 0 => SQL_LONGVARBINARY
+ , 1 => SQL_UNKNOWN_TYPE }}
+ , $ado_consts->{adChar } => { 0 => { 0 => DBI::SQL_VARCHAR
+ , 1 => DBI::SQL_CHAR }
+ , 1 => { 0 => SQL_LONGVARCHAR
+ , 1 => SQL_UNKNOWN_TYPE }}
+ , $ado_consts->{adWChar } => { 0 => { 0 => SQL_WVARCHAR
+ , 1 => SQL_WCHAR }
+ , 1 => { 0 => SQL_WLONGVARCHAR
+ , 1 => SQL_UNKNOWN_TYPE }}
+ # , $ado_consts->{adVarBinary} =>
+ # , $ado_consts->{adVarChar } =>
+ # , $ado_consts->{adVarWChar } =>
+ };
+
$myado_types_supported = {
$ado_consts->{adArray} =>
SQL_ARRAY
, $ado_consts->{adBigInt} =>
SQL_BIGINT
***************
*** 171,180 ****
, $ado_consts->{adChapter} =>
SQL_UNKNOWN_TYPE
, $ado_consts->{adChar} =>
DBI::SQL_CHAR
, $ado_consts->{adCurrency} =>
DBI::SQL_NUMERIC
! , $ado_consts->{adDate} =>
DBI::SQL_DATE
! , $ado_consts->{adDBDate} =>
DBI::SQL_DATE
! , $ado_consts->{adDBTime} =>
DBI::SQL_TIME
! , $ado_consts->{adDBTimeStamp} => DBI::SQL_TIMESTAMP
, $ado_consts->{adDecimal} =>
DBI::SQL_DECIMAL
, $ado_consts->{adDouble} =>
DBI::SQL_DOUBLE
, $ado_consts->{adEmpty} =>
SQL_UNKNOWN_TYPE
--- 202,211 ----
, $ado_consts->{adChapter} =>
SQL_UNKNOWN_TYPE
, $ado_consts->{adChar} =>
DBI::SQL_CHAR
, $ado_consts->{adCurrency} =>
DBI::SQL_NUMERIC
! , $ado_consts->{adDate} =>
SQL_TYPE_TIMESTAMP # XXX Not really!
! , $ado_consts->{adDBDate} =>
SQL_TYPE_DATE
! , $ado_consts->{adDBTime} =>
SQL_TYPE_TIME
! , $ado_consts->{adDBTimeStamp} => SQL_TYPE_TIMESTAMP
, $ado_consts->{adDecimal} =>
DBI::SQL_DECIMAL
, $ado_consts->{adDouble} =>
DBI::SQL_DOUBLE
, $ado_consts->{adEmpty} =>
SQL_UNKNOWN_TYPE
***************
*** 754,759 ****
--- 785,862 ----
$sth;
}
+ sub column_info {
+ my( $dbh, @Criteria ) = @_;
+ my $Criteria = \@Criteria if @Criteria;
+ my $QueryType = 'adSchemaColumns';
+ my @Rows;
+ my $conn = $dbh->{ado_conn};
+ my $tmpCursorLocation = $conn->{CursorLocation};
+ $conn->{CursorLocation} = $ado_consts->{adUseClient};
+
+ my $RecSet = $conn->OpenSchema( $ado_consts->{$QueryType}, $Criteria );
+ my $lastError = DBD::ADO::errors($conn);
+ return DBI::set_err($dbh, $DBD::ADO::err,
+ "Error occurred with call to OpenSchema ($QueryType):
+$lastError")
+ if $lastError;
+
+ $RecSet->{Sort} = 'TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME,
+ORDINAL_POSITION';
+ $lastError = DBD::ADO::errors($conn);
+ return DBI::set_err($dbh, $DBD::ADO::err,
+ "Error occurred defining sort order : $lastError")
+ if $lastError;
+
+ while ( ! $RecSet->{EOF} ) {
+ my @Fields;
+ my $AdoType = $RecSet->Fields('DATA_TYPE' )->{Value};
+ my $ColFlags = $RecSet->Fields('COLUMN_FLAGS')->{Value};
+ my $IsLong = ( $ColFlags & $ado_consts->{adFldLong } ) ? 1
+: 0;
+ my $IsFixed = ( $ColFlags & $ado_consts->{adFldFixed} ) ? 1
+: 0;
+ my @SqlType = DBD::ADO::db::convert_ado_to_odbc( $dbh,
+$AdoType, $IsFixed, $IsLong );
+ # my $TypeInfo = $dbh->type_info( $SqlType[0] );
+ # my $TypeName = $TypeInfo ? $TypeInfo->{TYPE_NAME} : undef;
+ my $TypeName;
+ my $IsNullable = $RecSet->Fields('IS_NULLABLE')->{Value} ?
+'YES' : 'NO';
+ my $ColSize = $RecSet->Fields('NUMERIC_PRECISION'
+)->{Value}
+ ||
+$RecSet->Fields('CHARACTER_MAXIMUM_LENGTH')->{Value};
+ my $ado_tis = DBD::ADO::db::_ado_get_type_info_for( $dbh,
+$AdoType, $IsFixed, $IsLong );
+ # print '***', $AdoType, $IsFixed, $IsLong, ' => ', $ColSize,
+$RecSet->Fields('COLUMN_NAME')->{Value};
+ for my $ti ( sort { $a->{COLUMN_SIZE} <=> $b->{COLUMN_SIZE} }
+@$ado_tis )
+ {
+ $TypeName = $ti->{TYPE_NAME};
+ # print '***', $AdoType, $IsFixed, $IsLong, ' => ',
+$ti->{TYPE_NAME}, $ti->{COLUMN_SIZE}, $ColSize,
+$RecSet->Fields('COLUMN_NAME')->{Value};
+ last if $ti->{COLUMN_SIZE} >= $ColSize;
+ }
+ $Fields[ 0] = $RecSet->Fields('TABLE_CATALOG'
+)->{Value}; # TABLE_CAT
+ $Fields[ 1] = $RecSet->Fields('TABLE_SCHEMA'
+)->{Value}; # TABLE_SCHEM
+ $Fields[ 2] = $RecSet->Fields('TABLE_NAME'
+)->{Value}; # TABLE_NAME
+ $Fields[ 3] = $RecSet->Fields('COLUMN_NAME'
+)->{Value}; # COLUMN_NAME
+ $Fields[ 4] = $SqlType[0]
+ ; # DATA_TYPE !!!
+ $Fields[ 5] = $TypeName
+ ; # TYPE_NAME !!!
+ $Fields[ 6] = $ColSize
+ ; # COLUMN_SIZE !!! MAX for *LONG*
+ $Fields[ 7] = $RecSet->Fields('CHARACTER_OCTET_LENGTH'
+)->{Value}; # BUFFER_LENGTH !!! MAX for *LONG*, ... (e.g. num)
+ $Fields[ 8] = $RecSet->Fields('NUMERIC_SCALE'
+)->{Value}; # DECIMAL_DIGITS ???
+ $Fields[ 9] = undef
+ ; # NUM_PREC_RADIX !!!
+ $Fields[10] = $RecSet->Fields('IS_NULLABLE'
+)->{Value}; # NULLABLE !!!
+ $Fields[11] = $RecSet->Fields('DESCRIPTION'
+)->{Value}; # REMARKS
+ $Fields[12] = $RecSet->Fields('COLUMN_DEFAULT'
+)->{Value}; # COLUMN_DEF
+ $Fields[13] = $SqlType[1]
+ ; # SQL_DATA_TYPE !!!
+ $Fields[14] = $SqlType[2]
+ ; # SQL_DATETIME_SUB !!!
+ $Fields[15] = $RecSet->Fields('CHARACTER_OCTET_LENGTH'
+)->{Value}; # CHAR_OCTET_LENGTH !!! MAX for *LONG*
+ $Fields[16] = $RecSet->Fields('ORDINAL_POSITION'
+)->{Value}; # ORDINAL_POSITION
+ $Fields[17] = $IsNullable
+ ; # IS_NULLABLE !!!
+
+ push( @Rows, \@Fields );
+ $RecSet->MoveNext;
+ }
+ $RecSet->Close; undef $RecSet;
+ $conn->{CursorLocation} = $tmpCursorLocation;
+
+ DBI->connect('dbi:Sponge:','','', { RaiseError => 1 })->prepare(
+ $QueryType, { rows => \@Rows, NAME =>
+ [ qw( TABLE_CAT TABLE_SCHEM TABLE_NAME COLUMN_NAME DATA_TYPE
+TYPE_NAME COLUMN_SIZE BUFFER_LENGTH DECIMAL_DIGITS NUM_PREC_RADIX NULLABLE REMARKS
+COLUMN_DEF SQL_DATA_TYPE SQL_DATETIME_SUB CHAR_OCTET_LENGTH ORDINAL_POSITION
+IS_NULLABLE ) ]});
+ }
+
sub primary_key_info {
my( $dbh, @Criteria ) = @_;
my $QueryType = 'adSchemaPrimaryKeys';
***************
*** 1009,1030 ****
return \@prov_type_return;
}
# Attempt to convert an ADO data type into an ODBC/SQL data type.
sub convert_ado_to_odbc {
! my ($dbh, $attrib) = @_;
return $dbh->DBI::set_err( -1,
"convert_ado_to_odbc: call without any attributes.")
! unless $attrib;
unless( $ado_types_supported ) {
&_determine_type_support($dbh);
}
! if ( exists $myado_types_supported->{$attrib} ) {
! return $myado_types_supported->{$attrib};
}
! return $attrib;
}
sub OpenSchema {
--- 1112,1168 ----
return \@prov_type_return;
}
+ sub _ado_get_type_info_for {
+ my ($dbh, $AdoType, $IsFixed, $IsLong ) = @_;
+
+ unless( $dbh->{ado_type_info_hash} ) {
+ my $sth = $dbh->func('adSchemaProviderTypes','OpenSchema');
+ while ( my $r = $sth->fetchrow_hashref ) {
+ push
+@{$dbh->{ado_type_info_hash}{$r->{DATA_TYPE}}{$r->{IS_FIXEDLENGTH}}{$r->{IS_LONG}}},
+$r;
+ }
+ }
+ $dbh->{ado_type_info_hash}{$AdoType}{$IsFixed}{$IsLong} || [];
+ }
+
# Attempt to convert an ADO data type into an ODBC/SQL data type.
sub convert_ado_to_odbc {
! my ($dbh, $AdoType, $IsFixed, $IsLong ) = @_;
return $dbh->DBI::set_err( -1,
"convert_ado_to_odbc: call without any attributes.")
! unless $AdoType;
unless( $ado_types_supported ) {
&_determine_type_support($dbh);
}
!
! my $SqlType = 0;
!
! if ( $AdoType & $ado_consts->{adArray} ) {
! $SqlType = 50; # XXX DBI::SQL_ARRAY();
! }
! elsif ( exists $myado_types_supported2->{$AdoType}{$IsLong}{$IsFixed}
) {
! $SqlType =
$myado_types_supported2->{$AdoType}{$IsLong}{$IsFixed};
}
+ elsif ( exists $myado_types_supported->{$AdoType} ) {
+ $SqlType = $myado_types_supported->{$AdoType};
+ }
+
+ if ( wantarray ) { # DATA_TYPE, SQL_DATA_TYPE, SQL_DATETIME_SUB
+ my @a = ( $SqlType );
! if ( 90 < $SqlType && $SqlType < 100 ) { # SQL_DATETIME
! push @a, 9, $SqlType - 90;
! }
! elsif ( 100 < $SqlType && $SqlType < 120 ) { # SQL_INTERVAL
! push @a, 10, $SqlType - 100;
! }
! else {
! push @a, $SqlType, undef;
! }
! return @a;
! }
! return $SqlType;
}
sub OpenSchema {