/*
* 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
*/
public boolean supportsANSI92EntryLevelSQL() throws SQLException
{
- Driver.debug("supportsANSI92EntryLevelSQL false ");
- return false;
+ boolean schemas = connection.haveMinimumServerVersion("7.3");
+ Driver.debug("supportsANSI92EntryLevelSQL " + schemas);
+ return schemas;
+
}
/*
*/
public boolean supportsSchemasInTableDefinitions() throws SQLException
{
- Driver.debug("supportsSchemasInTableDefinitions false");
- return false;
+ boolean schemas = connection.haveMinimumServerVersion("7.3");
+
+ Driver.debug("supportsSchemasInTableDefinitions " + schemas);
+ return schemas;
}
/*
" 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
{
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);
}
/*