Home | History | Annotate | Download | only in JDBC2z
      1 package SQLite.JDBC2z;
      2 
      3 import java.sql.*;
      4 import java.util.Hashtable;
      5 
      6 public 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