Re: [JDBC] JDBC MetaData getImportedKeys query - Mailing list pgsql-patches

From Barry Lind
Subject Re: [JDBC] JDBC MetaData getImportedKeys query
Date
Msg-id 3E23A08B.7090506@xythos.com
Whole thread Raw
In response to JDBC MetaData getImportedKeys query  (Kris Jurka <jurka@ejurka.com>)
List pgsql-patches
Patch applied.

I applied the basic one to the 7.3 branch and the one with the new
functionality for FK_NAME to head.

thanks,
--Barry

Kris Jurka wrote:
> For the DatabaseMetaData methods getImportedKeys, getExportedKeys, and
> getCrossReference a large query is used that triggered the genetic query
> optimizer which occasionally produced bad plans which made it look like
> the driver "hung" while it executed.  I've add some explicit JOIN
> statements so that it no longer enables the genetic optimizer and
> generates reasonable and consistent plans.
>
> I've attached two versions of the patch.  One which has an additional
> change to the value of the FK_NAME column.  Currently the returned value
> is the triggers arguments which look like
>
> "<unnamed>\000t2\000t1\000UNSPECIFIED\000a\000a\000"
>
> This was required for server versions < 7.3 when a user did not supply
> constraint names.  Every constraint was named "<unnamed>"
> .  7.3 has enforced unique constraint names per table so unnamed foreign
> keys will have different names "$1", "$2" and so on.  I've used logic
> along the lines of the following to preserve the unique names in the
> original scheme, but allow people who go to the trouble of naming their
> constraints to see them:
>
> if (triggerargs.startsWith("<unnamed>")) {
>     fkname = [the whole ugly trigger args name originally used];
> } else {
>     fkname = [the actual fk name];
> }
>
> Kris Jurka
>
>
> ------------------------------------------------------------------------
>
> Index: src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java
> ===================================================================
> RCS file:
/projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java,v
> retrieving revision 1.14
> diff -c -r1.14 AbstractJdbc1DatabaseMetaData.java
> *** src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2002/12/20 13:15:53    1.14
> --- src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2003/01/13 17:56:35
> ***************
> *** 2912,2973 ****
>           return connection.createStatement().executeQuery(sql);
>       }
>
> -     /*
> -      SELECT
> -             c.relname as primary,
> -             c2.relname as foreign,
> -             t.tgconstrname,
> -             ic.relname as fkeyname,
> -             af.attnum as fkeyseq,
> -             ipc.relname as pkeyname,
> -             ap.attnum as pkeyseq,
> -             t.tgdeferrable,
> -             t.tginitdeferred,
> -             t.tgnargs,t.tgargs,
> -             p1.proname as updaterule,
> -             p2.proname as deleterule
> -     FROM
> -             pg_trigger t,
> -             pg_trigger t1,
> -             pg_class c,
> -             pg_class c2,
> -             pg_class ic,
> -             pg_class ipc,
> -             pg_proc p1,
> -             pg_proc p2,
> -             pg_index if,
> -             pg_index ip,
> -             pg_attribute af,
> -             pg_attribute ap
> -     WHERE
> -             (t.tgrelid=c.oid
> -             AND t.tgisconstraint
> -             AND t.tgconstrrelid=c2.oid
> -             AND t.tgfoid=p1.oid
> -             and p1.proname like '%%upd')
> -
> -             and
> -             (t1.tgrelid=c.oid
> -             and t1.tgisconstraint
> -             and t1.tgconstrrelid=c2.oid
> -             AND t1.tgfoid=p2.oid
> -             and p2.proname like '%%del')
> -
> -             AND c2.relname='users'
> -
> -             AND
> -             (if.indrelid=c.oid
> -             AND if.indexrelid=ic.oid
> -             and ic.oid=af.attrelid
> -             AND if.indisprimary)
> -
> -             and
> -             (ip.indrelid=c2.oid
> -             and ip.indexrelid=ipc.oid
> -             and ipc.oid=ap.attrelid
> -             and ip.indisprimary)
> -
> -     */
>       /**
>        *
>        * @param catalog
> --- 2912,2917 ----
> ***************
> *** 3014,3068 ****
>            */
>
>           if (connection.haveMinimumServerVersion("7.3")) {
> !             select = "SELECT DISTINCT n.nspname as pnspname,n2.nspname as fnspname, ";
> !             from = " FROM pg_catalog.pg_namespace n, pg_catalog.pg_namespace n2, pg_catalog.pg_trigger t,
pg_catalog.pg_triggert1, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_class ic, pg_catalog.pg_proc p1,
pg_catalog.pg_procp2, pg_catalog.pg_index i, pg_catalog.pg_attribute a "; 
> !             where = " AND c.relnamespace = n.oid AND c2.relnamespace=n2.oid ";
>               if (primarySchema != null && !"".equals(primarySchema)) {
> !                 where += " AND n.nspname = '"+escapeQuotes(primarySchema)+"' ";
>               }
>               if (foreignSchema != null && !"".equals(foreignSchema)) {
>                   where += " AND n2.nspname = '"+escapeQuotes(foreignSchema)+"' ";
>               }
>           } else {
> !             select = "SELECT DISTINCT NULL::text as pnspname, NULL::text as fnspname, ";
> !             from = " FROM pg_trigger t, pg_trigger t1, pg_class c, pg_class c2, pg_class ic, pg_proc p1, pg_proc
p2,pg_index i, pg_attribute a "; 
>           }
>
>           String sql = select
> !             + "c.relname as prelname, "
>               + "c2.relname as frelname, "
> !             + "t.tgconstrname, "
>               + "a.attnum as keyseq, "
>               + "ic.relname as fkeyname, "
> !             + "t.tgdeferrable, "
> !             + "t.tginitdeferred, "
> !             + "t.tgnargs,t.tgargs, "
>               + "p1.proname as updaterule, "
>               + "p2.proname as deleterule "
>               + from
>               + "WHERE "
>               // isolate the update rule
> !             + "(t.tgrelid=c.oid "
> !             + "AND t.tgisconstraint "
> !             + "AND t.tgconstrrelid=c2.oid "
> !             + "AND t.tgfoid=p1.oid "
> !             + "and p1.proname like 'RI\\\\_FKey\\\\_%\\\\_upd') "
>
> !             + "and "
>               // isolate the delete rule
> !             + "(t1.tgrelid=c.oid "
> !             + "and t1.tgisconstraint "
> !             + "and t1.tgconstrrelid=c2.oid "
> !             + "AND t1.tgfoid=p2.oid "
> !             + "and p2.proname like 'RI\\\\_FKey\\\\_%\\\\_del') "
> !             + "AND i.indrelid=c.oid "
> !             + "AND i.indexrelid=ic.oid "
> !             + "AND ic.oid=a.attrelid "
>               + "AND i.indisprimary "
>               + where;
>
>           if (primaryTable != null) {
> !             sql += "AND c.relname='" + escapeQuotes(primaryTable) + "' ";
>           }
>           if (foreignTable != null) {
>               sql += "AND c2.relname='" + escapeQuotes(foreignTable) + "' ";
> --- 2958,3025 ----
>            */
>
>           if (connection.haveMinimumServerVersion("7.3")) {
> !             select = "SELECT n1.nspname as pnspname,n2.nspname as fnspname, ";
> !             from = " FROM pg_catalog.pg_namespace n1 "+
> !                 " JOIN pg_catalog.pg_class c1 ON (c1.relnamespace = n1.oid) "+
> !                 " JOIN pg_catalog.pg_index i ON (c1.oid=i.indrelid) "+
> !                 " JOIN pg_catalog.pg_class ic ON (i.indexrelid=ic.oid) "+
> !                 " JOIN pg_catalog.pg_attribute a ON (ic.oid=a.attrelid), "+
> !                 " pg_catalog.pg_namespace n2 "+
> !                 " JOIN pg_catalog.pg_class c2 ON (c2.relnamespace=n2.oid), "+
> !                 " pg_catalog.pg_trigger t1 "+
> !                 " JOIN pg_catalog.pg_proc p1 ON (t1.tgfoid=p1.oid), "+
> !                 " pg_catalog.pg_trigger t2 "+
> !                 " JOIN pg_catalog.pg_proc p2 ON (t2.tgfoid=p2.oid) ";
>               if (primarySchema != null && !"".equals(primarySchema)) {
> !                 where += " AND n1.nspname = '"+escapeQuotes(primarySchema)+"' ";
>               }
>               if (foreignSchema != null && !"".equals(foreignSchema)) {
>                   where += " AND n2.nspname = '"+escapeQuotes(foreignSchema)+"' ";
>               }
>           } else {
> !             select = "SELECT NULL::text as pnspname, NULL::text as fnspname, ";
> !             from = " FROM pg_class c1 "+
> !                 " JOIN pg_index i ON (c1.oid=i.indrelid) "+
> !                 " JOIN pg_class ic ON (i.indexrelid=ic.oid) "+
> !                 " JOIN pg_attribute a ON (ic.oid=a.attrelid), "+
> !                 " pg_class c2, "+
> !                 " pg_trigger t1 "+
> !                 " JOIN pg_proc p1 ON (t1.tgfoid=p1.oid), "+
> !                 " pg_trigger t2 "+
> !                 " JOIN pg_proc p2 ON (t2.tgfoid=p2.oid) ";
>           }
>
>           String sql = select
> !             + "c1.relname as prelname, "
>               + "c2.relname as frelname, "
> !             + "t1.tgconstrname, "
>               + "a.attnum as keyseq, "
>               + "ic.relname as fkeyname, "
> !             + "t1.tgdeferrable, "
> !             + "t1.tginitdeferred, "
> !             + "t1.tgnargs,t1.tgargs, "
>               + "p1.proname as updaterule, "
>               + "p2.proname as deleterule "
>               + from
>               + "WHERE "
>               // isolate the update rule
> !             + "(t1.tgrelid=c1.oid "
> !             + "AND t1.tgisconstraint "
> !             + "AND t1.tgconstrrelid=c2.oid "
> !             + "AND p1.proname LIKE 'RI\\\\_FKey\\\\_%\\\\_upd') "
>
> !             + "AND "
>               // isolate the delete rule
> !             + "(t2.tgrelid=c1.oid "
> !             + "AND t2.tgisconstraint "
> !             + "AND t2.tgconstrrelid=c2.oid "
> !             + "AND p2.proname LIKE 'RI\\\\_FKey\\\\_%\\\\_del') "
> !
>               + "AND i.indisprimary "
>               + where;
>
>           if (primaryTable != null) {
> !             sql += "AND c1.relname='" + escapeQuotes(primaryTable) + "' ";
>           }
>           if (foreignTable != null) {
>               sql += "AND c2.relname='" + escapeQuotes(foreignTable) + "' ";
> ***************
> *** 3076,3083 ****
> --- 3033,3046 ----
>           // since when getting crossreference, primaryTable will be defined
>
>           if (primaryTable != null) {
> +             if (connection.haveMinimumServerVersion("7.3")) {
> +                 sql += "fnspname,";
> +             }
>               sql += "frelname";
>           } else {
> +             if (connection.haveMinimumServerVersion("7.3")) {
> +                 sql += "pnspname,";
> +             }
>               sql += "prelname";
>           }
>
>
>
> ------------------------------------------------------------------------
>
> Index: src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java
> ===================================================================
> RCS file:
/projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java,v
> retrieving revision 1.14
> diff -c -r1.14 AbstractJdbc1DatabaseMetaData.java
> *** src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2002/12/20 13:15:53    1.14
> --- src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2003/01/13 18:55:23
> ***************
> *** 2912,2973 ****
>           return connection.createStatement().executeQuery(sql);
>       }
>
> -     /*
> -      SELECT
> -             c.relname as primary,
> -             c2.relname as foreign,
> -             t.tgconstrname,
> -             ic.relname as fkeyname,
> -             af.attnum as fkeyseq,
> -             ipc.relname as pkeyname,
> -             ap.attnum as pkeyseq,
> -             t.tgdeferrable,
> -             t.tginitdeferred,
> -             t.tgnargs,t.tgargs,
> -             p1.proname as updaterule,
> -             p2.proname as deleterule
> -     FROM
> -             pg_trigger t,
> -             pg_trigger t1,
> -             pg_class c,
> -             pg_class c2,
> -             pg_class ic,
> -             pg_class ipc,
> -             pg_proc p1,
> -             pg_proc p2,
> -             pg_index if,
> -             pg_index ip,
> -             pg_attribute af,
> -             pg_attribute ap
> -     WHERE
> -             (t.tgrelid=c.oid
> -             AND t.tgisconstraint
> -             AND t.tgconstrrelid=c2.oid
> -             AND t.tgfoid=p1.oid
> -             and p1.proname like '%%upd')
> -
> -             and
> -             (t1.tgrelid=c.oid
> -             and t1.tgisconstraint
> -             and t1.tgconstrrelid=c2.oid
> -             AND t1.tgfoid=p2.oid
> -             and p2.proname like '%%del')
> -
> -             AND c2.relname='users'
> -
> -             AND
> -             (if.indrelid=c.oid
> -             AND if.indexrelid=ic.oid
> -             and ic.oid=af.attrelid
> -             AND if.indisprimary)
> -
> -             and
> -             (ip.indrelid=c2.oid
> -             and ip.indexrelid=ipc.oid
> -             and ipc.oid=ap.attrelid
> -             and ip.indisprimary)
> -
> -     */
>       /**
>        *
>        * @param catalog
> --- 2912,2917 ----
> ***************
> *** 3014,3068 ****
>            */
>
>           if (connection.haveMinimumServerVersion("7.3")) {
> !             select = "SELECT DISTINCT n.nspname as pnspname,n2.nspname as fnspname, ";
> !             from = " FROM pg_catalog.pg_namespace n, pg_catalog.pg_namespace n2, pg_catalog.pg_trigger t,
pg_catalog.pg_triggert1, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_class ic, pg_catalog.pg_proc p1,
pg_catalog.pg_procp2, pg_catalog.pg_index i, pg_catalog.pg_attribute a "; 
> !             where = " AND c.relnamespace = n.oid AND c2.relnamespace=n2.oid ";
>               if (primarySchema != null && !"".equals(primarySchema)) {
> !                 where += " AND n.nspname = '"+escapeQuotes(primarySchema)+"' ";
>               }
>               if (foreignSchema != null && !"".equals(foreignSchema)) {
>                   where += " AND n2.nspname = '"+escapeQuotes(foreignSchema)+"' ";
>               }
>           } else {
> !             select = "SELECT DISTINCT NULL::text as pnspname, NULL::text as fnspname, ";
> !             from = " FROM pg_trigger t, pg_trigger t1, pg_class c, pg_class c2, pg_class ic, pg_proc p1, pg_proc
p2,pg_index i, pg_attribute a "; 
>           }
>
>           String sql = select
> !             + "c.relname as prelname, "
>               + "c2.relname as frelname, "
> !             + "t.tgconstrname, "
>               + "a.attnum as keyseq, "
>               + "ic.relname as fkeyname, "
> !             + "t.tgdeferrable, "
> !             + "t.tginitdeferred, "
> !             + "t.tgnargs,t.tgargs, "
>               + "p1.proname as updaterule, "
>               + "p2.proname as deleterule "
>               + from
>               + "WHERE "
>               // isolate the update rule
> !             + "(t.tgrelid=c.oid "
> !             + "AND t.tgisconstraint "
> !             + "AND t.tgconstrrelid=c2.oid "
> !             + "AND t.tgfoid=p1.oid "
> !             + "and p1.proname like 'RI\\\\_FKey\\\\_%\\\\_upd') "
>
> !             + "and "
>               // isolate the delete rule
> !             + "(t1.tgrelid=c.oid "
> !             + "and t1.tgisconstraint "
> !             + "and t1.tgconstrrelid=c2.oid "
> !             + "AND t1.tgfoid=p2.oid "
> !             + "and p2.proname like 'RI\\\\_FKey\\\\_%\\\\_del') "
> !             + "AND i.indrelid=c.oid "
> !             + "AND i.indexrelid=ic.oid "
> !             + "AND ic.oid=a.attrelid "
>               + "AND i.indisprimary "
>               + where;
>
>           if (primaryTable != null) {
> !             sql += "AND c.relname='" + escapeQuotes(primaryTable) + "' ";
>           }
>           if (foreignTable != null) {
>               sql += "AND c2.relname='" + escapeQuotes(foreignTable) + "' ";
> --- 2958,3025 ----
>            */
>
>           if (connection.haveMinimumServerVersion("7.3")) {
> !             select = "SELECT n1.nspname as pnspname,n2.nspname as fnspname, ";
> !             from = " FROM pg_catalog.pg_namespace n1 "+
> !                 " JOIN pg_catalog.pg_class c1 ON (c1.relnamespace = n1.oid) "+
> !                 " JOIN pg_catalog.pg_index i ON (c1.oid=i.indrelid) "+
> !                 " JOIN pg_catalog.pg_class ic ON (i.indexrelid=ic.oid) "+
> !                 " JOIN pg_catalog.pg_attribute a ON (ic.oid=a.attrelid), "+
> !                 " pg_catalog.pg_namespace n2 "+
> !                 " JOIN pg_catalog.pg_class c2 ON (c2.relnamespace=n2.oid), "+
> !                 " pg_catalog.pg_trigger t1 "+
> !                 " JOIN pg_catalog.pg_proc p1 ON (t1.tgfoid=p1.oid), "+
> !                 " pg_catalog.pg_trigger t2 "+
> !                 " JOIN pg_catalog.pg_proc p2 ON (t2.tgfoid=p2.oid) ";
>               if (primarySchema != null && !"".equals(primarySchema)) {
> !                 where += " AND n1.nspname = '"+escapeQuotes(primarySchema)+"' ";
>               }
>               if (foreignSchema != null && !"".equals(foreignSchema)) {
>                   where += " AND n2.nspname = '"+escapeQuotes(foreignSchema)+"' ";
>               }
>           } else {
> !             select = "SELECT NULL::text as pnspname, NULL::text as fnspname, ";
> !             from = " FROM pg_class c1 "+
> !                 " JOIN pg_index i ON (c1.oid=i.indrelid) "+
> !                 " JOIN pg_class ic ON (i.indexrelid=ic.oid) "+
> !                 " JOIN pg_attribute a ON (ic.oid=a.attrelid), "+
> !                 " pg_class c2, "+
> !                 " pg_trigger t1 "+
> !                 " JOIN pg_proc p1 ON (t1.tgfoid=p1.oid), "+
> !                 " pg_trigger t2 "+
> !                 " JOIN pg_proc p2 ON (t2.tgfoid=p2.oid) ";
>           }
>
>           String sql = select
> !             + "c1.relname as prelname, "
>               + "c2.relname as frelname, "
> !             + "t1.tgconstrname, "
>               + "a.attnum as keyseq, "
>               + "ic.relname as fkeyname, "
> !             + "t1.tgdeferrable, "
> !             + "t1.tginitdeferred, "
> !             + "t1.tgnargs,t1.tgargs, "
>               + "p1.proname as updaterule, "
>               + "p2.proname as deleterule "
>               + from
>               + "WHERE "
>               // isolate the update rule
> !             + "(t1.tgrelid=c1.oid "
> !             + "AND t1.tgisconstraint "
> !             + "AND t1.tgconstrrelid=c2.oid "
> !             + "AND p1.proname LIKE 'RI\\\\_FKey\\\\_%\\\\_upd') "
>
> !             + "AND "
>               // isolate the delete rule
> !             + "(t2.tgrelid=c1.oid "
> !             + "AND t2.tgisconstraint "
> !             + "AND t2.tgconstrrelid=c2.oid "
> !             + "AND p2.proname LIKE 'RI\\\\_FKey\\\\_%\\\\_del') "
> !
>               + "AND i.indisprimary "
>               + where;
>
>           if (primaryTable != null) {
> !             sql += "AND c1.relname='" + escapeQuotes(primaryTable) + "' ";
>           }
>           if (foreignTable != null) {
>               sql += "AND c2.relname='" + escapeQuotes(foreignTable) + "' ";
> ***************
> *** 3076,3083 ****
> --- 3033,3046 ----
>           // since when getting crossreference, primaryTable will be defined
>
>           if (primaryTable != null) {
> +             if (connection.haveMinimumServerVersion("7.3")) {
> +                 sql += "fnspname,";
> +             }
>               sql += "frelname";
>           } else {
> +             if (connection.haveMinimumServerVersion("7.3")) {
> +                 sql += "pnspname,";
> +             }
>               sql += "prelname";
>           }
>
> ***************
> *** 3160,3165 ****
> --- 3123,3129 ----
>               // Parse the tgargs data
>               String fkeyColumn = "";
>               String pkeyColumn = "";
> +             String fkName = "";
>               // Note, I am guessing at most of this, but it should be close
>               // if not, please correct
>               // the keys are in pairs and start after the first four arguments
> ***************
> *** 3172,3180 ****
>               // we are primarily interested in the column names which are the last items in the string
>
>               StringTokenizer st = new StringTokenizer(targs, "\\000");
>
>               int advance = 4 + (keySequence - 1) * 2;
> !             for ( int i = 0; st.hasMoreTokens() && i < advance ; i++ )
>                   st.nextToken(); // advance to the key column of interest
>
>               if ( st.hasMoreTokens() )
> --- 3136,3151 ----
>               // we are primarily interested in the column names which are the last items in the string
>
>               StringTokenizer st = new StringTokenizer(targs, "\\000");
> +             if (st.hasMoreTokens()) {
> +                 fkName = st.nextToken();
> +             }
> +
> +             if (fkName.startsWith("<unnamed>")) {
> +                 fkName = targs;
> +             }
>
>               int advance = 4 + (keySequence - 1) * 2;
> !             for ( int i = 1; st.hasMoreTokens() && i < advance ; i++ )
>                   st.nextToken(); // advance to the key column of interest
>
>               if ( st.hasMoreTokens() )
> ***************
> *** 3190,3196 ****
>               tuple[7] = fkeyColumn.getBytes(); //FKCOLUMN_NAME
>
>               tuple[8] = rs.getBytes(6); //KEY_SEQ
> !             tuple[11] = targs.getBytes(); //FK_NAME this will give us a unique name for the foreign key
>               tuple[12] = rs.getBytes(7); //PK_NAME
>
>               // DEFERRABILITY
> --- 3161,3167 ----
>               tuple[7] = fkeyColumn.getBytes(); //FKCOLUMN_NAME
>
>               tuple[8] = rs.getBytes(6); //KEY_SEQ
> !             tuple[11] = fkName.getBytes(); //FK_NAME this will give us a unique name for the foreign key
>               tuple[12] = rs.getBytes(7); //PK_NAME
>
>               // DEFERRABILITY
>
>
> ------------------------------------------------------------------------
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/users-lounge/docs/faq.html



pgsql-patches by date:

Previous
From: "Christopher Kings-Lynne"
Date:
Subject: Re: Add UNIQUE and PRIMARY KEY to pg_get_constraintdef
Next
From: Peter Eisentraut
Date:
Subject: Re: Docs for service file