JDBCDatabaseMetaData.java revision 17c83b1a74c906c9a36257a3a99cd1e3730b002e
1package SQLite.JDBC2z;
2
3import java.sql.*;
4import java.util.Hashtable;
5
6public class JDBCDatabaseMetaData implements DatabaseMetaData {
7
8    private JDBCConnection conn;
9
10    public JDBCDatabaseMetaData(JDBCConnection conn) {
11	this.conn = conn;
12    }
13
14    public boolean allProceduresAreCallable() throws SQLException {
15	return false;
16    }
17
18    public boolean allTablesAreSelectable() throws SQLException {
19	return true;
20    }
21
22    public String getURL() throws SQLException {
23	return conn.url;
24    }
25
26    public String getUserName() throws SQLException {
27	return "";
28    }
29
30    public boolean isReadOnly() throws SQLException {
31	return false;
32    }
33
34    public boolean nullsAreSortedHigh() throws SQLException {
35	return false;
36    }
37
38    public boolean nullsAreSortedLow() throws SQLException {
39	return false;
40    }
41
42    public boolean nullsAreSortedAtStart() throws SQLException {
43	return false;
44    }
45
46    public boolean nullsAreSortedAtEnd() throws SQLException {
47	return false;
48    }
49
50    public String getDatabaseProductName() throws SQLException {
51	return "SQLite";
52    }
53
54    public String getDatabaseProductVersion() throws SQLException {
55	return SQLite.Database.version();
56    }
57
58    public String getDriverName() throws SQLException {
59	return "SQLite/JDBC";
60    }
61
62    public String getDriverVersion() throws SQLException {
63	return "" + SQLite.JDBCDriver.MAJORVERSION + "." +
64	    SQLite.Constants.drv_minor;
65    }
66
67    public int getDriverMajorVersion() {
68	return SQLite.JDBCDriver.MAJORVERSION;
69    }
70
71    public int getDriverMinorVersion() {
72	return SQLite.Constants.drv_minor;
73    }
74
75    public boolean usesLocalFiles() throws SQLException {
76	return true;
77    }
78
79    public boolean usesLocalFilePerTable() throws SQLException {
80	return false;
81    }
82
83    public boolean supportsMixedCaseIdentifiers() throws SQLException {
84	return false;
85    }
86
87    public boolean storesUpperCaseIdentifiers() throws SQLException {
88	return false;
89    }
90
91    public boolean storesLowerCaseIdentifiers() throws SQLException {
92	return false;
93    }
94
95    public boolean storesMixedCaseIdentifiers() throws SQLException {
96	return true;
97    }
98
99    public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
100	return false;
101    }
102
103    public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
104	return false;
105    }
106
107    public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
108	return false;
109    }
110
111    public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
112	return true;
113    }
114
115    public String getIdentifierQuoteString() throws SQLException {
116	return "\"";
117    }
118
119    public String getSQLKeywords() throws SQLException {
120	return "SELECT,UPDATE,CREATE,TABLE,VIEW,DELETE,FROM,WHERE" +
121	    ",COMMIT,ROLLBACK,TRIGGER";
122    }
123
124    public String getNumericFunctions() throws SQLException {
125	return "";
126    }
127
128    public String getStringFunctions() throws SQLException {
129	return "";
130    }
131
132    public String getSystemFunctions() throws SQLException {
133	return "";
134    }
135
136    public String getTimeDateFunctions() throws SQLException {
137	return "";
138    }
139
140    public String getSearchStringEscape() throws SQLException {
141	return "\\";
142    }
143
144    public String getExtraNameCharacters() throws SQLException {
145	return "";
146    }
147
148    public boolean supportsAlterTableWithAddColumn() throws SQLException {
149	return false;
150    }
151
152    public boolean supportsAlterTableWithDropColumn() throws SQLException {
153	return false;
154    }
155
156    public boolean supportsColumnAliasing() throws SQLException {
157	return true;
158    }
159
160    public boolean nullPlusNonNullIsNull() throws SQLException {
161	return false;
162    }
163
164    public boolean supportsConvert() throws SQLException {
165	return false;
166    }
167
168    public boolean supportsConvert(int fromType, int toType)
169	throws SQLException {
170	return false;
171    }
172
173    public boolean supportsTableCorrelationNames() throws SQLException {
174	return true;
175    }
176
177    public boolean supportsDifferentTableCorrelationNames()
178	throws SQLException {
179	return false;
180    }
181
182    public boolean supportsExpressionsInOrderBy() throws SQLException {
183	return true;
184    }
185
186    public boolean supportsOrderByUnrelated() throws SQLException {
187	return true;
188    }
189
190    public boolean supportsGroupBy() throws SQLException {
191	return true;
192    }
193
194    public boolean supportsGroupByUnrelated() throws SQLException {
195	return true;
196    }
197
198    public boolean supportsGroupByBeyondSelect() throws SQLException {
199	return false;
200    }
201
202    public boolean supportsLikeEscapeClause() throws SQLException {
203	return false;
204    }
205
206    public boolean supportsMultipleResultSets() throws SQLException {
207	return false;
208    }
209
210    public boolean supportsMultipleTransactions() throws SQLException {
211	return false;
212    }
213
214    public boolean supportsNonNullableColumns() throws SQLException {
215	return true;
216    }
217
218    public boolean supportsMinimumSQLGrammar() throws SQLException {
219	return true;
220    }
221
222    public boolean supportsCoreSQLGrammar() throws SQLException {
223	return false;
224    }
225
226    public boolean supportsExtendedSQLGrammar() throws SQLException {
227	return false;
228    }
229
230    public boolean supportsANSI92EntryLevelSQL() throws SQLException {
231	return true;
232    }
233
234    public boolean supportsANSI92IntermediateSQL() throws SQLException {
235	return false;
236    }
237
238    public boolean supportsANSI92FullSQL() throws SQLException {
239	return false;
240    }
241
242    public boolean supportsIntegrityEnhancementFacility()
243	throws SQLException {
244	return false;
245    }
246
247    public boolean supportsOuterJoins() throws SQLException {
248	return false;
249    }
250
251    public boolean supportsFullOuterJoins() throws SQLException {
252	return false;
253    }
254
255    public boolean supportsLimitedOuterJoins() throws SQLException {
256	return false;
257    }
258
259    public String getSchemaTerm() throws SQLException {
260	return "";
261    }
262
263    public String getProcedureTerm() throws SQLException {
264	return "";
265    }
266
267    public String getCatalogTerm() throws SQLException {
268	return "";
269    }
270
271    public boolean isCatalogAtStart() throws SQLException {
272	return false;
273    }
274
275    public String getCatalogSeparator() throws SQLException {
276	return "";
277    }
278
279    public boolean supportsSchemasInDataManipulation() throws SQLException {
280	return false;
281    }
282
283    public boolean supportsSchemasInProcedureCalls() throws SQLException {
284	return false;
285    }
286
287    public boolean supportsSchemasInTableDefinitions() throws SQLException {
288	return false;
289    }
290
291    public boolean supportsSchemasInIndexDefinitions() throws SQLException {
292	return false;
293    }
294
295    public boolean supportsSchemasInPrivilegeDefinitions()
296	throws SQLException {
297	return false;
298    }
299
300    public boolean supportsCatalogsInDataManipulation() throws SQLException {
301	return false;
302    }
303
304    public boolean supportsCatalogsInProcedureCalls() throws SQLException {
305	return false;
306    }
307
308    public boolean supportsCatalogsInTableDefinitions() throws SQLException {
309	return false;
310    }
311
312    public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
313	return false;
314    }
315
316    public boolean supportsCatalogsInPrivilegeDefinitions()
317	throws SQLException {
318	return false;
319    }
320
321    public boolean supportsPositionedDelete() throws SQLException {
322	return false;
323    }
324
325    public boolean supportsPositionedUpdate() throws SQLException {
326	return false;
327    }
328
329    public boolean supportsSelectForUpdate() throws SQLException {
330	return false;
331    }
332
333    public boolean supportsStoredProcedures() throws SQLException {
334	return false;
335    }
336
337    public boolean supportsSubqueriesInComparisons() throws SQLException {
338	return true;
339    }
340
341    public boolean supportsSubqueriesInExists() throws SQLException {
342	return true;
343    }
344
345    public boolean supportsSubqueriesInIns() throws SQLException {
346	return true;
347    }
348
349    public boolean supportsSubqueriesInQuantifieds() throws SQLException {
350	return false;
351    }
352
353    public boolean supportsCorrelatedSubqueries() throws SQLException {
354	return false;
355    }
356
357    public boolean supportsUnion() throws SQLException {
358	return true;
359    }
360
361    public boolean supportsUnionAll() throws SQLException {
362	return true;
363    }
364
365    public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
366	return false;
367    }
368
369    public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
370	return false;
371    }
372
373    public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
374	return false;
375    }
376
377    public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
378	return false;
379    }
380
381    public int getMaxBinaryLiteralLength() throws SQLException {
382	return 0;
383    }
384
385    public int getMaxCharLiteralLength() throws SQLException {
386	return 0;
387    }
388
389    public int getMaxColumnNameLength() throws SQLException {
390	return 0;
391    }
392
393    public int getMaxColumnsInGroupBy() throws SQLException {
394	return 0;
395    }
396
397    public int getMaxColumnsInIndex() throws SQLException {
398	return 0;
399    }
400
401    public int getMaxColumnsInOrderBy() throws SQLException {
402	return 0;
403    }
404
405    public int getMaxColumnsInSelect() throws SQLException {
406	return 0;
407    }
408
409    public int getMaxColumnsInTable() throws SQLException {
410	return 0;
411    }
412
413    public int getMaxConnections() throws SQLException {
414	return 0;
415    }
416
417    public int getMaxCursorNameLength() throws SQLException {
418	return 8;
419    }
420
421    public int getMaxIndexLength() throws SQLException {
422	return 0;
423    }
424
425    public int getMaxSchemaNameLength() throws SQLException {
426	return 0;
427    }
428
429    public int getMaxProcedureNameLength() throws SQLException {
430	return 0;
431    }
432
433    public int getMaxCatalogNameLength() throws SQLException {
434	return 0;
435    }
436
437    public int getMaxRowSize() throws SQLException {
438	return 0;
439    }
440
441    public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
442	return true;
443    }
444
445    public int getMaxStatementLength() throws SQLException {
446	return 0;
447    }
448
449    public int getMaxStatements() throws SQLException {
450	return 0;
451    }
452
453    public int getMaxTableNameLength() throws SQLException {
454	return 0;
455    }
456
457    public int getMaxTablesInSelect() throws SQLException {
458	return 0;
459    }
460
461    public int getMaxUserNameLength() throws SQLException {
462	return 0;
463    }
464
465    public int getDefaultTransactionIsolation() throws SQLException {
466	return Connection.TRANSACTION_SERIALIZABLE;
467    }
468
469    public boolean supportsTransactions() throws SQLException {
470	return true;
471    }
472
473    public boolean supportsTransactionIsolationLevel(int level)
474	throws SQLException {
475	return level == Connection.TRANSACTION_SERIALIZABLE;
476    }
477
478    public boolean supportsDataDefinitionAndDataManipulationTransactions()
479	throws SQLException {
480	return true;
481    }
482
483    public boolean supportsDataManipulationTransactionsOnly()
484	throws SQLException {
485	return false;
486    }
487
488    public boolean dataDefinitionCausesTransactionCommit()
489	throws SQLException {
490	return false;
491    }
492
493    public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
494	return false;
495    }
496
497    public ResultSet getProcedures(String catalog, String schemaPattern,
498				   String procedureNamePattern)
499	throws SQLException {
500	return null;
501    }
502
503    public ResultSet getProcedureColumns(String catalog,
504					 String schemaPattern,
505					 String procedureNamePattern,
506					 String columnNamePattern)
507	throws SQLException {
508	return null;
509    }
510
511    public ResultSet getTables(String catalog, String schemaPattern,
512			       String tableNamePattern, String types[])
513	throws SQLException {
514	JDBCStatement s = new JDBCStatement(conn);
515	StringBuffer sb = new StringBuffer();
516	sb.append("SELECT '' AS 'TABLE_CAT', " +
517		  "'' AS 'TABLE_SCHEM', " +
518		  "tbl_name AS 'TABLE_NAME', " +
519		  "upper(type) AS 'TABLE_TYPE', " +
520		  "'' AS REMARKS FROM sqlite_master " +
521		  "WHERE tbl_name like ");
522	if (tableNamePattern != null) {
523	    sb.append(SQLite.Shell.sql_quote(tableNamePattern));
524	} else {
525	    sb.append("'%'");
526	}
527	sb.append(" AND ");
528	if (types == null || types.length == 0) {
529	    sb.append("(type = 'table' or type = 'view')");
530	} else {
531	    sb.append("(");
532	    String sep = "";
533	    for (int i = 0; i < types.length; i++) {
534		sb.append(sep);
535		sb.append("type = ");
536		sb.append(SQLite.Shell.sql_quote(types[i].toLowerCase()));
537		sep = " or ";
538	    }
539	    sb.append(")");
540	}
541	ResultSet rs = null;
542	try {
543	    rs = s.executeQuery(sb.toString());
544	    s.close();
545	} catch (SQLException e) {
546	    throw e;
547	} finally {
548	    s.close();
549	}
550	return rs;
551    }
552
553    public ResultSet getSchemas() throws SQLException {
554	String cols[] = { "TABLE_SCHEM" };
555	SQLite.TableResult tr = new SQLite.TableResult();
556	tr.columns(cols);
557	String row[] = { "" };
558	tr.newrow(row);
559	JDBCResultSet rs = new JDBCResultSet(tr, null);
560	return (ResultSet) rs;
561    }
562
563    public ResultSet getCatalogs() throws SQLException {
564	String cols[] = { "TABLE_CAT" };
565	SQLite.TableResult tr = new SQLite.TableResult();
566	tr.columns(cols);
567	String row[] = { "" };
568	tr.newrow(row);
569	JDBCResultSet rs = new JDBCResultSet(tr, null);
570	return (ResultSet) rs;
571    }
572
573    public ResultSet getTableTypes() throws SQLException {
574	String cols[] = { "TABLE_TYPE" };
575	SQLite.TableResult tr = new SQLite.TableResult();
576	tr.columns(cols);
577	String row[] = new String[1];
578	row[0] = "TABLE";
579	tr.newrow(row);
580	row = new String[1];
581	row[0] = "VIEW";
582	tr.newrow(row);
583	JDBCResultSet rs = new JDBCResultSet(tr, null);
584	return (ResultSet) rs;
585    }
586
587    public ResultSet getColumns(String catalog, String schemaPattern,
588				String tableNamePattern,
589				String columnNamePattern)
590	throws SQLException {
591    // BEGIN android-changed: add missing error check.
592    if (conn.db == null) {
593        throw new SQLException("connection closed");
594    }
595    // END android-changed
596	JDBCStatement s = new JDBCStatement(conn);
597	JDBCResultSet rs0 = null;
598	try {
599	    try {
600		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
601	    } catch (SQLite.Exception se) {
602		throw new SQLException("schema reload failed");
603	    }
604	    rs0 = (JDBCResultSet)
605		(s.executeQuery("PRAGMA table_info(" +
606				SQLite.Shell.sql_quote(tableNamePattern) +
607				")"));
608	    s.close();
609	} catch (SQLException e) {
610	    throw e;
611	} finally {
612	    s.close();
613	}
614	if (rs0.tr.nrows < 1) {
615	    throw new SQLException("no such table: " + tableNamePattern);
616	}
617	String cols[] = {
618	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
619	    "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME",
620	    "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS",
621	    "NUM_PREC_RADIX", "NULLABLE", "REMARKS",
622	    "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB",
623	    "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE"
624	};
625	int types[] = {
626	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
627	    Types.VARCHAR, Types.SMALLINT, Types.VARCHAR,
628	    Types.INTEGER, Types.INTEGER, Types.INTEGER,
629	    Types.INTEGER, Types.INTEGER, Types.VARCHAR,
630	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
631	    Types.INTEGER, Types.INTEGER, Types.VARCHAR
632	};
633	TableResultX tr = new TableResultX();
634	tr.columns(cols);
635	tr.sql_types(types);
636	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
637	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
638	    Hashtable<String, Integer> h = new Hashtable<String, Integer>();
639	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
640		h.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
641	    }
642	    if (columnNamePattern != null &&
643		columnNamePattern.charAt(0) == '%') {
644		columnNamePattern = null;
645	    }
646	    for (int i = 0; i < rs0.tr.nrows; i++) {
647		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
648		int col = ((Integer) h.get("name")).intValue();
649		if (columnNamePattern != null) {
650		    if (r0[col].compareTo(columnNamePattern) != 0) {
651			continue;
652		    }
653		}
654		String row[] = new String[cols.length];
655		row[0]  = "";
656		row[1]  = "";
657		row[2]  = tableNamePattern;
658		row[3]  = r0[col];
659		col = ((Integer) h.get("type")).intValue();
660		String typeStr = r0[col];
661		int type = mapSqlType(typeStr);
662		row[4]  = "" + type;
663		row[5]  = mapTypeName(type);
664		row[6]  = "" + getD(typeStr, type);
665		row[7]  = "" + getM(typeStr, type);
666		row[8]  = "10";
667		row[9]  = "0";
668		row[11] = null;
669		col = ((Integer) h.get("dflt_value")).intValue();
670		row[12] = r0[col];
671		row[13] = "0";
672		row[14] = "0";
673		row[15] = "65536";
674		col = ((Integer) h.get("cid")).intValue();
675		row[16] = Integer.toString(Integer.parseInt(r0[col]) + 1); // android-changed
676		col = ((Integer) h.get("notnull")).intValue();
677		row[17] = (r0[col].charAt(0) == '0') ? "YES" : "NO";
678		row[10] = (r0[col].charAt(0) == '0') ? "" + columnNullable :
679			  "" + columnNoNulls;
680		tr.newrow(row);
681	    }
682	}
683	return rs;
684    }
685
686    public ResultSet getColumnPrivileges(String catalog, String schema,
687					 String table,
688					 String columnNamePattern)
689	throws SQLException {
690	String cols[] = {
691	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
692	    "COLUMN_NAME", "GRANTOR", "GRANTEE",
693	    "PRIVILEGE", "IS_GRANTABLE"
694	};
695	int types[] = {
696	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
697	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
698	    Types.VARCHAR, Types.VARCHAR
699	};
700	TableResultX tr = new TableResultX();
701	tr.columns(cols);
702	tr.sql_types(types);
703	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
704	return rs;
705    }
706
707    public ResultSet getTablePrivileges(String catalog, String schemaPattern,
708					String tableNamePattern)
709	throws SQLException {
710	String cols[] = {
711	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
712	    "COLUMN_NAME", "GRANTOR", "GRANTEE",
713	    "PRIVILEGE", "IS_GRANTABLE"
714	};
715	int types[] = {
716	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
717	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
718	    Types.VARCHAR, Types.VARCHAR
719	};
720	TableResultX tr = new TableResultX();
721	tr.columns(cols);
722	tr.sql_types(types);
723	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
724	return rs;
725    }
726
727    public ResultSet getBestRowIdentifier(String catalog, String schema,
728					  String table, int scope,
729					  boolean nullable)
730	throws SQLException {
731	JDBCStatement s0 = new JDBCStatement(conn);
732	JDBCResultSet rs0 = null;
733	JDBCStatement s1 = new JDBCStatement(conn);
734	JDBCResultSet rs1 = null;
735	try {
736	    try {
737		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
738	    } catch (SQLite.Exception se) {
739		throw new SQLException("schema reload failed");
740	    }
741	    rs0 = (JDBCResultSet)
742		(s0.executeQuery("PRAGMA index_list(" +
743				 SQLite.Shell.sql_quote(table) + ")"));
744	    rs1 = (JDBCResultSet)
745		(s1.executeQuery("PRAGMA table_info(" +
746				 SQLite.Shell.sql_quote(table) + ")"));
747	} catch (SQLException e) {
748	    throw e;
749	} finally {
750	    s0.close();
751	    s1.close();
752	}
753	String cols[] = {
754	    "SCOPE", "COLUMN_NAME", "DATA_TYPE",
755	    "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH",
756	    "DECIMAL_DIGITS", "PSEUDO_COLUMN"
757	};
758	int types[] = {
759	    Types.SMALLINT, Types.VARCHAR, Types.SMALLINT,
760	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
761	    Types.SMALLINT, Types.SMALLINT
762	};
763	TableResultX tr = new TableResultX();
764	tr.columns(cols);
765	tr.sql_types(types);
766	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
767	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0 &&
768	    rs1 != null && rs1.tr != null && rs1.tr.nrows > 0) {
769	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
770	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
771		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
772	    }
773	    Hashtable<String, Integer> h1 = new Hashtable<String, Integer>();
774	    for (int i = 0; i < rs1.tr.ncolumns; i++) {
775		h1.put(rs1.tr.column[i], Integer.valueOf(i)); // android-changed
776	    }
777	    for (int i = 0; i < rs0.tr.nrows; i++) {
778		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
779		int col = ((Integer) h0.get("unique")).intValue();
780		String uniq = r0[col];
781		col = ((Integer) h0.get("name")).intValue();
782		String iname = r0[col];
783		if (uniq.charAt(0) == '0') {
784		    continue;
785		}
786		JDBCStatement s2 = new JDBCStatement(conn);
787		JDBCResultSet rs2 = null;
788		try {
789		    rs2 = (JDBCResultSet)
790			(s2.executeQuery("PRAGMA index_info(" +
791					 SQLite.Shell.sql_quote(iname) + ")"));
792		} catch (SQLException e) {
793		} finally {
794		    s2.close();
795		}
796		if (rs2 == null || rs2.tr == null || rs2.tr.nrows <= 0) {
797		    continue;
798		}
799		Hashtable<String, Integer> h2 =
800		    new Hashtable<String, Integer>();
801		for (int k = 0; k < rs2.tr.ncolumns; k++) {
802		    h2.put(rs2.tr.column[k], Integer.valueOf(k)); // android-changed
803		}
804		for (int k = 0; k < rs2.tr.nrows; k++) {
805		    String r2[] = (String [])(rs2.tr.rows.elementAt(k));
806		    col = ((Integer) h2.get("name")).intValue();
807		    String cname = r2[col];
808		    for (int m = 0; m < rs1.tr.nrows; m++) {
809			String r1[] = (String [])(rs1.tr.rows.elementAt(m));
810			col = ((Integer) h1.get("name")).intValue();
811			if (cname.compareTo(r1[col]) == 0) {
812			    String row[] = new String[cols.length];
813			    row[0] = "" + scope;
814			    row[1] = cname;
815			    row[2] = "" + Types.VARCHAR;
816			    row[3] = "VARCHAR";
817			    row[4] = "65536";
818			    row[5] = "0";
819			    row[6] = "0";
820			    row[7] = "" + bestRowNotPseudo;
821			    tr.newrow(row);
822			}
823		    }
824		}
825	    }
826	}
827	if (tr.nrows <= 0) {
828	    String row[] = new String[cols.length];
829	    row[0] = "" + scope;
830	    row[1] = "_ROWID_";
831	    row[2] = "" + Types.INTEGER;
832	    row[3] = "INTEGER";
833	    row[4] = "10";
834	    row[5] = "0";
835	    row[6] = "0";
836	    row[7] = "" + bestRowPseudo;
837	    tr.newrow(row);
838	}
839	return rs;
840    }
841
842    public ResultSet getVersionColumns(String catalog, String schema,
843				       String table) throws SQLException {
844	String cols[] = {
845	    "SCOPE", "COLUMN_NAME", "DATA_TYPE",
846	    "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH",
847	    "DECIMAL_DIGITS", "PSEUDO_COLUMN"
848	};
849	int types[] = {
850	    Types.SMALLINT, Types.VARCHAR, Types.SMALLINT,
851	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
852	    Types.SMALLINT, Types.SMALLINT
853	};
854	TableResultX tr = new TableResultX();
855	tr.columns(cols);
856	tr.sql_types(types);
857	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
858	return rs;
859    }
860
861    public ResultSet getPrimaryKeys(String catalog, String schema,
862				    String table) throws SQLException {
863	JDBCStatement s0 = new JDBCStatement(conn);
864	JDBCResultSet rs0 = null;
865	try {
866	    try {
867		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
868	    } catch (SQLite.Exception se) {
869		throw new SQLException("schema reload failed");
870	    }
871	    rs0 = (JDBCResultSet)
872		(s0.executeQuery("PRAGMA index_list(" +
873				 SQLite.Shell.sql_quote(table) + ")"));
874	} catch (SQLException e) {
875	    throw e;
876	} finally {
877	    s0.close();
878	}
879	String cols[] = {
880	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
881	    "COLUMN_NAME", "KEY_SEQ", "PK_NAME"
882	};
883	int types[] = {
884	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
885	    Types.VARCHAR, Types.SMALLINT, Types.VARCHAR
886	};
887	TableResultX tr = new TableResultX();
888	tr.columns(cols);
889	tr.sql_types(types);
890	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
891	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
892	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
893	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
894		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
895	    }
896	    for (int i = 0; i < rs0.tr.nrows; i++) {
897		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
898		int col = ((Integer) h0.get("unique")).intValue();
899		String uniq = r0[col];
900		col = ((Integer) h0.get("name")).intValue();
901		String iname = r0[col];
902		if (uniq.charAt(0) == '0') {
903		    continue;
904		}
905		JDBCStatement s1 = new JDBCStatement(conn);
906		JDBCResultSet rs1 = null;
907		try {
908		    rs1 = (JDBCResultSet)
909			(s1.executeQuery("PRAGMA index_info(" +
910					 SQLite.Shell.sql_quote(iname) + ")"));
911		} catch (SQLException e) {
912		} finally {
913		    s1.close();
914		}
915		if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) {
916		    continue;
917		}
918		Hashtable<String, Integer> h1 =
919		    new Hashtable<String, Integer>();
920		for (int k = 0; k < rs1.tr.ncolumns; k++) {
921		    h1.put(rs1.tr.column[k], Integer.valueOf(k)); // android-changed
922		}
923		for (int k = 0; k < rs1.tr.nrows; k++) {
924		    String r1[] = (String [])(rs1.tr.rows.elementAt(k));
925		    String row[] = new String[cols.length];
926		    row[0]  = "";
927		    row[1]  = "";
928		    row[2]  = table;
929		    col = ((Integer) h1.get("name")).intValue();
930		    row[3] = r1[col];
931		    col = ((Integer) h1.get("seqno")).intValue();
932		    row[4]  = Integer.toString(Integer.parseInt(r1[col]) + 1); // android-changed: performance
933		    row[5]  = iname;
934		    tr.newrow(row);
935		}
936	    }
937	}
938	if (tr.nrows > 0) {
939	    return rs;
940	}
941	JDBCStatement s1 = new JDBCStatement(conn);
942	try {
943	    rs0 = (JDBCResultSet)
944		(s1.executeQuery("PRAGMA table_info(" +
945				 SQLite.Shell.sql_quote(table) + ")"));
946	} catch (SQLException e) {
947	    throw e;
948	} finally {
949	    s1.close();
950	}
951	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
952	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
953	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
954		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
955	    }
956	    for (int i = 0; i < rs0.tr.nrows; i++) {
957		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
958		int col = ((Integer) h0.get("type")).intValue();
959		String type = r0[col];
960		if (!type.equalsIgnoreCase("integer")) {
961		    continue;
962		}
963		col = ((Integer) h0.get("pk")).intValue();
964		String pk = r0[col];
965		if (pk.charAt(0) == '0') {
966		    continue;
967		}
968		String row[] = new String[cols.length];
969		row[0]  = "";
970		row[1]  = "";
971		row[2]  = table;
972		col = ((Integer) h0.get("name")).intValue();
973		row[3] = r0[col];
974		col = ((Integer) h0.get("cid")).intValue();
975		row[4] = Integer.toString(Integer.parseInt(r0[col]) + 1); // android-changed: performance
976		row[5] = "";
977		tr.newrow(row);
978	    }
979	}
980	return rs;
981    }
982
983    private void internalImportedKeys(String table, String pktable,
984				      JDBCResultSet in, TableResultX out) {
985	Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
986	for (int i = 0; i < in.tr.ncolumns; i++) {
987	    h0.put(in.tr.column[i], Integer.valueOf(i)); // android-changed
988	}
989	for (int i = 0; i < in.tr.nrows; i++) {
990	    String r0[] = (String [])(in.tr.rows.elementAt(i));
991	    int col = ((Integer) h0.get("table")).intValue();
992	    String pktab = r0[col];
993	    if (pktable != null && !pktable.equalsIgnoreCase(pktab)) {
994		continue;
995	    }
996	    col = ((Integer) h0.get("from")).intValue();
997	    String fkcol = r0[col];
998	    col = ((Integer) h0.get("to")).intValue();
999	    String pkcol = r0[col];
1000	    col = ((Integer) h0.get("seq")).intValue();
1001	    String seq = r0[col];
1002	    String row[] = new String[out.ncolumns];
1003	    row[0]  = "";
1004	    row[1]  = "";
1005	    row[2]  = pktab;
1006	    row[3]  = pkcol;
1007	    row[4]  = "";
1008	    row[5]  = "";
1009	    row[6]  = table;
1010	    row[7]  = fkcol == null ? pkcol : fkcol;
1011	    row[8]  = Integer.toString(Integer.parseInt(seq) + 1); // android-changed: performance
1012	    row[9]  =
1013		"" + java.sql.DatabaseMetaData.importedKeyNoAction;
1014	    row[10] =
1015		"" + java.sql.DatabaseMetaData.importedKeyNoAction;
1016	    row[11] = null;
1017	    row[12] = null;
1018	    row[13] =
1019		"" + java.sql.DatabaseMetaData.importedKeyNotDeferrable;
1020	    out.newrow(row);
1021	}
1022    }
1023
1024    public ResultSet getImportedKeys(String catalog, String schema,
1025				     String table) throws SQLException {
1026	JDBCStatement s0 = new JDBCStatement(conn);
1027	JDBCResultSet rs0 = null;
1028	try {
1029	    try {
1030		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
1031	    } catch (SQLite.Exception se) {
1032		throw new SQLException("schema reload failed");
1033	    }
1034	    rs0 = (JDBCResultSet)
1035		(s0.executeQuery("PRAGMA foreign_key_list(" +
1036				 SQLite.Shell.sql_quote(table) + ")"));
1037	} catch (SQLException e) {
1038	    throw e;
1039	} finally {
1040	    s0.close();
1041	}
1042	String cols[] = {
1043	    "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME",
1044	    "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM",
1045	    "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ",
1046	    "UPDATE_RULE", "DELETE_RULE", "FK_NAME",
1047	    "PK_NAME", "DEFERRABILITY"
1048	};
1049	int types[] = {
1050	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1051	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1052	    Types.VARCHAR, Types.VARCHAR, Types.SMALLINT,
1053	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1054	    Types.VARCHAR, Types.SMALLINT
1055	};
1056	TableResultX tr = new TableResultX();
1057	tr.columns(cols);
1058	tr.sql_types(types);
1059	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
1060	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
1061	    internalImportedKeys(table, null, rs0, tr);
1062	}
1063	return rs;
1064    }
1065
1066    public ResultSet getExportedKeys(String catalog, String schema,
1067				     String table) throws SQLException {
1068	String cols[] = {
1069	    "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME",
1070	    "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM",
1071	    "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ",
1072	    "UPDATE_RULE", "DELETE_RULE", "FK_NAME",
1073	    "PK_NAME", "DEFERRABILITY"
1074	};
1075	int types[] = {
1076	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1077	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1078	    Types.VARCHAR, Types.VARCHAR, Types.SMALLINT,
1079	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1080	    Types.VARCHAR, Types.SMALLINT
1081	};
1082	TableResultX tr = new TableResultX();
1083	tr.columns(cols);
1084	tr.sql_types(types);
1085	JDBCResultSet rs = new JDBCResultSet(tr, null);
1086	return rs;
1087    }
1088
1089    public ResultSet getCrossReference(String primaryCatalog,
1090				       String primarySchema,
1091				       String primaryTable,
1092				       String foreignCatalog,
1093				       String foreignSchema,
1094				       String foreignTable)
1095	throws SQLException {
1096	JDBCResultSet rs0 = null;
1097	if (foreignTable != null && foreignTable.charAt(0) != '%') {
1098	    JDBCStatement s0 = new JDBCStatement(conn);
1099	    try {
1100		try {
1101		    conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
1102		} catch (SQLite.Exception se) {
1103		    throw new SQLException("schema reload failed");
1104		}
1105		rs0 = (JDBCResultSet)
1106		    (s0.executeQuery("PRAGMA foreign_key_list(" +
1107				     SQLite.Shell.sql_quote(foreignTable) + ")"));
1108	    } catch (SQLException e) {
1109		throw e;
1110	    } finally {
1111		s0.close();
1112	    }
1113	}
1114	String cols[] = {
1115	    "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME",
1116	    "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM",
1117	    "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ",
1118	    "UPDATE_RULE", "DELETE_RULE", "FK_NAME",
1119	    "PK_NAME", "DEFERRABILITY"
1120	};
1121	int types[] = {
1122	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1123	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1124	    Types.VARCHAR, Types.VARCHAR, Types.SMALLINT,
1125	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1126	    Types.VARCHAR, Types.SMALLINT
1127	};
1128	TableResultX tr = new TableResultX();
1129	tr.columns(cols);
1130	tr.sql_types(types);
1131	JDBCResultSet rs = new JDBCResultSet(tr, null);
1132	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
1133	    String pktable = null;
1134	    if (primaryTable != null && primaryTable.charAt(0) != '%') {
1135		pktable = primaryTable;
1136	    }
1137	    internalImportedKeys(foreignTable, pktable, rs0, tr);
1138	}
1139	return rs;
1140    }
1141
1142    public ResultSet getTypeInfo() throws SQLException {
1143	String cols[] = {
1144	    "TYPE_NAME", "DATA_TYPE", "PRECISION",
1145	    "LITERAL_PREFIX", "LITERAL_SUFFIX", "CREATE_PARAMS",
1146	    "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE",
1147	    "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT",
1148	    "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE",
1149	    "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"
1150	};
1151	int types[] = {
1152	    Types.VARCHAR, Types.SMALLINT, Types.INTEGER,
1153	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1154	    Types.SMALLINT, Types.BIT, Types.SMALLINT,
1155	    Types.BIT, Types.BIT, Types.BIT,
1156	    Types.VARCHAR, Types.SMALLINT, Types.SMALLINT,
1157	    Types.INTEGER, Types.INTEGER, Types.INTEGER
1158	};
1159	TableResultX tr = new TableResultX();
1160	tr.columns(cols);
1161	tr.sql_types(types);
1162	JDBCResultSet rs = new JDBCResultSet(tr, null);
1163	String row1[] = {
1164	    "VARCHAR", "" + Types.VARCHAR, "65536",
1165	    "'", "'", null,
1166	    "" + typeNullable, "1", "" + typeSearchable,
1167	    "0", "0", "0",
1168	    null, "0", "0",
1169	    "0", "0", "0"
1170	};
1171	tr.newrow(row1);
1172	String row2[] = {
1173	    "INTEGER", "" + Types.INTEGER, "32",
1174	    null, null, null,
1175	    "" + typeNullable, "0", "" + typeSearchable,
1176	    "0", "0", "1",
1177	    null, "0", "0",
1178	    "0", "0", "2"
1179	};
1180	tr.newrow(row2);
1181	String row3[] = {
1182	    "DOUBLE", "" + Types.DOUBLE, "16",
1183	    null, null, null,
1184	    "" + typeNullable, "0", "" + typeSearchable,
1185	    "0", "0", "1",
1186	    null, "0", "0",
1187	    "0", "0", "10"
1188	};
1189	tr.newrow(row3);
1190	String row4[] = {
1191	    "FLOAT", "" + Types.FLOAT, "7",
1192	    null, null, null,
1193	    "" + typeNullable, "0", "" + typeSearchable,
1194	    "0", "0", "1",
1195	    null, "0", "0",
1196	    "0", "0", "10"
1197	};
1198	tr.newrow(row4);
1199	String row5[] = {
1200	    "SMALLINT", "" + Types.SMALLINT, "16",
1201	    null, null, null,
1202	    "" + typeNullable, "0", "" + typeSearchable,
1203	    "0", "0", "1",
1204	    null, "0", "0",
1205	    "0", "0", "2"
1206	};
1207	tr.newrow(row5);
1208	String row6[] = {
1209	    "BIT", "" + Types.BIT, "1",
1210	    null, null, null,
1211	    "" + typeNullable, "0", "" + typeSearchable,
1212	    "0", "0", "1",
1213	    null, "0", "0",
1214	    "0", "0", "2"
1215	};
1216	tr.newrow(row6);
1217	String row7[] = {
1218	    "TIMESTAMP", "" + Types.TIMESTAMP, "30",
1219	    null, null, null,
1220	    "" + typeNullable, "0", "" + typeSearchable,
1221	    "0", "0", "1",
1222	    null, "0", "0",
1223	    "0", "0", "0"
1224	};
1225	tr.newrow(row7);
1226	String row8[] = {
1227	    "DATE", "" + Types.DATE, "10",
1228	    null, null, null,
1229	    "" + typeNullable, "0", "" + typeSearchable,
1230	    "0", "0", "1",
1231	    null, "0", "0",
1232	    "0", "0", "0"
1233	};
1234	tr.newrow(row8);
1235	String row9[] = {
1236	    "TIME", "" + Types.TIME, "8",
1237	    null, null, null,
1238	    "" + typeNullable, "0", "" + typeSearchable,
1239	    "0", "0", "1",
1240	    null, "0", "0",
1241	    "0", "0", "0"
1242	};
1243	tr.newrow(row9);
1244	String row10[] = {
1245	    "BINARY", "" + Types.BINARY, "65536",
1246	    null, null, null,
1247	    "" + typeNullable, "0", "" + typeSearchable,
1248	    "0", "0", "1",
1249	    null, "0", "0",
1250	    "0", "0", "0"
1251	};
1252	tr.newrow(row10);
1253	String row11[] = {
1254	    "VARBINARY", "" + Types.VARBINARY, "65536",
1255	    null, null, null,
1256	    "" + typeNullable, "0", "" + typeSearchable,
1257	    "0", "0", "1",
1258	    null, "0", "0",
1259	    "0", "0", "0"
1260	};
1261	tr.newrow(row11);
1262	String row12[] = {
1263	    "REAL", "" + Types.REAL, "16",
1264	    null, null, null,
1265	    "" + typeNullable, "0", "" + typeSearchable,
1266	    "0", "0", "1",
1267	    null, "0", "0",
1268	    "0", "0", "10"
1269	};
1270	tr.newrow(row12);
1271	return rs;
1272    }
1273
1274    public ResultSet getIndexInfo(String catalog, String schema, String table,
1275				  boolean unique, boolean approximate)
1276	throws SQLException {
1277	JDBCStatement s0 = new JDBCStatement(conn);
1278	JDBCResultSet rs0 = null;
1279	try {
1280	    try {
1281		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
1282	    } catch (SQLite.Exception se) {
1283		throw new SQLException("schema reload failed");
1284	    }
1285	    rs0 = (JDBCResultSet)
1286		(s0.executeQuery("PRAGMA index_list(" +
1287				 SQLite.Shell.sql_quote(table) + ")"));
1288	} catch (SQLException e) {
1289	    throw e;
1290	} finally {
1291	    s0.close();
1292	}
1293	String cols[] = {
1294	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
1295	    "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME",
1296	    "TYPE", "ORDINAL_POSITION", "COLUMN_NAME",
1297	    "ASC_OR_DESC", "CARDINALITY", "PAGES",
1298	    "FILTER_CONDITION"
1299	};
1300	int types[] = {
1301	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1302	    Types.BIT, Types.VARCHAR, Types.VARCHAR,
1303	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1304	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
1305	    Types.VARCHAR
1306	};
1307	TableResultX tr = new TableResultX();
1308	tr.columns(cols);
1309	tr.sql_types(types);
1310	JDBCResultSet rs = new JDBCResultSet(tr, null);
1311	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
1312	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
1313	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
1314		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
1315	    }
1316	    for (int i = 0; i < rs0.tr.nrows; i++) {
1317		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
1318		int col = ((Integer) h0.get("unique")).intValue();
1319		String uniq = r0[col];
1320		col = ((Integer) h0.get("name")).intValue();
1321		String iname = r0[col];
1322		if (unique && uniq.charAt(0) == '0') {
1323		    continue;
1324		}
1325		JDBCStatement s1 = new JDBCStatement(conn);
1326		JDBCResultSet rs1 = null;
1327		try {
1328		    rs1 = (JDBCResultSet)
1329			(s1.executeQuery("PRAGMA index_info(" +
1330					 SQLite.Shell.sql_quote(iname) + ")"));
1331		} catch (SQLException e) {
1332		} finally {
1333		    s1.close();
1334		}
1335		if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) {
1336		    continue;
1337		}
1338		Hashtable<String, Integer> h1 =
1339		    new Hashtable<String, Integer>();
1340		for (int k = 0; k < rs1.tr.ncolumns; k++) {
1341		    h1.put(rs1.tr.column[k], Integer.valueOf(k)); // android-changed
1342		}
1343		for (int k = 0; k < rs1.tr.nrows; k++) {
1344		    String r1[] = (String [])(rs1.tr.rows.elementAt(k));
1345		    String row[] = new String[cols.length];
1346		    row[0]  = "";
1347		    row[1]  = "";
1348		    row[2]  = table;
1349		    row[3]  = (uniq.charAt(0) != '0' ||
1350			(iname.charAt(0) == '(' &&
1351			 iname.indexOf(" autoindex ") > 0)) ? "0" : "1";
1352		    row[4]  = "";
1353		    row[5]  = iname;
1354		    row[6]  = "" + tableIndexOther;
1355		    col = ((Integer) h1.get("seqno")).intValue();
1356		    row[7]  = Integer.toString(Integer.parseInt(r1[col]) + 1); // android-changed: performance
1357		    col = ((Integer) h1.get("name")).intValue();
1358		    row[8]  = r1[col];
1359		    row[9]  = "A";
1360		    row[10] = "0";
1361		    row[11] = "0";
1362		    row[12] = null;
1363		    tr.newrow(row);
1364		}
1365	    }
1366	}
1367	return rs;
1368    }
1369
1370    public boolean supportsResultSetType(int type) throws SQLException {
1371	return type == ResultSet.TYPE_FORWARD_ONLY ||
1372	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1373	    type == ResultSet.TYPE_SCROLL_SENSITIVE;
1374    }
1375
1376    public boolean supportsResultSetConcurrency(int type, int concurrency)
1377	throws SQLException {
1378	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1379	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1380	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1381	    return concurrency == ResultSet.CONCUR_READ_ONLY ||
1382		concurrency == ResultSet.CONCUR_UPDATABLE;
1383	}
1384	return false;
1385    }
1386
1387    public boolean ownUpdatesAreVisible(int type) throws SQLException {
1388	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1389	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1390	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1391	    return true;
1392	}
1393	return false;
1394    }
1395
1396    public boolean ownDeletesAreVisible(int type) throws SQLException {
1397	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1398	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1399	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1400	    return true;
1401	}
1402	return false;
1403    }
1404
1405    public boolean ownInsertsAreVisible(int type) throws SQLException {
1406	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1407	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1408	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1409	    return true;
1410	}
1411	return false;
1412    }
1413
1414    public boolean othersUpdatesAreVisible(int type) throws SQLException {
1415	return false;
1416    }
1417
1418    public boolean othersDeletesAreVisible(int type) throws SQLException {
1419	return false;
1420    }
1421
1422    public boolean othersInsertsAreVisible(int type) throws SQLException {
1423	return false;
1424    }
1425
1426    public boolean updatesAreDetected(int type) throws SQLException {
1427	return false;
1428    }
1429
1430    public boolean deletesAreDetected(int type) throws SQLException {
1431	return false;
1432    }
1433
1434    public boolean insertsAreDetected(int type) throws SQLException {
1435	return false;
1436    }
1437
1438    public boolean supportsBatchUpdates() throws SQLException {
1439	return true;
1440    }
1441
1442    public ResultSet getUDTs(String catalog, String schemaPattern,
1443		      String typeNamePattern, int[] types)
1444	throws SQLException {
1445	return null;
1446    }
1447
1448    public Connection getConnection() throws SQLException {
1449	return conn;
1450    }
1451
1452    static String mapTypeName(int type) {
1453	switch (type) {
1454	case Types.INTEGER:	return "integer";
1455	case Types.SMALLINT:	return "smallint";
1456	case Types.FLOAT:	return "float";
1457	case Types.DOUBLE:	return "double";
1458	case Types.TIMESTAMP:	return "timestamp";
1459	case Types.DATE:	return "date";
1460	case Types.TIME:	return "time";
1461	case Types.BINARY:	return "binary";
1462	case Types.VARBINARY:	return "varbinary";
1463	case Types.REAL:	return "real";
1464	}
1465	return "varchar";
1466    }
1467
1468    static int mapSqlType(String type) {
1469	if (type == null) {
1470	    return Types.VARCHAR;
1471	}
1472	type = type.toLowerCase();
1473	if (type.startsWith("inter")) {
1474	    return Types.VARCHAR;
1475	}
1476	if (type.startsWith("numeric") ||
1477	    type.startsWith("int")) {
1478	    return Types.INTEGER;
1479	}
1480	if (type.startsWith("tinyint") ||
1481	    type.startsWith("smallint")) {
1482	    return Types.SMALLINT;
1483	}
1484	if (type.startsWith("float")) {
1485	    return Types.FLOAT;
1486	}
1487	if (type.startsWith("double")) {
1488	    return Types.DOUBLE;
1489	}
1490	if (type.startsWith("datetime") ||
1491	    type.startsWith("timestamp")) {
1492	    return Types.TIMESTAMP;
1493	}
1494	if (type.startsWith("date")) {
1495	    return Types.DATE;
1496	}
1497	if (type.startsWith("time")) {
1498	    return Types.TIME;
1499	}
1500	if (type.startsWith("blob")) {
1501	    return Types.BINARY;
1502	}
1503	if (type.startsWith("binary")) {
1504	    return Types.BINARY;
1505	}
1506	if (type.startsWith("varbinary")) {
1507	    return Types.VARBINARY;
1508	}
1509	if (type.startsWith("real")) {
1510	    return Types.REAL;
1511	}
1512	return Types.VARCHAR;
1513    }
1514
1515    static int getM(String typeStr, int type) {
1516	int m = 65536;
1517	switch (type) {
1518	case Types.INTEGER:	m = 11; break;
1519	case Types.SMALLINT:	m = 6;  break;
1520	case Types.FLOAT:	m = 25; break;
1521	case Types.REAL:
1522	case Types.DOUBLE:	m = 54; break;
1523	case Types.TIMESTAMP:	return 30;
1524	case Types.DATE:	return 10;
1525	case Types.TIME:	return 8;
1526	}
1527	typeStr = typeStr.toLowerCase();
1528	int i1 = typeStr.indexOf('(');
1529	if (i1 > 0) {
1530	    ++i1;
1531	    int i2 = typeStr.indexOf(',', i1);
1532	    if (i2 < 0) {
1533		i2 = typeStr.indexOf(')', i1);
1534	    }
1535	    if (i2 - i1 > 0) {
1536		String num = typeStr.substring(i1, i2);
1537		try {
1538		    m = java.lang.Integer.parseInt(num, 10);
1539		} catch (NumberFormatException e) {
1540		}
1541	    }
1542	}
1543	return m;
1544    }
1545
1546    static int getD(String typeStr, int type) {
1547	int d = 0;
1548	switch (type) {
1549	case Types.INTEGER:	d = 10; break;
1550	case Types.SMALLINT:	d = 5;  break;
1551	case Types.FLOAT:	d = 24; break;
1552	case Types.REAL:
1553	case Types.DOUBLE:	d = 53; break;
1554	default:		return getM(typeStr, type);
1555	}
1556	typeStr = typeStr.toLowerCase();
1557	int i1 = typeStr.indexOf('(');
1558	if (i1 > 0) {
1559	    ++i1;
1560	    int i2 = typeStr.indexOf(',', i1);
1561	    if (i2 < 0) {
1562		return getM(typeStr, type);
1563	    }
1564	    i1 = i2;
1565	    i2 = typeStr.indexOf(')', i1);
1566	    if (i2 - i1 > 0) {
1567		String num = typeStr.substring(i1, i2);
1568		try {
1569		    d = java.lang.Integer.parseInt(num, 10);
1570		} catch (NumberFormatException e) {
1571		}
1572	    }
1573	}
1574	return d;
1575    }
1576
1577    public boolean supportsSavepoints() {
1578	return false;
1579    }
1580
1581    public boolean supportsNamedParameters() {
1582	return false;
1583    }
1584
1585    public boolean supportsMultipleOpenResults() {
1586	return false;
1587    }
1588
1589    public boolean supportsGetGeneratedKeys() {
1590	return false;
1591    }
1592
1593    public boolean supportsResultSetHoldability(int x) {
1594	return false;
1595    }
1596
1597    public boolean supportsStatementPooling() {
1598	return false;
1599    }
1600
1601    public boolean locatorsUpdateCopy() throws SQLException {
1602	throw new SQLException("not supported");
1603    }
1604
1605    public ResultSet getSuperTypes(String catalog, String schemaPattern,
1606			    String typeNamePattern)
1607	throws SQLException {
1608	throw new SQLException("not supported");
1609    }
1610
1611    public ResultSet getSuperTables(String catalog, String schemaPattern,
1612				    String tableNamePattern)
1613	throws SQLException {
1614	throw new SQLException("not supported");
1615    }
1616
1617    public ResultSet getAttributes(String catalog, String schemaPattern,
1618				   String typeNamePattern,
1619				   String attributeNamePattern)
1620	throws SQLException {
1621	throw new SQLException("not supported");
1622    }
1623
1624    public int getResultSetHoldability() throws SQLException {
1625	return ResultSet.HOLD_CURSORS_OVER_COMMIT;
1626    }
1627
1628    public int getDatabaseMajorVersion() {
1629	return SQLite.JDBCDriver.MAJORVERSION;
1630    }
1631
1632    public int getDatabaseMinorVersion() {
1633	return SQLite.Constants.drv_minor;
1634    }
1635
1636    public int getJDBCMajorVersion() {
1637	return 1;
1638    }
1639
1640    public int getJDBCMinorVersion() {
1641	return 0;
1642    }
1643
1644    public int getSQLStateType() throws SQLException {
1645	return sqlStateXOpen;
1646    }
1647
1648    public RowIdLifetime getRowIdLifetime() throws SQLException {
1649	return RowIdLifetime.ROWID_UNSUPPORTED;
1650    }
1651
1652    public ResultSet getSchemas(String cat, String schema)
1653	throws SQLException {
1654	throw new SQLException("not supported");
1655    }
1656
1657    public boolean supportsStoredFunctionsUsingCallSyntax()
1658	throws SQLException {
1659	return false;
1660    }
1661
1662    public boolean autoCommitFailureClosesAllResultSets()
1663	throws SQLException {
1664	return false;
1665    }
1666
1667    public ResultSet getClientInfoProperties() throws SQLException {
1668	throw new SQLException("unsupported");
1669    }
1670
1671    public ResultSet getFunctions(String cat, String schema, String func)
1672	throws SQLException {
1673	throw new SQLException("unsupported");
1674    }
1675
1676    public ResultSet getFunctionColumns(String cat, String schema,
1677					String func, String colpat)
1678	throws SQLException {
1679	throw new SQLException("unsupported");
1680    }
1681
1682    public <T> T unwrap(java.lang.Class<T> iface) throws SQLException {
1683	throw new SQLException("unsupported");
1684    }
1685
1686    public boolean isWrapperFor(java.lang.Class iface) throws SQLException {
1687	return false;
1688    }
1689
1690}
1691