JDBCDatabaseMetaData.java revision 4538aff6d563d32cd1c5d2f7b349809384a0a540
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	if (conn.db == null) {
592	    throw new SQLException("connection closed.");
593	}
594	JDBCStatement s = new JDBCStatement(conn);
595	JDBCResultSet rs0 = null;
596	try {
597	    try {
598		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
599	    } catch (SQLite.Exception se) {
600		throw new SQLException("schema reload failed");
601	    }
602	    rs0 = (JDBCResultSet)
603		(s.executeQuery("PRAGMA table_info(" +
604				SQLite.Shell.sql_quote(tableNamePattern) +
605				")"));
606	    s.close();
607	} catch (SQLException e) {
608	    throw e;
609	} finally {
610	    s.close();
611	}
612	if (rs0.tr.nrows < 1) {
613	    throw new SQLException("no such table: " + tableNamePattern);
614	}
615	String cols[] = {
616	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
617	    "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME",
618	    "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS",
619	    "NUM_PREC_RADIX", "NULLABLE", "REMARKS",
620	    "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB",
621	    "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE"
622	};
623	int types[] = {
624	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
625	    Types.VARCHAR, Types.SMALLINT, Types.VARCHAR,
626	    Types.INTEGER, Types.INTEGER, Types.INTEGER,
627	    Types.INTEGER, Types.INTEGER, Types.VARCHAR,
628	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
629	    Types.INTEGER, Types.INTEGER, Types.VARCHAR
630	};
631	TableResultX tr = new TableResultX();
632	tr.columns(cols);
633	tr.sql_types(types);
634	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
635	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
636	    Hashtable<String, Integer> h = new Hashtable<String, Integer>();
637	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
638		h.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
639	    }
640	    if (columnNamePattern != null &&
641		columnNamePattern.charAt(0) == '%') {
642		columnNamePattern = null;
643	    }
644	    for (int i = 0; i < rs0.tr.nrows; i++) {
645		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
646		int col = ((Integer) h.get("name")).intValue();
647		if (columnNamePattern != null) {
648		    if (r0[col].compareTo(columnNamePattern) != 0) {
649			continue;
650		    }
651		}
652		String row[] = new String[cols.length];
653		row[0]  = "";
654		row[1]  = "";
655		row[2]  = tableNamePattern;
656		row[3]  = r0[col];
657		col = ((Integer) h.get("type")).intValue();
658		String typeStr = r0[col];
659		int type = mapSqlType(typeStr);
660		row[4]  = "" + type;
661		row[5]  = mapTypeName(type);
662		row[6]  = "" + getD(typeStr, type);
663		row[7]  = "" + getM(typeStr, type);
664		row[8]  = "10";
665		row[9]  = "0";
666		row[11] = null;
667		col = ((Integer) h.get("dflt_value")).intValue();
668		row[12] = r0[col];
669		row[13] = "0";
670		row[14] = "0";
671		row[15] = "65536";
672		col = ((Integer) h.get("cid")).intValue();
673		row[16] = Integer.toString(Integer.parseInt(r0[col]) + 1); // android-changed
674		col = ((Integer) h.get("notnull")).intValue();
675		row[17] = (r0[col].charAt(0) == '0') ? "YES" : "NO";
676		row[10] = (r0[col].charAt(0) == '0') ? "" + columnNullable :
677			  "" + columnNoNulls;
678		tr.newrow(row);
679	    }
680	}
681	return rs;
682    }
683
684    public ResultSet getColumnPrivileges(String catalog, String schema,
685					 String table,
686					 String columnNamePattern)
687	throws SQLException {
688	String cols[] = {
689	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
690	    "COLUMN_NAME", "GRANTOR", "GRANTEE",
691	    "PRIVILEGE", "IS_GRANTABLE"
692	};
693	int types[] = {
694	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
695	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
696	    Types.VARCHAR, Types.VARCHAR
697	};
698	TableResultX tr = new TableResultX();
699	tr.columns(cols);
700	tr.sql_types(types);
701	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
702	return rs;
703    }
704
705    public ResultSet getTablePrivileges(String catalog, String schemaPattern,
706					String tableNamePattern)
707	throws SQLException {
708	String cols[] = {
709	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
710	    "COLUMN_NAME", "GRANTOR", "GRANTEE",
711	    "PRIVILEGE", "IS_GRANTABLE"
712	};
713	int types[] = {
714	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
715	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
716	    Types.VARCHAR, Types.VARCHAR
717	};
718	TableResultX tr = new TableResultX();
719	tr.columns(cols);
720	tr.sql_types(types);
721	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
722	return rs;
723    }
724
725    public ResultSet getBestRowIdentifier(String catalog, String schema,
726					  String table, int scope,
727					  boolean nullable)
728	throws SQLException {
729	JDBCStatement s0 = new JDBCStatement(conn);
730	JDBCResultSet rs0 = null;
731	JDBCStatement s1 = new JDBCStatement(conn);
732	JDBCResultSet rs1 = null;
733	try {
734	    try {
735		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
736	    } catch (SQLite.Exception se) {
737		throw new SQLException("schema reload failed");
738	    }
739	    rs0 = (JDBCResultSet)
740		(s0.executeQuery("PRAGMA index_list(" +
741				 SQLite.Shell.sql_quote(table) + ")"));
742	    rs1 = (JDBCResultSet)
743		(s1.executeQuery("PRAGMA table_info(" +
744				 SQLite.Shell.sql_quote(table) + ")"));
745	} catch (SQLException e) {
746	    throw e;
747	} finally {
748	    s0.close();
749	    s1.close();
750	}
751	String cols[] = {
752	    "SCOPE", "COLUMN_NAME", "DATA_TYPE",
753	    "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH",
754	    "DECIMAL_DIGITS", "PSEUDO_COLUMN"
755	};
756	int types[] = {
757	    Types.SMALLINT, Types.VARCHAR, Types.SMALLINT,
758	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
759	    Types.SMALLINT, Types.SMALLINT
760	};
761	TableResultX tr = new TableResultX();
762	tr.columns(cols);
763	tr.sql_types(types);
764	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
765	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0 &&
766	    rs1 != null && rs1.tr != null && rs1.tr.nrows > 0) {
767	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
768	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
769		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
770	    }
771	    Hashtable<String, Integer> h1 = new Hashtable<String, Integer>();
772	    for (int i = 0; i < rs1.tr.ncolumns; i++) {
773		h1.put(rs1.tr.column[i], Integer.valueOf(i)); // android-changed
774	    }
775	    for (int i = 0; i < rs0.tr.nrows; i++) {
776		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
777		int col = ((Integer) h0.get("unique")).intValue();
778		String uniq = r0[col];
779		col = ((Integer) h0.get("name")).intValue();
780		String iname = r0[col];
781		if (uniq.charAt(0) == '0') {
782		    continue;
783		}
784		JDBCStatement s2 = new JDBCStatement(conn);
785		JDBCResultSet rs2 = null;
786		try {
787		    rs2 = (JDBCResultSet)
788			(s2.executeQuery("PRAGMA index_info(" +
789					 SQLite.Shell.sql_quote(iname) + ")"));
790		} catch (SQLException e) {
791		} finally {
792		    s2.close();
793		}
794		if (rs2 == null || rs2.tr == null || rs2.tr.nrows <= 0) {
795		    continue;
796		}
797		Hashtable<String, Integer> h2 =
798		    new Hashtable<String, Integer>();
799		for (int k = 0; k < rs2.tr.ncolumns; k++) {
800		    h2.put(rs2.tr.column[k], Integer.valueOf(k)); // android-changed
801		}
802		for (int k = 0; k < rs2.tr.nrows; k++) {
803		    String r2[] = (String [])(rs2.tr.rows.elementAt(k));
804		    col = ((Integer) h2.get("name")).intValue();
805		    String cname = r2[col];
806		    for (int m = 0; m < rs1.tr.nrows; m++) {
807			String r1[] = (String [])(rs1.tr.rows.elementAt(m));
808			col = ((Integer) h1.get("name")).intValue();
809			if (cname.compareTo(r1[col]) == 0) {
810			    String row[] = new String[cols.length];
811			    row[0] = "" + scope;
812			    row[1] = cname;
813			    row[2] = "" + Types.VARCHAR;
814			    row[3] = "VARCHAR";
815			    row[4] = "65536";
816			    row[5] = "0";
817			    row[6] = "0";
818			    row[7] = "" + bestRowNotPseudo;
819			    tr.newrow(row);
820			}
821		    }
822		}
823	    }
824	}
825	if (tr.nrows <= 0) {
826	    String row[] = new String[cols.length];
827	    row[0] = "" + scope;
828	    row[1] = "_ROWID_";
829	    row[2] = "" + Types.INTEGER;
830	    row[3] = "INTEGER";
831	    row[4] = "10";
832	    row[5] = "0";
833	    row[6] = "0";
834	    row[7] = "" + bestRowPseudo;
835	    tr.newrow(row);
836	}
837	return rs;
838    }
839
840    public ResultSet getVersionColumns(String catalog, String schema,
841				       String table) throws SQLException {
842	String cols[] = {
843	    "SCOPE", "COLUMN_NAME", "DATA_TYPE",
844	    "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH",
845	    "DECIMAL_DIGITS", "PSEUDO_COLUMN"
846	};
847	int types[] = {
848	    Types.SMALLINT, Types.VARCHAR, Types.SMALLINT,
849	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
850	    Types.SMALLINT, Types.SMALLINT
851	};
852	TableResultX tr = new TableResultX();
853	tr.columns(cols);
854	tr.sql_types(types);
855	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
856	return rs;
857    }
858
859    public ResultSet getPrimaryKeys(String catalog, String schema,
860				    String table) throws SQLException {
861	JDBCStatement s0 = new JDBCStatement(conn);
862	JDBCResultSet rs0 = null;
863	try {
864	    try {
865		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
866	    } catch (SQLite.Exception se) {
867		throw new SQLException("schema reload failed");
868	    }
869	    rs0 = (JDBCResultSet)
870		(s0.executeQuery("PRAGMA index_list(" +
871				 SQLite.Shell.sql_quote(table) + ")"));
872	} catch (SQLException e) {
873	    throw e;
874	} finally {
875	    s0.close();
876	}
877	String cols[] = {
878	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
879	    "COLUMN_NAME", "KEY_SEQ", "PK_NAME"
880	};
881	int types[] = {
882	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
883	    Types.VARCHAR, Types.SMALLINT, Types.VARCHAR
884	};
885	TableResultX tr = new TableResultX();
886	tr.columns(cols);
887	tr.sql_types(types);
888	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
889	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
890	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
891	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
892		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
893	    }
894	    for (int i = 0; i < rs0.tr.nrows; i++) {
895		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
896		int col = ((Integer) h0.get("unique")).intValue();
897		String uniq = r0[col];
898		col = ((Integer) h0.get("name")).intValue();
899		String iname = r0[col];
900		if (uniq.charAt(0) == '0') {
901		    continue;
902		}
903		JDBCStatement s1 = new JDBCStatement(conn);
904		JDBCResultSet rs1 = null;
905		try {
906		    rs1 = (JDBCResultSet)
907			(s1.executeQuery("PRAGMA index_info(" +
908					 SQLite.Shell.sql_quote(iname) + ")"));
909		} catch (SQLException e) {
910		} finally {
911		    s1.close();
912		}
913		if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) {
914		    continue;
915		}
916		Hashtable<String, Integer> h1 =
917		    new Hashtable<String, Integer>();
918		for (int k = 0; k < rs1.tr.ncolumns; k++) {
919		    h1.put(rs1.tr.column[k], Integer.valueOf(k)); // android-changed
920		}
921		for (int k = 0; k < rs1.tr.nrows; k++) {
922		    String r1[] = (String [])(rs1.tr.rows.elementAt(k));
923		    String row[] = new String[cols.length];
924		    row[0]  = "";
925		    row[1]  = "";
926		    row[2]  = table;
927		    col = ((Integer) h1.get("name")).intValue();
928		    row[3] = r1[col];
929		    col = ((Integer) h1.get("seqno")).intValue();
930		    row[4]  = Integer.toString(Integer.parseInt(r1[col]) + 1);
931		    row[5]  = iname;
932		    tr.newrow(row);
933		}
934	    }
935	}
936	if (tr.nrows > 0) {
937	    return rs;
938	}
939	JDBCStatement s1 = new JDBCStatement(conn);
940	try {
941	    rs0 = (JDBCResultSet)
942		(s1.executeQuery("PRAGMA table_info(" +
943				 SQLite.Shell.sql_quote(table) + ")"));
944	} catch (SQLException e) {
945	    throw e;
946	} finally {
947	    s1.close();
948	}
949	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
950	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
951	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
952		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
953	    }
954	    for (int i = 0; i < rs0.tr.nrows; i++) {
955		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
956		int col = ((Integer) h0.get("type")).intValue();
957		String type = r0[col];
958		if (!type.equalsIgnoreCase("integer")) {
959		    continue;
960		}
961		col = ((Integer) h0.get("pk")).intValue();
962		String pk = r0[col];
963		if (pk.charAt(0) == '0') {
964		    continue;
965		}
966		String row[] = new String[cols.length];
967		row[0]  = "";
968		row[1]  = "";
969		row[2]  = table;
970		col = ((Integer) h0.get("name")).intValue();
971		row[3] = r0[col];
972		col = ((Integer) h0.get("cid")).intValue();
973		row[4] = Integer.toString(Integer.parseInt(r0[col]) + 1);
974		row[5] = "";
975		tr.newrow(row);
976	    }
977	}
978	return rs;
979    }
980
981    private void internalImportedKeys(String table, String pktable,
982				      JDBCResultSet in, TableResultX out) {
983	Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
984	for (int i = 0; i < in.tr.ncolumns; i++) {
985	    h0.put(in.tr.column[i], Integer.valueOf(i)); // android-changed
986	}
987	for (int i = 0; i < in.tr.nrows; i++) {
988	    String r0[] = (String [])(in.tr.rows.elementAt(i));
989	    int col = ((Integer) h0.get("table")).intValue();
990	    String pktab = r0[col];
991	    if (pktable != null && !pktable.equalsIgnoreCase(pktab)) {
992		continue;
993	    }
994	    col = ((Integer) h0.get("from")).intValue();
995	    String fkcol = r0[col];
996	    col = ((Integer) h0.get("to")).intValue();
997	    String pkcol = r0[col];
998	    col = ((Integer) h0.get("seq")).intValue();
999	    String seq = r0[col];
1000	    String row[] = new String[out.ncolumns];
1001	    row[0]  = "";
1002	    row[1]  = "";
1003	    row[2]  = pktab;
1004	    row[3]  = pkcol;
1005	    row[4]  = "";
1006	    row[5]  = "";
1007	    row[6]  = table;
1008	    row[7]  = fkcol == null ? pkcol : fkcol;
1009	    row[8]  = Integer.toString(Integer.parseInt(seq) + 1);
1010	    row[9]  =
1011		"" + java.sql.DatabaseMetaData.importedKeyNoAction;
1012	    row[10] =
1013		"" + java.sql.DatabaseMetaData.importedKeyNoAction;
1014	    row[11] = null;
1015	    row[12] = null;
1016	    row[13] =
1017		"" + java.sql.DatabaseMetaData.importedKeyNotDeferrable;
1018	    out.newrow(row);
1019	}
1020    }
1021
1022    public ResultSet getImportedKeys(String catalog, String schema,
1023				     String table) throws SQLException {
1024	JDBCStatement s0 = new JDBCStatement(conn);
1025	JDBCResultSet rs0 = null;
1026	try {
1027	    try {
1028		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
1029	    } catch (SQLite.Exception se) {
1030		throw new SQLException("schema reload failed");
1031	    }
1032	    rs0 = (JDBCResultSet)
1033		(s0.executeQuery("PRAGMA foreign_key_list(" +
1034				 SQLite.Shell.sql_quote(table) + ")"));
1035	} catch (SQLException e) {
1036	    throw e;
1037	} finally {
1038	    s0.close();
1039	}
1040	String cols[] = {
1041	    "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME",
1042	    "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM",
1043	    "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ",
1044	    "UPDATE_RULE", "DELETE_RULE", "FK_NAME",
1045	    "PK_NAME", "DEFERRABILITY"
1046	};
1047	int types[] = {
1048	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1049	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1050	    Types.VARCHAR, Types.VARCHAR, Types.SMALLINT,
1051	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1052	    Types.VARCHAR, Types.SMALLINT
1053	};
1054	TableResultX tr = new TableResultX();
1055	tr.columns(cols);
1056	tr.sql_types(types);
1057	JDBCResultSet rs = new JDBCResultSet((SQLite.TableResult) tr, null);
1058	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
1059	    internalImportedKeys(table, null, rs0, tr);
1060	}
1061	return rs;
1062    }
1063
1064    public ResultSet getExportedKeys(String catalog, String schema,
1065				     String table) throws SQLException {
1066	String cols[] = {
1067	    "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME",
1068	    "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM",
1069	    "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ",
1070	    "UPDATE_RULE", "DELETE_RULE", "FK_NAME",
1071	    "PK_NAME", "DEFERRABILITY"
1072	};
1073	int types[] = {
1074	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1075	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1076	    Types.VARCHAR, Types.VARCHAR, Types.SMALLINT,
1077	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1078	    Types.VARCHAR, Types.SMALLINT
1079	};
1080	TableResultX tr = new TableResultX();
1081	tr.columns(cols);
1082	tr.sql_types(types);
1083	JDBCResultSet rs = new JDBCResultSet(tr, null);
1084	return rs;
1085    }
1086
1087    public ResultSet getCrossReference(String primaryCatalog,
1088				       String primarySchema,
1089				       String primaryTable,
1090				       String foreignCatalog,
1091				       String foreignSchema,
1092				       String foreignTable)
1093	throws SQLException {
1094	JDBCResultSet rs0 = null;
1095	if (foreignTable != null && foreignTable.charAt(0) != '%') {
1096	    JDBCStatement s0 = new JDBCStatement(conn);
1097	    try {
1098		try {
1099		    conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
1100		} catch (SQLite.Exception se) {
1101		    throw new SQLException("schema reload failed");
1102		}
1103		rs0 = (JDBCResultSet)
1104		    (s0.executeQuery("PRAGMA foreign_key_list(" +
1105				     SQLite.Shell.sql_quote(foreignTable) + ")"));
1106	    } catch (SQLException e) {
1107		throw e;
1108	    } finally {
1109		s0.close();
1110	    }
1111	}
1112	String cols[] = {
1113	    "PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME",
1114	    "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM",
1115	    "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ",
1116	    "UPDATE_RULE", "DELETE_RULE", "FK_NAME",
1117	    "PK_NAME", "DEFERRABILITY"
1118	};
1119	int types[] = {
1120	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1121	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1122	    Types.VARCHAR, Types.VARCHAR, Types.SMALLINT,
1123	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1124	    Types.VARCHAR, Types.SMALLINT
1125	};
1126	TableResultX tr = new TableResultX();
1127	tr.columns(cols);
1128	tr.sql_types(types);
1129	JDBCResultSet rs = new JDBCResultSet(tr, null);
1130	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
1131	    String pktable = null;
1132	    if (primaryTable != null && primaryTable.charAt(0) != '%') {
1133		pktable = primaryTable;
1134	    }
1135	    internalImportedKeys(foreignTable, pktable, rs0, tr);
1136	}
1137	return rs;
1138    }
1139
1140    public ResultSet getTypeInfo() throws SQLException {
1141	String cols[] = {
1142	    "TYPE_NAME", "DATA_TYPE", "PRECISION",
1143	    "LITERAL_PREFIX", "LITERAL_SUFFIX", "CREATE_PARAMS",
1144	    "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE",
1145	    "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT",
1146	    "LOCAL_TYPE_NAME", "MINIMUM_SCALE", "MAXIMUM_SCALE",
1147	    "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"
1148	};
1149	int types[] = {
1150	    Types.VARCHAR, Types.SMALLINT, Types.INTEGER,
1151	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1152	    Types.SMALLINT, Types.BIT, Types.SMALLINT,
1153	    Types.BIT, Types.BIT, Types.BIT,
1154	    Types.VARCHAR, Types.SMALLINT, Types.SMALLINT,
1155	    Types.INTEGER, Types.INTEGER, Types.INTEGER
1156	};
1157	TableResultX tr = new TableResultX();
1158	tr.columns(cols);
1159	tr.sql_types(types);
1160	JDBCResultSet rs = new JDBCResultSet(tr, null);
1161	String row1[] = {
1162	    "VARCHAR", "" + Types.VARCHAR, "65536",
1163	    "'", "'", null,
1164	    "" + typeNullable, "1", "" + typeSearchable,
1165	    "0", "0", "0",
1166	    null, "0", "0",
1167	    "0", "0", "0"
1168	};
1169	tr.newrow(row1);
1170	String row2[] = {
1171	    "INTEGER", "" + Types.INTEGER, "32",
1172	    null, null, null,
1173	    "" + typeNullable, "0", "" + typeSearchable,
1174	    "0", "0", "1",
1175	    null, "0", "0",
1176	    "0", "0", "2"
1177	};
1178	tr.newrow(row2);
1179	String row3[] = {
1180	    "DOUBLE", "" + Types.DOUBLE, "16",
1181	    null, null, null,
1182	    "" + typeNullable, "0", "" + typeSearchable,
1183	    "0", "0", "1",
1184	    null, "0", "0",
1185	    "0", "0", "10"
1186	};
1187	tr.newrow(row3);
1188	String row4[] = {
1189	    "FLOAT", "" + Types.FLOAT, "7",
1190	    null, null, null,
1191	    "" + typeNullable, "0", "" + typeSearchable,
1192	    "0", "0", "1",
1193	    null, "0", "0",
1194	    "0", "0", "10"
1195	};
1196	tr.newrow(row4);
1197	String row5[] = {
1198	    "SMALLINT", "" + Types.SMALLINT, "16",
1199	    null, null, null,
1200	    "" + typeNullable, "0", "" + typeSearchable,
1201	    "0", "0", "1",
1202	    null, "0", "0",
1203	    "0", "0", "2"
1204	};
1205	tr.newrow(row5);
1206	String row6[] = {
1207	    "BIT", "" + Types.BIT, "1",
1208	    null, null, null,
1209	    "" + typeNullable, "0", "" + typeSearchable,
1210	    "0", "0", "1",
1211	    null, "0", "0",
1212	    "0", "0", "2"
1213	};
1214	tr.newrow(row6);
1215	String row7[] = {
1216	    "TIMESTAMP", "" + Types.TIMESTAMP, "30",
1217	    null, null, null,
1218	    "" + typeNullable, "0", "" + typeSearchable,
1219	    "0", "0", "1",
1220	    null, "0", "0",
1221	    "0", "0", "0"
1222	};
1223	tr.newrow(row7);
1224	String row8[] = {
1225	    "DATE", "" + Types.DATE, "10",
1226	    null, null, null,
1227	    "" + typeNullable, "0", "" + typeSearchable,
1228	    "0", "0", "1",
1229	    null, "0", "0",
1230	    "0", "0", "0"
1231	};
1232	tr.newrow(row8);
1233	String row9[] = {
1234	    "TIME", "" + Types.TIME, "8",
1235	    null, null, null,
1236	    "" + typeNullable, "0", "" + typeSearchable,
1237	    "0", "0", "1",
1238	    null, "0", "0",
1239	    "0", "0", "0"
1240	};
1241	tr.newrow(row9);
1242	String row10[] = {
1243	    "BINARY", "" + Types.BINARY, "65536",
1244	    null, null, null,
1245	    "" + typeNullable, "0", "" + typeSearchable,
1246	    "0", "0", "1",
1247	    null, "0", "0",
1248	    "0", "0", "0"
1249	};
1250	tr.newrow(row10);
1251	String row11[] = {
1252	    "VARBINARY", "" + Types.VARBINARY, "65536",
1253	    null, null, null,
1254	    "" + typeNullable, "0", "" + typeSearchable,
1255	    "0", "0", "1",
1256	    null, "0", "0",
1257	    "0", "0", "0"
1258	};
1259	tr.newrow(row11);
1260	String row12[] = {
1261	    "REAL", "" + Types.REAL, "16",
1262	    null, null, null,
1263	    "" + typeNullable, "0", "" + typeSearchable,
1264	    "0", "0", "1",
1265	    null, "0", "0",
1266	    "0", "0", "10"
1267	};
1268	tr.newrow(row12);
1269	return rs;
1270    }
1271
1272    public ResultSet getIndexInfo(String catalog, String schema, String table,
1273				  boolean unique, boolean approximate)
1274	throws SQLException {
1275	JDBCStatement s0 = new JDBCStatement(conn);
1276	JDBCResultSet rs0 = null;
1277	try {
1278	    try {
1279		conn.db.exec("SELECT 1 FROM sqlite_master LIMIT 1", null);
1280	    } catch (SQLite.Exception se) {
1281		throw new SQLException("schema reload failed");
1282	    }
1283	    rs0 = (JDBCResultSet)
1284		(s0.executeQuery("PRAGMA index_list(" +
1285				 SQLite.Shell.sql_quote(table) + ")"));
1286	} catch (SQLException e) {
1287	    throw e;
1288	} finally {
1289	    s0.close();
1290	}
1291	String cols[] = {
1292	    "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
1293	    "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME",
1294	    "TYPE", "ORDINAL_POSITION", "COLUMN_NAME",
1295	    "ASC_OR_DESC", "CARDINALITY", "PAGES",
1296	    "FILTER_CONDITION"
1297	};
1298	int types[] = {
1299	    Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1300	    Types.BIT, Types.VARCHAR, Types.VARCHAR,
1301	    Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
1302	    Types.VARCHAR, Types.INTEGER, Types.INTEGER,
1303	    Types.VARCHAR
1304	};
1305	TableResultX tr = new TableResultX();
1306	tr.columns(cols);
1307	tr.sql_types(types);
1308	JDBCResultSet rs = new JDBCResultSet(tr, null);
1309	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
1310	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
1311	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
1312		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
1313	    }
1314	    for (int i = 0; i < rs0.tr.nrows; i++) {
1315		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
1316		int col = ((Integer) h0.get("unique")).intValue();
1317		String uniq = r0[col];
1318		col = ((Integer) h0.get("name")).intValue();
1319		String iname = r0[col];
1320		if (unique && uniq.charAt(0) == '0') {
1321		    continue;
1322		}
1323		JDBCStatement s1 = new JDBCStatement(conn);
1324		JDBCResultSet rs1 = null;
1325		try {
1326		    rs1 = (JDBCResultSet)
1327			(s1.executeQuery("PRAGMA index_info(" +
1328					 SQLite.Shell.sql_quote(iname) + ")"));
1329		} catch (SQLException e) {
1330		} finally {
1331		    s1.close();
1332		}
1333		if (rs1 == null || rs1.tr == null || rs1.tr.nrows <= 0) {
1334		    continue;
1335		}
1336		Hashtable<String, Integer> h1 =
1337		    new Hashtable<String, Integer>();
1338		for (int k = 0; k < rs1.tr.ncolumns; k++) {
1339		    h1.put(rs1.tr.column[k], Integer.valueOf(k)); // android-changed
1340		}
1341		for (int k = 0; k < rs1.tr.nrows; k++) {
1342		    String r1[] = (String [])(rs1.tr.rows.elementAt(k));
1343		    String row[] = new String[cols.length];
1344		    row[0]  = "";
1345		    row[1]  = "";
1346		    row[2]  = table;
1347		    row[3]  = (uniq.charAt(0) != '0' ||
1348			(iname.charAt(0) == '(' &&
1349			 iname.indexOf(" autoindex ") > 0)) ? "0" : "1";
1350		    row[4]  = "";
1351		    row[5]  = iname;
1352		    row[6]  = "" + tableIndexOther;
1353		    col = ((Integer) h1.get("seqno")).intValue();
1354		    row[7]  = Integer.toString(Integer.parseInt(r1[col]) + 1);
1355		    col = ((Integer) h1.get("name")).intValue();
1356		    row[8]  = r1[col];
1357		    row[9]  = "A";
1358		    row[10] = "0";
1359		    row[11] = "0";
1360		    row[12] = null;
1361		    tr.newrow(row);
1362		}
1363	    }
1364	}
1365	return rs;
1366    }
1367
1368    public boolean supportsResultSetType(int type) throws SQLException {
1369	return type == ResultSet.TYPE_FORWARD_ONLY ||
1370	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1371	    type == ResultSet.TYPE_SCROLL_SENSITIVE;
1372    }
1373
1374    public boolean supportsResultSetConcurrency(int type, int concurrency)
1375	throws SQLException {
1376	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1377	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1378	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1379	    return concurrency == ResultSet.CONCUR_READ_ONLY ||
1380		concurrency == ResultSet.CONCUR_UPDATABLE;
1381	}
1382	return false;
1383    }
1384
1385    public boolean ownUpdatesAreVisible(int type) throws SQLException {
1386	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1387	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1388	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1389	    return true;
1390	}
1391	return false;
1392    }
1393
1394    public boolean ownDeletesAreVisible(int type) throws SQLException {
1395	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1396	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1397	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1398	    return true;
1399	}
1400	return false;
1401    }
1402
1403    public boolean ownInsertsAreVisible(int type) throws SQLException {
1404	if (type == ResultSet.TYPE_FORWARD_ONLY ||
1405	    type == ResultSet.TYPE_SCROLL_INSENSITIVE ||
1406	    type == ResultSet.TYPE_SCROLL_SENSITIVE) {
1407	    return true;
1408	}
1409	return false;
1410    }
1411
1412    public boolean othersUpdatesAreVisible(int type) throws SQLException {
1413	return false;
1414    }
1415
1416    public boolean othersDeletesAreVisible(int type) throws SQLException {
1417	return false;
1418    }
1419
1420    public boolean othersInsertsAreVisible(int type) throws SQLException {
1421	return false;
1422    }
1423
1424    public boolean updatesAreDetected(int type) throws SQLException {
1425	return false;
1426    }
1427
1428    public boolean deletesAreDetected(int type) throws SQLException {
1429	return false;
1430    }
1431
1432    public boolean insertsAreDetected(int type) throws SQLException {
1433	return false;
1434    }
1435
1436    public boolean supportsBatchUpdates() throws SQLException {
1437	return true;
1438    }
1439
1440    public ResultSet getUDTs(String catalog, String schemaPattern,
1441		      String typeNamePattern, int[] types)
1442	throws SQLException {
1443	return null;
1444    }
1445
1446    public Connection getConnection() throws SQLException {
1447	return conn;
1448    }
1449
1450    static String mapTypeName(int type) {
1451	switch (type) {
1452	case Types.INTEGER:	return "integer";
1453	case Types.SMALLINT:	return "smallint";
1454	case Types.FLOAT:	return "float";
1455	case Types.DOUBLE:	return "double";
1456	case Types.TIMESTAMP:	return "timestamp";
1457	case Types.DATE:	return "date";
1458	case Types.TIME:	return "time";
1459	case Types.BINARY:	return "binary";
1460	case Types.VARBINARY:	return "varbinary";
1461	case Types.REAL:	return "real";
1462	}
1463	return "varchar";
1464    }
1465
1466    static int mapSqlType(String type) {
1467	if (type == null) {
1468	    return Types.VARCHAR;
1469	}
1470	type = type.toLowerCase();
1471	if (type.startsWith("inter")) {
1472	    return Types.VARCHAR;
1473	}
1474	if (type.startsWith("numeric") ||
1475	    type.startsWith("int")) {
1476	    return Types.INTEGER;
1477	}
1478	if (type.startsWith("tinyint") ||
1479	    type.startsWith("smallint")) {
1480	    return Types.SMALLINT;
1481	}
1482	if (type.startsWith("float")) {
1483	    return Types.FLOAT;
1484	}
1485	if (type.startsWith("double")) {
1486	    return Types.DOUBLE;
1487	}
1488	if (type.startsWith("datetime") ||
1489	    type.startsWith("timestamp")) {
1490	    return Types.TIMESTAMP;
1491	}
1492	if (type.startsWith("date")) {
1493	    return Types.DATE;
1494	}
1495	if (type.startsWith("time")) {
1496	    return Types.TIME;
1497	}
1498	if (type.startsWith("blob")) {
1499	    return Types.BINARY;
1500	}
1501	if (type.startsWith("binary")) {
1502	    return Types.BINARY;
1503	}
1504	if (type.startsWith("varbinary")) {
1505	    return Types.VARBINARY;
1506	}
1507	if (type.startsWith("real")) {
1508	    return Types.REAL;
1509	}
1510	return Types.VARCHAR;
1511    }
1512
1513    static int getM(String typeStr, int type) {
1514	int m = 65536;
1515	switch (type) {
1516	case Types.INTEGER:	m = 11; break;
1517	case Types.SMALLINT:	m = 6;  break;
1518	case Types.FLOAT:	m = 25; break;
1519	case Types.REAL:
1520	case Types.DOUBLE:	m = 54; break;
1521	case Types.TIMESTAMP:	return 30;
1522	case Types.DATE:	return 10;
1523	case Types.TIME:	return 8;
1524	}
1525	typeStr = typeStr.toLowerCase();
1526	int i1 = typeStr.indexOf('(');
1527	if (i1 > 0) {
1528	    ++i1;
1529	    int i2 = typeStr.indexOf(',', i1);
1530	    if (i2 < 0) {
1531		i2 = typeStr.indexOf(')', i1);
1532	    }
1533	    if (i2 - i1 > 0) {
1534		String num = typeStr.substring(i1, i2);
1535		try {
1536		    m = java.lang.Integer.parseInt(num, 10);
1537		} catch (NumberFormatException e) {
1538		}
1539	    }
1540	}
1541	return m;
1542    }
1543
1544    static int getD(String typeStr, int type) {
1545	int d = 0;
1546	switch (type) {
1547	case Types.INTEGER:	d = 10; break;
1548	case Types.SMALLINT:	d = 5;  break;
1549	case Types.FLOAT:	d = 24; break;
1550	case Types.REAL:
1551	case Types.DOUBLE:	d = 53; break;
1552	default:		return getM(typeStr, type);
1553	}
1554	typeStr = typeStr.toLowerCase();
1555	int i1 = typeStr.indexOf('(');
1556	if (i1 > 0) {
1557	    ++i1;
1558	    int i2 = typeStr.indexOf(',', i1);
1559	    if (i2 < 0) {
1560		return getM(typeStr, type);
1561	    }
1562	    i1 = i2;
1563	    i2 = typeStr.indexOf(')', i1);
1564	    if (i2 - i1 > 0) {
1565		String num = typeStr.substring(i1, i2);
1566		try {
1567		    d = java.lang.Integer.parseInt(num, 10);
1568		} catch (NumberFormatException e) {
1569		}
1570	    }
1571	}
1572	return d;
1573    }
1574
1575    public boolean supportsSavepoints() {
1576	return false;
1577    }
1578
1579    public boolean supportsNamedParameters() {
1580	return false;
1581    }
1582
1583    public boolean supportsMultipleOpenResults() {
1584	return false;
1585    }
1586
1587    public boolean supportsGetGeneratedKeys() {
1588	return false;
1589    }
1590
1591    public boolean supportsResultSetHoldability(int x) {
1592	return false;
1593    }
1594
1595    public boolean supportsStatementPooling() {
1596	return false;
1597    }
1598
1599    public boolean locatorsUpdateCopy() throws SQLException {
1600	throw new SQLException("not supported");
1601    }
1602
1603    public ResultSet getSuperTypes(String catalog, String schemaPattern,
1604			    String typeNamePattern)
1605	throws SQLException {
1606	throw new SQLException("not supported");
1607    }
1608
1609    public ResultSet getSuperTables(String catalog, String schemaPattern,
1610				    String tableNamePattern)
1611	throws SQLException {
1612	throw new SQLException("not supported");
1613    }
1614
1615    public ResultSet getAttributes(String catalog, String schemaPattern,
1616				   String typeNamePattern,
1617				   String attributeNamePattern)
1618	throws SQLException {
1619	throw new SQLException("not supported");
1620    }
1621
1622    public int getResultSetHoldability() throws SQLException {
1623	return ResultSet.HOLD_CURSORS_OVER_COMMIT;
1624    }
1625
1626    public int getDatabaseMajorVersion() {
1627	return SQLite.JDBCDriver.MAJORVERSION;
1628    }
1629
1630    public int getDatabaseMinorVersion() {
1631	return SQLite.Constants.drv_minor;
1632    }
1633
1634    public int getJDBCMajorVersion() {
1635	return 1;
1636    }
1637
1638    public int getJDBCMinorVersion() {
1639	return 0;
1640    }
1641
1642    public int getSQLStateType() throws SQLException {
1643	return sqlStateXOpen;
1644    }
1645
1646    public RowIdLifetime getRowIdLifetime() throws SQLException {
1647	return RowIdLifetime.ROWID_UNSUPPORTED;
1648    }
1649
1650    public ResultSet getSchemas(String cat, String schema)
1651	throws SQLException {
1652	throw new SQLException("not supported");
1653    }
1654
1655    public boolean supportsStoredFunctionsUsingCallSyntax()
1656	throws SQLException {
1657	return false;
1658    }
1659
1660    public boolean autoCommitFailureClosesAllResultSets()
1661	throws SQLException {
1662	return false;
1663    }
1664
1665    public ResultSet getClientInfoProperties() throws SQLException {
1666	throw new SQLException("unsupported");
1667    }
1668
1669    public ResultSet getFunctions(String cat, String schema, String func)
1670	throws SQLException {
1671	throw new SQLException("unsupported");
1672    }
1673
1674    public ResultSet getFunctionColumns(String cat, String schema,
1675					String func, String colpat)
1676	throws SQLException {
1677	throw new SQLException("unsupported");
1678    }
1679
1680    public <T> T unwrap(java.lang.Class<T> iface) throws SQLException {
1681	throw new SQLException("unsupported");
1682    }
1683
1684    public boolean isWrapperFor(java.lang.Class iface) throws SQLException {
1685	return false;
1686    }
1687
1688}
1689