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