Committed by Greg Sabino Mullane <[email protected]>

Add a new field, pg_expression, to the results from
statistics_info. This will show the index expression for the column in
question. In other words, things such as lower(foo) will show up here. Per
request from RT #76608

---
 Pg.pm          | 76 ++++++++++++++++++++++++++++++++++++++++------------------
 t/03dbmethod.t | 43 +++++++++++++++++----------------
 2 files changed, 76 insertions(+), 43 deletions(-)

diff --git a/Pg.pm b/Pg.pm
index a6ee67f..3a23ded 100644
--- a/Pg.pm
+++ b/Pg.pm
@@ -611,8 +611,9 @@ use 5.008001;
                my $stats_sql = qq{
             SELECT
                 c.relname, i.indkey, i.indisunique, i.indisclustered, a.amname,
-                n.nspname, c.relpages, c.reltuples, i.indexprs,
-                pg_get_expr(i.indpred,i.indrelid) as predicate
+                n.nspname, c.relpages, c.reltuples, i.indexprs, i.indnatts, 
i.indexrelid,
+                pg_get_expr(i.indpred,i.indrelid) as predicate,
+                pg_get_expr(i.indexprs,i.indrelid, true) AS indexdef
             FROM
                 pg_catalog.pg_index i, pg_catalog.pg_class c,
                 pg_catalog.pg_class d, pg_catalog.pg_am a,
@@ -624,6 +625,14 @@ use 5.008001;
                 i.indisunique desc, a.amname, c.relname
         };
 
+               my $indexdef_sql = qq{
+            SELECT
+                pg_get_indexdef(indexrelid,x,true)
+            FROM
+              pg_index
+            JOIN generate_series(1,?) s(x) ON indexrelid = ?
+        };
+
                my @output_rows;
 
                # Table-level stats
@@ -645,6 +654,7 @@ use 5.008001;
                                $tst->{reltuples},# CARDINALITY
                                $tst->{relpages}, # PAGES
                                undef,            # FILTER_CONDITION
+                undef,            # pg_expression
                        ]);
                }
 
@@ -653,16 +663,16 @@ use 5.008001;
                $colnames_sth->execute(@exe_args) or return undef;
                my $colnames = $colnames_sth->fetchall_hashref('attnum');
 
+               # Fetch the individual parts of the index
+               my $sth_indexdef = $dbh->prepare($indexdef_sql);
+
                # Fetch the index definitions
                my $sth = $dbh->prepare($stats_sql);
                $sth->execute(@exe_args) or return undef;
 
                STAT_ROW:
-               #use Data::Dumper;
-               #warn Dumper $stats_sql;
                while (my $row = $sth->fetchrow_hashref) {
-                       #warn Dumper $row;
-                       next if $row->{indexprs}; # We can't return these 
accurately via this interface ...
+
                        next if $unique_only and !$row->{indisunique};
 
                        my $indtype = $row->{indisclustered}
@@ -675,21 +685,26 @@ use 5.008001;
                        my $nonunique = $row->{indisunique} ? 0 : 1;
 
                        my @index_row = (
-                               undef,             # TABLE_CAT
-                               $row->{nspname},   # TABLE_SCHEM
-                               $table,            # TABLE_NAME
-                               $nonunique,        # NON_UNIQUE
-                               undef,             # INDEX_QUALIFIER
-                               $row->{relname},   # INDEX_NAME
-                               $indtype,          # TYPE
-                               undef,             # ORDINAL_POSITION
-                               undef,             # COLUMN_NAME
-                               'A',               # ASC_OR_DESC
-                               $row->{reltuples}, # CARDINALITY
-                               $row->{relpages},  # PAGES
-                               $row->{predicate}, # FILTER_CONDITION
+                               undef,             # TABLE_CAT         0
+                               $row->{nspname},   # TABLE_SCHEM       1
+                               $table,            # TABLE_NAME        2
+                               $nonunique,        # NON_UNIQUE        3
+                               undef,             # INDEX_QUALIFIER   4
+                               $row->{relname},   # INDEX_NAME        5
+                               $indtype,          # TYPE              6
+                               undef,             # ORDINAL_POSITION  7
+                               undef,             # COLUMN_NAME       8
+                               'A',               # ASC_OR_DESC       9
+                               $row->{reltuples}, # CARDINALITY      10
+                               $row->{relpages},  # PAGES            11
+                               $row->{predicate}, # FILTER_CONDITION 12
+                undef,             # pg_expression    13
                        );
 
+                       ## Grab expression information
+                       $sth_indexdef->execute($row->{indnatts}, 
$row->{indexrelid});
+                       my $expression = $sth_indexdef->fetchall_arrayref();
+
                        my $col_nums = $row->{indkey};
                        $col_nums =~ s/^\s+//;
                        my @col_nums = split(/\s+/, $col_nums);
@@ -697,15 +712,17 @@ use 5.008001;
                        my $ord_pos = 1;
                        for my $col_num (@col_nums) {
                                my @copy = @index_row;
-                               $copy[7] = $ord_pos++; # ORDINAL_POSITION
+                               $copy[7] = $ord_pos; # ORDINAL_POSITION
                                $copy[8] = $colnames->{$col_num}->{attname}; # 
COLUMN_NAME
+                               $copy[13] = $expression->[$ord_pos-1][0];
                                push(@output_rows, \@copy);
+                               $ord_pos++;
                        }
                }
 
                my @output_colnames = qw/ TABLE_CAT TABLE_SCHEM TABLE_NAME 
NON_UNIQUE INDEX_QUALIFIER
                                        INDEX_NAME TYPE ORDINAL_POSITION 
COLUMN_NAME ASC_OR_DESC
-                                       CARDINALITY PAGES FILTER_CONDITION /;
+                                       CARDINALITY PAGES FILTER_CONDITION 
pg_expression /;
 
                return _prepare_from_data('statistics_info', \@output_rows, 
\@output_colnames);
        }
@@ -2983,11 +3000,24 @@ Returns a statement handle that can be fetched from to 
give statistics informati
 on a specific table and its indexes. The C<$table> argument is mandatory. The 
 C<$schema> argument is optional but recommended. The C<$unique_only> argument, 
if true, 
 causes only information about unique indexes to be returned. The C<$quick> 
argument is 
-not used by DBD::Pg. For information on the format of the rows returned, 
please see the DBI 
-documentation.
+not used by DBD::Pg. For information on the format of the standard rows 
returned, please 
+see the DBI documentation.
 
 =for html <a 
href="http://search.cpan.org/~timb/DBI/DBI.pm#statistics_info";>DBI section on 
statistics_info</a>
 
+In addition, the following Postgres specific columns are returned:
+
+=over 4
+
+=item pg_expression
+
+Postgres allows indexes on functions and scalar expressions based on one or 
more columns. This field 
+will always be populated if an index, but the lack of an entry in the 
COLUMN_NAME should indicate 
+that this is an index expression.
+
+=back
+
+
 =head3 B<tables>
 
   @names = $dbh->tables( undef, $schema, $table, $type, \%attr );
diff --git a/t/03dbmethod.t b/t/03dbmethod.t
index e86d0de..48b5378 100644
--- a/t/03dbmethod.t
+++ b/t/03dbmethod.t
@@ -688,8 +688,10 @@ is ($sth, undef, $t);
                         'CONSTRAINT dbd_pg_test1_pk PRIMARY KEY (a))');
        $dbh->do("ALTER TABLE $table1 ADD CONSTRAINT dbd_pg_test1_uc1 UNIQUE 
(b)");
        $dbh->do("CREATE UNIQUE INDEX dbd_pg_test1_index_c ON $table1(c)");
+
        $dbh->do("CREATE TABLE $table2 (a INT, b INT, c INT, PRIMARY KEY(a,b), 
UNIQUE(b,c))");
-       $dbh->do("CREATE INDEX dbd_pg_test2_skipme ON $table2(c,(a+b))");
+       $dbh->do("CREATE INDEX dbd_pg_test2_expr ON $table2(c,(a+b))");
+
        $dbh->do("CREATE TABLE $table3 (a INT, b INT, c INT, PRIMARY KEY(a)) 
WITH OIDS");
        $dbh->do("CREATE UNIQUE INDEX dbd_pg_test3_index_b ON $table3(b)");
        $dbh->do("CREATE INDEX dbd_pg_test3_index_c ON $table3 USING hash(c)");
@@ -700,30 +702,32 @@ is ($sth, undef, $t);
 
 my $correct_stats = {
 one => [
-       [ undef, $schema, $table1, undef, undef, undef, 'table', undef, undef, 
undef, '0', '0', undef ],
-       [ undef, $schema, $table1, '0', undef, 'dbd_pg_test1_index_c', 'btree', 
 1, 'c', 'A', '0', '1', undef ],
-       [ undef, $schema, $table1, '0', undef, 'dbd_pg_test1_pk',      'btree', 
 1, 'a', 'A', '0', '1', undef ],
-       [ undef, $schema, $table1, '0', undef, 'dbd_pg_test1_uc1',     'btree', 
 1, 'b', 'A', '0', '1', undef ],
+       [ undef, $schema, $table1, undef, undef, undef, 'table', undef, undef, 
undef, '0', '0', undef, undef ],
+       [ undef, $schema, $table1, '0', undef, 'dbd_pg_test1_index_c', 'btree', 
 1, 'c', 'A', '0', '1', undef, 'c' ],
+       [ undef, $schema, $table1, '0', undef, 'dbd_pg_test1_pk',      'btree', 
 1, 'a', 'A', '0', '1', undef, 'a' ],
+       [ undef, $schema, $table1, '0', undef, 'dbd_pg_test1_uc1',     'btree', 
 1, 'b', 'A', '0', '1', undef, 'b' ],
        ],
        two => [
-       [ undef, $schema, $table2, undef, undef, undef, 'table', undef, undef, 
undef, '0', '0', undef ],
-       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_b_key',   'btree', 
 1, 'b', 'A', '0', '1', undef ],
-       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_b_key',   'btree', 
 2, 'c', 'A', '0', '1', undef ],
-       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_pkey',    'btree', 
 1, 'a', 'A', '0', '1', undef ],
-       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_pkey',    'btree', 
 2, 'b', 'A', '0', '1', undef ],
+       [ undef, $schema, $table2, undef, undef, undef, 'table', undef, undef, 
undef, '0', '0', undef, undef ],
+       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_b_key',   'btree', 
 1, 'b', 'A', '0', '1', undef, 'b' ],
+       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_b_key',   'btree', 
 2, 'c', 'A', '0', '1', undef, 'c' ],
+       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_pkey',    'btree', 
 1, 'a', 'A', '0', '1', undef, 'a' ],
+       [ undef, $schema, $table2, '0', undef, 'dbd_pg_test2_pkey',    'btree', 
 2, 'b', 'A', '0', '1', undef, 'b' ],
+       [ undef, $schema, $table2, '1', undef, 'dbd_pg_test2_expr',    'btree', 
 1, 'c', 'A', '0', '1', undef, 'c' ],
+       [ undef, $schema, $table2, '1', undef, 'dbd_pg_test2_expr',    'btree', 
 2, undef, 'A', '0', '1', undef, '(a + b)' ],
        ],
        three => [
-       [ undef, $schema, $table3, undef, undef, undef, 'table', undef, undef, 
undef, '0', '0', undef ],
-       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_index_b', 'btree', 
 1, 'b', 'A', '0', '1', undef ],
-       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pkey',    'btree', 
 1, 'a', 'A', '0', '1', undef ],
-       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pred',    'btree', 
 1, 'c', 'A', '0', '1', '((c > 0) AND (c < 45))' ],
-       [ undef, $schema, $table3, '1', undef, 'dbd_pg_test3_oid',     'btree', 
 1, 'oid', 'A', '0', '1', undef ],
-       [ undef, $schema, $table3, '1', undef, 'dbd_pg_test3_index_c', 
'hashed', 1, 'c', 'A', '0', '4', undef ],
+       [ undef, $schema, $table3, undef, undef, undef, 'table', undef, undef, 
undef, '0', '0', undef, undef ],
+       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_index_b', 'btree', 
 1, 'b', 'A', '0', '1', undef, 'b' ],
+       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pkey',    'btree', 
 1, 'a', 'A', '0', '1', undef, 'a' ],
+       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pred',    'btree', 
 1, 'c', 'A', '0', '1', '((c > 0) AND (c < 45))', 'c' ],
+       [ undef, $schema, $table3, '1', undef, 'dbd_pg_test3_oid',     'btree', 
 1, 'oid', 'A', '0', '1', undef, 'oid' ],
+       [ undef, $schema, $table3, '1', undef, 'dbd_pg_test3_index_c', 
'hashed', 1, 'c', 'A', '0', '4', undef, 'c' ],
 ],
        three_uo => [
-       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_index_b', 'btree', 
 1, 'b', 'A', '0', '1', undef ],
-       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pkey',    'btree', 
 1, 'a', 'A', '0', '1', undef ],
-       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pred',    'btree', 
 1, 'c', 'A', '0', '1', '((c > 0) AND (c < 45))' ],
+       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_index_b', 'btree', 
 1, 'b', 'A', '0', '1', undef, 'b' ],
+       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pkey',    'btree', 
 1, 'a', 'A', '0', '1', undef, 'a' ],
+       [ undef, $schema, $table3, '0', undef, 'dbd_pg_test3_pred',    'btree', 
 1, 'c', 'A', '0', '1', '((c > 0) AND (c < 45))', 'c' ],
        ],
 };
 
@@ -788,7 +792,6 @@ $dbh->do("DROP TABLE $table1");
 
 } ## end of statistics_info tests
 
-
 #
 # Test of the "foreign_key_info" database handle method
 #
-- 
1.8.4

Reply via email to