OSDN Git Service

fixed getImported/ExportedKeys to be simpler, and return the correct number of keys
authorDave Cramer <davec@fastcrypt.com>
Wed, 5 Jun 2002 19:12:01 +0000 (19:12 +0000)
committerDave Cramer <davec@fastcrypt.com>
Wed, 5 Jun 2002 19:12:01 +0000 (19:12 +0000)
src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java
src/interfaces/jdbc/org/postgresql/test/jdbc2/DatabaseMetaDataTest.java

index e819d4b..d8327f1 100644 (file)
@@ -15,7 +15,7 @@ import org.postgresql.util.PSQLException;
 /*
  * This class provides information about the database as a whole.
  *
- * $Id: DatabaseMetaData.java,v 1.52 2002/04/16 13:28:44 davec Exp $
+ * $Id: DatabaseMetaData.java,v 1.53 2002/06/05 19:12:01 davec Exp $
  *
  * <p>Many of the methods here return lists of information in ResultSets.  You
  * can use the normal ResultSet methods such as getString and getInt to
@@ -760,8 +760,10 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
         */
        public boolean supportsANSI92EntryLevelSQL() throws SQLException
        {
-               Driver.debug("supportsANSI92EntryLevelSQL false ");
-               return false;
+               boolean schemas = connection.haveMinimumServerVersion("7.3");
+               Driver.debug("supportsANSI92EntryLevelSQL " + schemas);
+               return schemas;
+
        }
 
        /*
@@ -941,8 +943,10 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
         */
        public boolean supportsSchemasInTableDefinitions() throws SQLException
        {
-               Driver.debug("supportsSchemasInTableDefinitions false");
-               return false;
+               boolean schemas = connection.haveMinimumServerVersion("7.3");
+
+               Driver.debug("supportsSchemasInTableDefinitions " + schemas);
+               return schemas;
        }
 
        /*
@@ -2410,6 +2414,71 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
                                " ORDER BY table_name, pk_name, key_seq"
                                                                                                                );
        }
+/*
+ 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
+ * @param schema
+ * @param primaryTable if provided will get the keys exported by this table
+ * @param foreignTable if provided will get the keys imported by this table
+ * @return ResultSet
+ * @throws SQLException
+ */
 
        private java.sql.ResultSet getImportedExportedKeys(String catalog, String schema, String primaryTable, String foreignTable) throws SQLException
        {
@@ -2430,120 +2499,203 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
                f[12] = new Field(connection, "PK_NAME", iVarcharOid, 32);
                f[13] = new Field(connection, "DEFERRABILITY", iInt2Oid, 2);
 
-               java.sql.ResultSet rs = connection.ExecSQL("SELECT c.relname,c2.relname,"
-                                                               + "t.tgconstrname,ic.relname,"
-                                                               + "t.tgdeferrable,t.tginitdeferred,"
-                                                               + "t.tgnargs,t.tgargs,p.proname "
-                                                               + "FROM pg_trigger t,pg_class c,pg_class c2,"
-                                                               + "pg_class ic,pg_proc p, pg_index i "
-                                                               + "WHERE t.tgrelid=c.oid AND t.tgconstrrelid=c2.oid "
-                                                               + "AND t.tgfoid=p.oid AND tgisconstraint "
-                                                               + ((primaryTable != null) ? "AND c.relname='" + primaryTable + "' " : "")
-                                                               + ((foreignTable != null) ? "AND c2.relname='" + foreignTable + "' " : "")
-                                                               + "AND i.indrelid=c.oid "
-                                                               + "AND i.indexrelid=ic.oid AND i.indisprimary "
-                                                               + "ORDER BY c.relname,c2.relname"
-                                                                                                 );
+               java.sql.ResultSet rs = connection.ExecSQL(
+                "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 "
+                  + "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 "
+          + "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 '%%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 '%%del') "
+
+                  // if we are looking for exported keys then primary table will be used
+                                                                 + ((primaryTable != null) ? "AND c.relname='" + primaryTable + "' " : "")
+
+                  // if we are looking for imported keys then the foreign table will be used
+                                                                 + ((foreignTable != null) ? "AND c2.relname='" + foreignTable + "' " : "")
+                  + "AND i.indrelid=c.oid "
+                  + "AND i.indexrelid=ic.oid "
+                  + "AND ic.oid=a.attrelid "
+                  + "AND i.indisprimary "
+          + "ORDER BY "
+
+                   // orderby is as follows getExported, orders by FKTABLE,
+                   // getImported orders by PKTABLE
+                   // getCrossReference orders by FKTABLE, so this should work for both,
+                   // since when getting crossreference, primaryTable will be defined
+
+                  +   (primaryTable != null ? "frelname" : "prelname") + ",keyseq");
+
+// returns the following columns
+// and some example data with a table defined as follows
+
+// create table people ( id int primary key);
+// create table policy ( id int primary key);
+// create table users  ( id int primary key, people_id int references people(id), policy_id int references policy(id))
+
+// prelname | frelname | tgconstrname | keyseq | fkeyName    | tgdeferrable | tginitdeferred
+//    1     |    2     |      3       |    4   |     5       |       6      |    7
+
+//  people  | users    | <unnamed>    |    1   | people_pkey |       f      |    f
+
+// | tgnargs |                        tgargs                                      | updaterule           | deleterule
+// |    8    |                          9                                         |    10                |    11
+// |    6    | <unnamed>\000users\000people\000UNSPECIFIED\000people_id\000id\000 | RI_FKey_noaction_upd | RI_FKey_noaction_del
+
                Vector tuples = new Vector();
-               short seq = 0;
-               if (rs.next())
-               {
-                       boolean hasMore;
-                       do
-                       {
-                               byte tuple[][] = new byte[14][0];
-                               for (int k = 0;k < 14;k++)
-                                       tuple[k] = null;
 
-                               String fKeyName = rs.getString(3);
-                               boolean foundRule = false;
-                               do
-                               {
-                                       String proname = rs.getString(9);
-                                       if (proname != null && proname.startsWith("RI_FKey_"))
-                                       {
-                                               int col = -1;
-                                               if (proname.endsWith("_upd"))
-                                                       col = 9; // UPDATE_RULE
-                                               else if (proname.endsWith("_del"))
-                                                       col = 10; // DELETE_RULE
-                                               if (col > -1)
-                                               {
-                                                       String rule = proname.substring(8, proname.length() - 4);
-                                                       int action = importedKeyNoAction;
-                                                       if ("cascade".equals(rule))
-                                                               action = importedKeyCascade;
-                                                       else if ("setnull".equals(rule))
-                                                               action = importedKeySetNull;
-                                                       else if ("setdefault".equals(rule))
-                                                               action = importedKeySetDefault;
-                                                       tuple[col] = Integer.toString(action).getBytes();
-
-                                                       if (!foundRule)
-                                                       {
-                                                               tuple[2] = rs.getBytes(1); //PKTABLE_NAME
-                                                               tuple[6] = rs.getBytes(2); //FKTABLE_NAME
-
-                                                               // Parse the tgargs data
-                                                               StringBuffer fkeyColumns = new StringBuffer();
-                                                               StringBuffer pkeyColumns = new StringBuffer();
-                                                               int numColumns = (rs.getInt(7) >> 1) - 2;
-                                                               String s = rs.getString(8);
-                                                               int pos = s.lastIndexOf("\\000");
-                                                               for (int c = 0;c < numColumns;c++)
-                                                               {
-                                                                       if (pos > -1)
-                                                                       {
-                                                                               int pos2 = s.lastIndexOf("\\000", pos - 1);
-                                                                               if (pos2 > -1)
-                                                                               {
-                                                                                       if (pkeyColumns.length() > 0)
-                                                                                               pkeyColumns.insert(0, ',');
-                                                                                       pkeyColumns.insert(0, s.substring(pos2 + 4, pos)); //PKCOLUMN_NAME
-                                                                                       pos = s.lastIndexOf("\\000", pos2 - 1);
-                                                                                       if (pos > -1)
-                                                                                       {
-                                                                                               if (fkeyColumns.length() > 0)
-                                                                                                   fkeyColumns.insert(0, ',');
-                                                                                               fkeyColumns.insert(0, s.substring(pos + 4, pos2)); //FKCOLUMN_NAME
-                                                                                       }
-                                                                               }
-                                                                       }
-                                                               }
-                                                               tuple[3] = pkeyColumns.toString().getBytes(); //PKCOLUMN_NAME
-                                                               tuple[7] = fkeyColumns.toString().getBytes(); //FKCOLUMN_NAME
-
-                                                               tuple[8] = Integer.toString(seq++).getBytes(); //KEY_SEQ
-                                                               tuple[11] = fKeyName.getBytes(); //FK_NAME
-                                                               tuple[12] = rs.getBytes(4); //PK_NAME
-
-                                                               // DEFERRABILITY
-                                                               int deferrability = importedKeyNotDeferrable;
-                                                               boolean deferrable = rs.getBoolean(5);
-                                                               boolean initiallyDeferred = rs.getBoolean(6);
-                                                               if (deferrable)
-                                                               {
-                                                                       if (initiallyDeferred)
-                                                                               deferrability = importedKeyInitiallyDeferred;
-                                                                       else
-                                                                               deferrability = importedKeyInitiallyImmediate;
-                                                               }
-                                                               tuple[13] = Integer.toString(deferrability).getBytes();
-
-                                                               foundRule = true;
-                                                       }
-                                               }
-                                       }
-                               }
-                               while ((hasMore = rs.next()) && fKeyName.equals(rs.getString(3)));
 
-                               if(foundRule) tuples.addElement(tuple);
+               while ( rs.next() )
+               {
+                       byte tuple[][] = new byte[14][];
 
-                       }
-                       while (hasMore);
-               }
+      tuple[2] = rs.getBytes(1); //PKTABLE_NAME
+      tuple[6] = rs.getBytes(2); //FKTABLE_NAME
+      String fKeyName = rs.getString(3);
+      String updateRule = rs.getString(10);
 
-               return new ResultSet(connection, f, tuples, "OK", 1);
+      if (updateRule != null )
+      {
+        // Rules look like this RI_FKey_noaction_del so we want to pull out the part between the 'Key_' and the last '_' s
+
+        String rule = updateRule.substring(8, updateRule.length() - 4);
+
+        int action = importedKeyNoAction;
+
+        if ( rule == null || "noaction".equals(rule) )
+           action = importedKeyNoAction;
+        if ("cascade".equals(rule))
+          action = importedKeyCascade;
+        else if ("setnull".equals(rule))
+          action = importedKeySetNull;
+        else if ("setdefault".equals(rule))
+          action = importedKeySetDefault;
+        else if ("restrict".equals(rule))
+          action = importedKeyRestrict;
+
+        tuple[9] = Integer.toString(action).getBytes();
+
+      }
+
+      String deleteRule = rs.getString(11);
+
+      if ( deleteRule != null )
+      {
+
+        String rule = updateRule.substring(8, updateRule.length() - 4);
+
+        int action = importedKeyNoAction;
+        if ("cascade".equals(rule))
+          action = importedKeyCascade;
+        else if ("setnull".equals(rule))
+          action = importedKeySetNull;
+        else if ("setdefault".equals(rule))
+          action = importedKeySetDefault;
+        tuple[10] = Integer.toString(action).getBytes();
+      }
+
+
+      // Parse the tgargs data
+      StringBuffer fkeyColumns = new StringBuffer();
+      StringBuffer pkeyColumns = new StringBuffer();
+
+
+      // 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
+      // the arguments are seperated by \000
+
+      int numColumns = (rs.getInt(8) >> 1) - 2;
+
+
+
+      // get the args
+      String targs = rs.getString(9);
+
+      // start parsing from the end
+      int pos = targs.lastIndexOf("\\000");
+
+      for (int c = 0;c < numColumns;c++)
+      {
+        // this should never be, since we should never get to the beginning of the string
+        // as the number of columns should override this, but it is a safe test
+        if (pos > -1)
+        {
+          int pos2 = targs.lastIndexOf("\\000", pos - 1);
+          if (pos2 > -1)
+          {
+            // seperate the pkColumns by ',' s
+            if (pkeyColumns.length() > 0)
+                    pkeyColumns.insert(0, ',');
+
+            // extract the column name out 4 characters ahead essentially removing the /000
+            pkeyColumns.insert(0, targs.substring(pos2 + 4, pos)); //PKCOLUMN_NAME
+
+            // now find the associated fkColumn
+            pos = targs.lastIndexOf("\\000", pos2 - 1);
+            if (pos > -1)
+            {
+              if (fkeyColumns.length() > 0)
+                  fkeyColumns.insert(0, ',');
+              fkeyColumns.insert(0, targs.substring(pos + 4, pos2)); //FKCOLUMN_NAME
+            }
+          }
+        }
+      }
+
+      tuple[3] = pkeyColumns.toString().getBytes(); //PKCOLUMN_NAME
+      tuple[7] = fkeyColumns.toString().getBytes(); //FKCOLUMN_NAME
+
+      tuple[8] =  rs.getBytes(4); //KEY_SEQ
+      tuple[11] = rs.getBytes(5); //FK_NAME
+      tuple[12] = rs.getBytes(3); //PK_NAME
+
+      // DEFERRABILITY
+      int deferrability = importedKeyNotDeferrable;
+      boolean deferrable = rs.getBoolean(6);
+      boolean initiallyDeferred = rs.getBoolean(7);
+      if (deferrable)
+      {
+        if (initiallyDeferred)
+                deferrability = importedKeyInitiallyDeferred;
+        else
+                deferrability = importedKeyInitiallyImmediate;
+      }
+      tuple[13] = Integer.toString(deferrability).getBytes();
+
+      tuples.addElement(tuple);
+    }
+
+    return new ResultSet(connection, f, tuples, "OK", 1);
        }
 
        /*
index 1050227..e6acfc0 100644 (file)
@@ -9,7 +9,7 @@ import java.sql.*;
  *
  * PS: Do you know how difficult it is to type on a train? ;-)
  *
- * $Id: DatabaseMetaDataTest.java,v 1.7 2002/05/30 16:39:26 davec Exp $
+ * $Id: DatabaseMetaDataTest.java,v 1.8 2002/06/05 19:12:01 davec Exp $
  */
 
 public class DatabaseMetaDataTest extends TestCase
@@ -235,6 +235,7 @@ public class DatabaseMetaDataTest extends TestCase
                  Connection con1 = JDBC2Tests.openDB();
                  JDBC2Tests.createTable( con1, "people", "id int4 primary key, name text" );
                  JDBC2Tests.createTable( con1, "policy", "id int4 primary key, name text" );
+
                  JDBC2Tests.createTable( con1, "users", "id int4 primary key, people_id int4, policy_id int4,"+
                                     "CONSTRAINT people FOREIGN KEY (people_id) references people(id),"+
                                     "constraint policy FOREIGN KEY (policy_id) references policy(id)" );
@@ -261,9 +262,10 @@ public class DatabaseMetaDataTest extends TestCase
          assertTrue( fkColumnName.equals( "people_id" ) || fkColumnName.equals( "policy_id" ) ) ;
 
          String fkName = rs.getString( "FK_NAME" );
-         assertTrue( fkName.equals( "people") || fkName.equals( "policy" ) );
+         assertTrue( fkName.equals( "people_pkey") || fkName.equals( "policy_pkey" ) );
 
          String pkName = rs.getString( "PK_NAME" );
+//         assertTrue( pkName.equals("users") );
 
       }
 
@@ -280,7 +282,7 @@ public class DatabaseMetaDataTest extends TestCase
       assertTrue( rs.getString( "FKTABLE_NAME" ).equals( "users" ) );
       assertTrue( rs.getString( "FKCOLUMN_NAME" ).equals( "people_id" ) );
 
-      assertTrue( rs.getString( "FK_NAME" ).equals( "people" ) );
+      assertTrue( rs.getString( "FK_NAME" ).equals( "people_pkey" ) );
 
 
       JDBC2Tests.dropTable( con1, "users" );