H.Merijn Brand wrote:
> I see a big difference in what $sth->{TYPE} returns (and the name) and
> what column_info () - if implemented - is returning.

I don't think I do with DBD::ODBC (results below).

> From the DBI docs:
> 
>    Handle attributes:
> 
>        "TYPE"  (array-ref, read-only)
> 
>        Returns a reference to an array of integer values for each column.
>        The value indicates the data type of the corresponding column.
> 
>        The values correspond to the international standards (ANSI X3.135
>        and ISO/IEC 9075) which, in general terms, means ODBC. Driver-specific
>        types that don't exactly match standard types should generally return
>        the same values as an ODBC driver supplied by the makers of the
>        database. That might include private type numbers in ranges the
>        vendor has officially registered with the ISO working group:
> 
>          ftp://sqlstandards.org/SC32/SQL_Registry/
> 
>        Where there's no vendor-supplied ODBC driver to be compatible with,
>        the DBI driver can use type numbers in the range that is now
>        officially reserved for use by the DBI: -9999 to -9000.
> 
>        All possible values for "TYPE" should have at least one entry in the
>        output of the "type_info_all" method (see "type_info_all").
> 
>    column_info:
> 
>        DATA_TYPE: The concise data type code.
> 
>        TYPE_NAME: A data source dependent data type name.
> 
> DATA_TYPE has no specification of what type of code that is. It can be
> either the code the type is internally known by with the database, or
> it can be the ODBC equivalent.
> 
> TYPE_NAME has no guarantee whatsoever to be like what type_info ()
> returns with code like:

I thought it should.

> --8<---
> {   my %types;        # Cache for types
> 
>     # Convert numeric to readable
>     sub _type_name
>     {
>       my $type = shift;
> 
>       unless (exists $types{$dbh}{$type}) {
>           my $tpi = $type =~ m/^-?[0-9]+$/ ? $dbh->type_info ($type) : undef;
>           $types{$dbh}{$type} = $tpi ? $tpi->{TYPE_NAME} : $type // "?";
>           }
>       return $types{$dbh}{$type};
>       } # type_name
>     }
> -->8---
> 
> The keys in the hashref returned from column_info () often do not honor
> the {FetchHashKeyName} dbh attribute, which makes it quite a bit harder
> to write database-independent code. I think either document that the
> sth returned from column_info () doesn't have to follow this attribute,
> or make the authors alter the code so it does.

I guess you are mostly referring to the 'COLUMN_NAME', 'TABLE_NAME',
'TABLE_SCHEM' and 'TABLE_CAT' keys - yes?

> 
> Extra fun comes from databases that store type names instead of type
> codes in their data-dictionary (like Unify and SQLite), and reversing
> that process to make column_info () return both TYPE_NAME and DATA_TYPE
> makes it a different pair than TYPE and the derived counterpart from
> type_info ().
> 
> 
> My real question is, should the docs be enhanced to
> 
> • make clear that these two return different things

or make them return the same things. Obviously for ODBC this is simple
as they are the same things but for other DBDs I think it is useful to
know a single type that can be used across all databases and the real
type implemented in the database (and be able to map between them) -
from your results mysql looks closest in this respect.

People writing bugzilla, open LDAP etc backend support in databases are
having to hand code the schema for each database but in many cases it
may be possible (if the DBDs returned a single set of types) to code
this generically (although I'd guess it would be still quite hard).

> • column_info () is not always available (sth is undef then)

I guess so.

It should not be difficult to add column_info to DBD::Oracle - I know
this has come up in the past. I think I even provided some SQL that
would do it but I cannot find it right now.

> Here's my findings so far ...
> 
> PostgreSQL
>   Create as               sth attributes              column_info ()
>   ----------------------- --------------------------  
> -----------------------------------
>   bigint                  ?                       -5  bigint                  
>          -5
>   bigserial               ?                       -5  bigint                  
>          -5
>   bit                     unknown                  0  bit                     
>           0
>   bit (9)                 unknown                  0  bit                     
>           0
>   bit varying             unknown                  0  bit varying             
>           0
>   bit varying (35)        unknown                  0  bit varying             
>           0
>   bool                    bool                    16  boolean                 
>          16
>   boolean                 bool                    16  boolean                 
>          16
>   box                     unknown                  0  box                     
>           0
>   bytea                   bytea                   -3  bytea                   
>          -3
>   character               bpchar                   1  character               
>           1
>   character (5)           bpchar                   1  character               
>           1
>   character varying       text                    12  character varying       
>          12
>   character varying (21)  text                    12  character varying       
>          12
>   cidr                    unknown                  0  cidr                    
>           0
>   circle                  unknown                  0  circle                  
>           0
>   date                    date                    91  date                    
>          91
>   decimal                 numeric                  3  numeric                 
>           3
>   decimal (15, 2)         numeric                  3  numeric                 
>           3
>   decimal (8)             numeric                  3  numeric                 
>           3
>   double precision        float4                   6  double precision        
>           6
>   float4                  unknown                  0  real                    
>           0
>   float8                  float4                   6  double precision        
>           6
>   inet                    unknown                  0  inet                    
>           0
>   int                     int4                     4  integer                 
>           4
>   int2                    int2                     5  smallint                
>           5
>   int4                    int4                     4  integer                 
>           4
>   int8                    ?                       -5  bigint                  
>          -5
>   integer                 int4                     4  integer                 
>           4
>   interval                unknown                  0  interval                
>           0
>   interval (3)            unknown                  0  interval                
>           0
>   line                    unknown                  0  line                    
>           0
>   lseg                    unknown                  0  lseg                    
>           0
>   macaddr                 unknown                  0  macaddr                 
>           0
>   money                   unknown                  0  money                   
>           0
>   numeric                 numeric                  3  numeric                 
>           3
>   numeric (15, 2)         numeric                  3  numeric                 
>           3
>   numeric (8)             numeric                  3  numeric                 
>           3
>   path                    unknown                  0  path                    
>           0
>   point                   unknown                  0  point                   
>           0
>   polygon                 unknown                  0  polygon                 
>           0
>   real                    unknown                  0  real                    
>           0
>   serial                  int4                     4  integer                 
>           4
>   serial4                 int4                     4  integer                 
>           4
>   smallint                int2                     5  smallint                
>           5
>   text                    ?                       -1  text                    
>          -1
>   time                    time                    92  time without time zone  
>          92
>   time (3)                time                    92  time without time zone  
>          92
>   timestamp               timestamp               11  timestamp without time 
> zone      11
>   timestamp (3)           timestamp               11  timestamp without time 
> zone      11
>   timestamptz             timestamptz             95  timestamp with time 
> zone         95
>   timestamptz (3)         timestamptz             95  timestamp with time 
> zone         95
>   timetz                  unknown                  0  time with time zone     
>           0
>   timetz (3)              unknown                  0  time with time zone     
>           0
>   tsquery                 unknown                  0  tsquery                 
>           0
>   tsvector                unknown                  0  tsvector                
>           0
>   txid_snapshot           unknown                  0  txid_snapshot           
>           0
>   uuid                    unknown                  0  uuid                    
>           0
>   varchar                 text                    12  character varying       
>          12
>   varchar (21)            text                    12  character varying       
>          12
>   xml                     unknown                  0  xml                     
>           0
> 
> 
> DBD::Oracle does not support column_info ()
> 
> Oracle
>   Create as               sth attributes              column_info ()
>   ----------------------- --------------------------  
> -------------------------
>   bfile                   ?                    -9114  -
>   blob                    ?                       30  -
>   char                    CHAR                     1  -
>   char (19)               CHAR                     1  -
>   clob                    ?                       40  -
>   date                    DATE                    93  -
>   float                   DOUBLE PRECISION         8  -
>   float (12)              DOUBLE PRECISION         8  -
>   integer                 DECIMAL                  3  -
>   interval day to second  INTERVAL DAY TO SECOND   110  -
>   interval day (3) to second (2)  INTERVAL DAY TO SECOND   110  -
>   long                    LONG                    -1  -
>   long raw                LONG RAW                -4  -
> Field 1 has an Oracle type (106) which is not explicitly supported at 
> /pro/lib/perl5/site_perl/5.10.1/x86_64-linux/DBD/Oracle.pm line 284, <DATA> 
> line 122.
> DBD::Oracle::st execute failed: ORA-00932: inconsistent datatypes: expected 
> NUMBER got LABEL (DBD ERROR: error possibly near <*> indicator at char 7 in 
> 'select <*>* from xbb where 0 = 1') [for Statement "select * from xbb where 0 
> = 1"] at /pro/lib/perl5/site_perl/5.10.1/x86_64-linux/PROCURA/DBD.pm line 
> 421, <DATA> line 122.
>   mlslabel                ?                    -9106  -
>   nchar                   CHAR                     1  -
>   nchar (13)              CHAR                     1  -
>   nclob                   ?                       40  -
>   number                  DOUBLE PRECISION         8  -
>   number (8)              DECIMAL                  3  -
>   number (15, 2)          DECIMAL                  3  -
>   number (9, -2)          DECIMAL                  3  -
>   nvarchar2 (3)           VARCHAR2                12  -
>   raw (58)                ?                       -2  -
>   rowid                   ?                    -9104  -
>   timestamp               DATE                    93  -
>   timestamp (3)           DATE                    93  -
>   urowid                  ?                    -9104  -
>   varchar (46)            VARCHAR2                12  -
>   varchar2 (46)           VARCHAR2                12  -
>   xmltype                 ?                    -9108  -
> 
> 
> DBD::Unify will have column_info () in the next release. I'm all open
> for changes.
> 
> Unify
>   Create as               sth attributes              column_info ()
>   ----------------------- --------------------------  
> -----------------------------------
>   amount                  FLOAT                    6  AMOUNT                  
>        -206
>   amount (5, 2)           FLOAT                    6  AMOUNT                  
>        -206
>   huge amount             REAL                     7  HUGE AMOUNT             
>        -207
>   huge amount (5, 2)      REAL                     7  HUGE AMOUNT             
>        -207
>   huge amount (15, 2)     REAL                     7  HUGE AMOUNT             
>        -207
>   byte                    BYTE                    -2  BYTE                    
>          -2
>   byte (512)              BYTE                    -2  BYTE                    
>          -2
>   char                    CHAR                     1  CHARACTER               
>           1
>   char (12)               CHAR                     1  CHARACTER               
>           1
>   currency                HUGE AMOUNT              0  -
>   currency (9)            HUGE AMOUNT              0  -
>   currency (7,2)          HUGE AMOUNT              0  -
>   date                    DATE                     9  DATE                    
>           9
>   huge date               HUGE DATE               11  HUGE DATE               
>          11
>   decimal                 NUMERIC                  2  NUMERIC                 
>           2
>   decimal (2)             NUMERIC                  2  NUMERIC                 
>           2
>   decimal (8)             NUMERIC                  2  NUMERIC                 
>           2
>   double precision        DOUBLE PRECISION         8  DOUBLE                  
>           8
>   float                   DOUBLE PRECISION         8  FLOAT                   
>           6
>   huge integer            HUGE INTEGER            -5  -
>   integer                 NUMERIC                  2  NUMERIC                 
>           2
>   numeric                 NUMERIC                  2  NUMERIC                 
>           2
>   numeric (2)             SMALLINT                 5  NUMERIC                 
>           2
>   numeric (6)             NUMERIC                  2  NUMERIC                 
>           2
>   real                    REAL                     7  REAL                    
>           7
>   smallint                SMALLINT                 5  NUMERIC                 
>           2
>   text                    TEXT                    -1  TEXT                    
>          -1
>   time                    TIME                    10  TIME                    
>          10
> 
> MySQL
>   Create as               sth attributes              column_info ()
>   ----------------------- --------------------------  
> -----------------------------------
>   serial                  bigint                  -5  BIGINT                  
>           4
>   tinyint                 tinyint                 -6  TINYINT                 
>           4
>   tinyint unsigned        tinyint                 -6  TINYINT                 
>           4
>   tinyint (2)             tinyint                 -6  TINYINT                 
>           4
>   tinyint (2) unsigned    tinyint                 -6  TINYINT                 
>           4
>   bool                    tinyint                 -6  TINYINT                 
>           4
>   boolean                 tinyint                 -6  TINYINT                 
>           4
>   smallint                smallint                 5  SMALLINT                
>           4
>   smallint unsigned       smallint                 5  SMALLINT                
>           4
>   smallint (2)            smallint                 5  SMALLINT                
>           4
>   smallint (2) unsigned   smallint                 5  SMALLINT                
>           4
>   mediumint               integer                  4  MEDIUMINT               
>           4
>   mediumint unsigned      integer                  4  MEDIUMINT               
>           4
>   mediumint (2)           integer                  4  MEDIUMINT               
>           4
>   mediumint (2) unsigned  integer                  4  MEDIUMINT               
>           4
>   int                     integer                  4  INT                     
>           4
>   int unsigned            integer                  4  INT                     
>           4
>   int (2)                 integer                  4  INT                     
>           4
>   int (2) unsigned        integer                  4  INT                     
>           4
>   integer                 integer                  4  INT                     
>           4
>   integer unsigned        integer                  4  INT                     
>           4
>   integer (2)             integer                  4  INT                     
>           4
>   integer (2) unsigned    integer                  4  INT                     
>           4
>   bigint                  bigint                  -5  BIGINT                  
>           4
>   bigint unsigned         bigint                  -5  BIGINT                  
>           4
>   bigint (2)              bigint                  -5  BIGINT                  
>           4
>   bigint (2) unsigned     bigint                  -5  BIGINT                  
>           4
>   float                   float                    7  FLOAT                   
>           6
>   float unsigned          float                    7  FLOAT                   
>           6
>   float (15)              float                    7  FLOAT                   
>           6
>   float (15) unsigned     float                    7  FLOAT                   
>           6
>   float (15, 2)           float                    7  FLOAT                   
>           6
>   float (15, 2) unsigned  float                    7  FLOAT                   
>           6
>   double                  double                   8  DOUBLE                  
>           8
>   double unsigned         double                   8  DOUBLE                  
>           8
>   double (15, 2)          double                   8  DOUBLE                  
>           8
>   double (15, 2) unsigned  double                   8  DOUBLE                 
>            8
>   double precision        double                   8  DOUBLE                  
>           8
>   double precision unsigned  double                   8  DOUBLE               
>              8
>   double precision (15, 2)  double                   8  DOUBLE                
>             8
>   double precision (15, 2) unsigned  double                   8  DOUBLE       
>                      8
>   decimal                 decimal                  3  DECIMAL                 
>           3
>   decimal unsigned        decimal                  3  DECIMAL                 
>           3
>   decimal (15)            decimal                  3  DECIMAL                 
>           3
>   decimal (15) unsigned   decimal                  3  DECIMAL                 
>           3
>   decimal (15, 2)         decimal                  3  DECIMAL                 
>           3
>   decimal (15, 2) unsigned  decimal                  3  DECIMAL               
>             3
>   date                    date                     9  DATE                    
>           9
>   datetime                timestamp               11  DATETIME                
>          11
>   timestamp               timestamp               11  TIMESTAMP               
>          11
>   time                    time                    10  TIME                    
>          10
>   year                    smallint                 5  YEAR                    
>           4
>   year (2)                smallint                 5  YEAR                    
>           4
>   year (4)                smallint                 5  YEAR                    
>           4
>   char                    char                     1  CHAR                    
>           1
>   char (3)                char                     1  CHAR                    
>           1
>   nchar                   char                     1  CHAR                    
>           1
>   nchar (3)               char                     1  CHAR                    
>           1
>   national char           char                     1  CHAR                    
>           1
>   national char (3)       char                     1  CHAR                    
>           1
>   char character set utf8  char                     1  CHAR                   
>            1
>   varchar (3)             varchar                 12  VARCHAR                 
>          12
>   nvarchar (3)            varchar                 12  VARCHAR                 
>          12
>   national varchar (3)    varchar                 12  VARCHAR                 
>          12
>   varchar (3) character set utf8  varchar                 12  VARCHAR         
>                  12
>   binary (35)             char                     1  BINARY                  
>           1
>   varbinary (17)          varchar                 12  VARBINARY               
>          12
>   tinyblob                blob                    -4  TINYBLOB                
>          12
>   tinytext                blob                    -4  TINYTEXT                
>          12
>   tinytext character set utf8  blob                    -4  TINYTEXT           
>               12
>   blob                    blob                    -4  BLOB                    
>          12
>   blob (123)              blob                    -4  TINYBLOB                
>          12
>   text                    blob                    -4  TEXT                    
>          12
>   text (123)              blob                    -4  TINYTEXT                
>          12
>   text character set utf8  blob                    -4  TEXT                   
>           12
>   text (123) character set utf8  blob                    -4  TEXT             
>                 12
>   mediumblob              blob                    -4  MEDIUMBLOB              
>          12
>   mediumtext              blob                    -4  MEDIUMTEXT              
>          12
>   mediumtext character set utf8  blob                    -4  MEDIUMTEXT       
>                 12
>   longblob                blob                    -4  LONGBLOB                
>          12
>   longtext                blob                    -4  LONGTEXT                
>          12
>   longtext character set utf8  blob                    -4  LONGTEXT           
>               12
>   enum ('a','b')          char                     1  ENUM                    
>          12
>   enum ('a','b') character set utf8  char                     1  ENUM         
>                     12
>   set ('a','b')           char                     1  SET                     
>          12
>   set ('a','b') character set utf8  char                     1  SET           
>                    12
> 
> 
> SQLite does not return handle TYPE attribute attributes :(
> 
> SQLite
>   Create as               sth attributes              column_info ()
>   ----------------------- --------------------------  
> -----------------------------------
>   int                     ?                        0  int                     
>           ?
>   integer                 ?                        0  integer                 
>           ?
>   integer (3)             ?                        0  integer                 
>           ?
>   tinyint                 ?                        0  tinyint                 
>           ?
>   smallint                ?                        0  smallint                
>           ?
>   mediumint               ?                        0  mediumint               
>           ?
>   bigint                  ?                        0  bigint                  
>           ?
>   unsigned big int        ?                        0  unsigned big int        
>           ?
>   int2                    ?                        0  int2                    
>           ?
>   int8                    ?                        0  int8                    
>           ?
>   character (2)           ?                        0  character               
>           ?
>   varchar (20)            ?                        0  varchar                 
>           ?
>   varying character (3)   ?                        0  varying character       
>           ?
>   nchar (13)              ?                        0  nchar                   
>           ?
>   native character (7)    ?                        0  native character        
>           ?
>   nvarchar (11)           ?                        0  nvarchar                
>           ?
>   text                    ?                        0  text                    
>           ?
>   clob                    ?                        0  clob                    
>           ?
>   blob                    ?                        0  blob                    
>           ?
>   real                    ?                        0  real                    
>           ?
>   double                  ?                        0  double                  
>           ?
>   double precision        ?                        0  double precision        
>           ?
>   float                   ?                        0  float                   
>           ?
>   numeric                 ?                        0  numeric                 
>           ?
>   numeric (3)             ?                        0  numeric                 
>           ?
>   decimal (10, 5)         ?                        0  decimal (10, 5)         
>           ?
>   boolean                 ?                        0  boolean                 
>           ?
>   date                    ?                        0  date                    
>           ?
>   datetime                ?                        0  datetime                
>           ?
> 
> 

and here are mine with MS SQL Server (and our driver) - note there may
be a small issue with the XML type here - I have passed this on to the
person responsible. I've skipped multiple identity columns but could
provide more if you really want it.

typeinfo_all:
xml, -152
sql_variant, -150
uniqueidentifier, -11
ntext, -10
nvarchar, -9
sysname, -9
nchar, -8
bit, -7
tinyint, -6
tinyint identity, -6
bigint, -5
bigint identity, -5
image, -4
varbinary, -3
binary, -2
timestamp, -2
text, -1
char, 1
numeric, 2
numeric() identity, 2
decimal, 3
money, 3
smallmoney, 3
decimal() identity, 3
int, 4
int identity, 4
smallint, 5
smallint identity, 5
float, 6
real, 7
varchar, 12
datetime, 93
smalldatetime, 93
PSDATE, 93
PSDATETIME, 93

create table mje (a1 xml,a2 sql_variant,a3 uniqueidentifier,a4 ntext,a5
nvarchar,a6 sysname,a7 nchar,a8 bit,a9 tinyint,a10 tinyint identity,a11
bigint,a12 image,a13 varbinary,a14 binary,a15 timestamp,a16 text,a17
char,a18 numeric,a19 decimal,a20 money,a21 smallmoney,a22 int,a23
smallint,a24 float,a25 real,a26 varchar,a27 datetime,a28
smalldatetime,a29 PSDATE,a30 PSDATETIME)

column_info:
a1, xml, -152
a2, sql_variant, -150
a3, uniqueidentifier, -11
a4, ntext, -10
a5, nvarchar, -9
a6, sysname, -9
a7, nchar, -8
a8, bit, -7
a9, tinyint, -6
a10, tinyint identity, -6
a11, bigint, -5
a12, image, -4
a13, varbinary, -3
a14, binary, -2
a15, timestamp, -2
a16, text, -1
a17, char, 1
a18, numeric, 2
a19, decimal, 3
a20, money, 3
a21, smallmoney, 3
a22, int, 4
a23, smallint, 5
a24, float, 6
a25, real, 7
a26, varchar, 12
a27, datetime, 93
a28, smalldatetime, 93
a29, PSDATE, 93
a30, PSDATETIME, 93

sth->{TYPE}:
$VAR1 = [
          -10,   <--- suspicious entry
          -150,
          -11,
          -10,
          -9,
          -9,
          -8,
          -7,
          -6,
          -6,
          -5,
          -4,
          -3,
          -2,
          -2,
          -1,
          1,
          2,
          3,
          3,
          3,
          4,
          5,
          6,
          7,
          12,
          93,
          93,
          93,
          93
        ];

I seem to remember a similar issue with the lack of column_info came up
on Perl monks recently with DBD::Interbase. With the increasing use of
modules like DBIx::Class etc the meta data methods are becoming a lot
more important than they perhaps used to be.

Martin
-- 
Martin J. Evans
Easysoft Limited
http://www.easysoft.com

Reply via email to