http://git-wip-us.apache.org/repos/asf/ignite/blob/ebb9e2e9/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java new file mode 100644 index 0000000..98a2563 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java @@ -0,0 +1,1401 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.jdbc2; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.RowIdLifetime; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; +import org.apache.ignite.internal.processors.cache.query.GridCacheSqlIndexMetadata; +import org.apache.ignite.internal.processors.cache.query.GridCacheSqlMetadata; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.resources.IgniteInstanceResource; + +import static java.sql.Connection.TRANSACTION_NONE; +import static java.sql.ResultSet.CONCUR_READ_ONLY; +import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT; +import static java.sql.RowIdLifetime.ROWID_UNSUPPORTED; + +/** + * JDBC database metadata implementation. + */ +public class JdbcDatabaseMetadata implements DatabaseMetaData { + /** Connection. */ + private final JdbcConnection conn; + + /** Metadata. */ + private Map<String, Map<String, Map<String, String>>> meta; + + /** Index info. */ + private Collection<List<Object>> indexes; + + /** + * @param conn Connection. + */ + JdbcDatabaseMetadata(JdbcConnection conn) { + this.conn = conn; + } + + /** {@inheritDoc} */ + @Override public boolean allProceduresAreCallable() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean allTablesAreSelectable() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public String getURL() throws SQLException { + return conn.url(); + } + + /** {@inheritDoc} */ + @Override public String getUserName() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public boolean isReadOnly() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean nullsAreSortedLow() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean nullsAreSortedAtEnd() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public String getDatabaseProductName() throws SQLException { + return "Ignite Cache"; + } + + /** {@inheritDoc} */ + @Override public String getDatabaseProductVersion() throws SQLException { + return "4.1.0"; + } + + /** {@inheritDoc} */ + @Override public String getDriverName() throws SQLException { + return "Ignite JDBC Driver"; + } + + /** {@inheritDoc} */ + @Override public String getDriverVersion() throws SQLException { + return "1.0"; + } + + /** {@inheritDoc} */ + @Override public int getDriverMajorVersion() { + return 1; + } + + /** {@inheritDoc} */ + @Override public int getDriverMinorVersion() { + return 0; + } + + /** {@inheritDoc} */ + @Override public boolean usesLocalFiles() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsMixedCaseIdentifiers() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean storesUpperCaseIdentifiers() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean storesLowerCaseIdentifiers() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean storesMixedCaseIdentifiers() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public String getIdentifierQuoteString() throws SQLException { + return " "; + } + + /** {@inheritDoc} */ + @Override public String getSQLKeywords() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getNumericFunctions() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getStringFunctions() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getSystemFunctions() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getTimeDateFunctions() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getSearchStringEscape() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getExtraNameCharacters() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsColumnAliasing() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean nullPlusNonNullIsNull() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsConvert() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsTableCorrelationNames() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsExpressionsInOrderBy() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsOrderByUnrelated() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsGroupBy() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsGroupByUnrelated() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsGroupByBeyondSelect() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsLikeEscapeClause() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsMultipleTransactions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsNonNullableColumns() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsMinimumSQLGrammar() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsOuterJoins() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsFullOuterJoins() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsLimitedOuterJoins() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public String getSchemaTerm() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getProcedureTerm() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public String getCatalogTerm() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public boolean isCatalogAtStart() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public String getCatalogSeparator() throws SQLException { + return ""; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSelectForUpdate() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsStoredProcedures() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSubqueriesInComparisons() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSubqueriesInExists() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSubqueriesInIns() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsCorrelatedSubqueries() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsUnion() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsUnionAll() throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public int getMaxBinaryLiteralLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxCharLiteralLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxColumnNameLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxColumnsInGroupBy() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxColumnsInIndex() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxColumnsInOrderBy() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxColumnsInSelect() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxConnections() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxCursorNameLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxIndexLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxProcedureNameLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxCatalogNameLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxRowSize() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public int getMaxStatementLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxStatements() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxTableNameLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxTablesInSelect() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getMaxUserNameLength() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getDefaultTransactionIsolation() throws SQLException { + return TRANSACTION_NONE; + } + + /** {@inheritDoc} */ + @Override public boolean supportsTransactions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public ResultSet getProcedures(String catalog, String schemaPtrn, + String procedureNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("PROCEDURE_CAT", "PROCEDURE_SCHEM", "PROCEDURE_NAME", + "REMARKS", "PROCEDURE_TYPE", "SPECIFIC_NAME"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), Short.class.getName(), String.class.getName()), + Collections.<List<?>>emptyList(), true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getProcedureColumns(String catalog, String schemaPtrn, String procedureNamePtrn, + String colNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("PROCEDURE_CAT", "PROCEDURE_SCHEM", "PROCEDURE_NAME", + "COLUMN_NAME", "COLUMN_TYPE", "DATA_TYPE", "TYPE_NAME", "PRECISION", + "LENGTH", "SCALE", "RADIX", "NULLABLE", "REMARKS", "COLUMN_DEF", + "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", "IS_NULLABLE", "SPECIFIC_NAME"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), Short.class.getName(), Integer.class.getName(), String.class.getName(), + Integer.class.getName(), Integer.class.getName(), Short.class.getName(), Short.class.getName(), + Short.class.getName(), String.class.getName(), String.class.getName(), Integer.class.getName(), + Integer.class.getName(), Integer.class.getName(), Integer.class.getName(), String.class.getName(), + String.class.getName()), + Collections.<List<?>>emptyList(), true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getTables(String catalog, String schemaPtrn, String tblNamePtrn, + String[] tblTypes) throws SQLException { + updateMetaData(); + + List<List<?>> rows = new LinkedList<>(); + + if (tblTypes == null || Arrays.asList(tblTypes).contains("TABLE")) + for (Map.Entry<String, Map<String, Map<String, String>>> schema : meta.entrySet()) + if (matches(schema.getKey(), schemaPtrn)) + for (String tbl : schema.getValue().keySet()) + if (matches(tbl, tblNamePtrn)) + rows.add(tableRow(schema.getKey(), tbl)); + + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", "TYPE_CAT", + "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", "REF_GENERATION"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), String.class.getName(), String.class.getName()), + rows, true + ); + } + + /** + * @param schema Schema name. + * @param tbl Table name. + * @return Table metadata row. + */ + private List<Object> tableRow(String schema, String tbl) { + List<Object> row = new ArrayList<>(10); + + row.add(null); + row.add(schema); + row.add(tbl.toUpperCase()); + row.add("TABLE"); + row.add(null); + row.add(null); + row.add(null); + row.add(null); + row.add(null); + row.add(null); + + return row; + } + + /** {@inheritDoc} */ + @Override public ResultSet getSchemas() throws SQLException { + return getSchemas(null, "%"); + } + + /** {@inheritDoc} */ + @Override public ResultSet getCatalogs() throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.singletonList("TABLE_CAT"), + Collections.singletonList(String.class.getName()), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getTableTypes() throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.singletonList("TABLE_TYPE"), + Collections.singletonList(String.class.getName()), + Collections.<List<?>>singletonList(Collections.singletonList("TABLE")), + true); + } + + /** {@inheritDoc} */ + @Override public ResultSet getColumns(String catalog, String schemaPtrn, String tblNamePtrn, + String colNamePtrn) throws SQLException { + updateMetaData(); + + List<List<?>> rows = new LinkedList<>(); + + int cnt = 0; + + for (Map.Entry<String, Map<String, Map<String, String>>> schema : meta.entrySet()) + if (matches(schema.getKey(), schemaPtrn)) + for (Map.Entry<String, Map<String, String>> tbl : schema.getValue().entrySet()) + if (matches(tbl.getKey(), tblNamePtrn)) + for (Map.Entry<String, String> col : tbl.getValue().entrySet()) + rows.add(columnRow(schema.getKey(), tbl.getKey(), col.getKey(), + JdbcUtils.type(col.getValue()), JdbcUtils.typeName(col.getValue()), + JdbcUtils.nullable(col.getKey(), col.getValue()), ++cnt)); + + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", + "TYPE_NAME", "COLUMN_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", + "REMARKS", "COLUMN_DEF", "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE", + "SCOPE_CATLOG", "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), Integer.class.getName(), String.class.getName(), Integer.class.getName(), + Integer.class.getName(), Integer.class.getName(), Integer.class.getName(), String.class.getName(), + String.class.getName(), Integer.class.getName(), Integer.class.getName(), String.class.getName(), + String.class.getName(), String.class.getName(), String.class.getName(), Short.class.getName(), + String.class.getName()), + rows, true + ); + } + + /** + * @param schema Schema name. + * @param tbl Table name. + * @param col Column name. + * @param type Type. + * @param typeName Type name. + * @param nullable Nullable flag. + * @param pos Ordinal position. + * @return Column metadata row. + */ + private List<Object> columnRow(String schema, String tbl, String col, int type, String typeName, + boolean nullable, int pos) { + List<Object> row = new ArrayList<>(20); + + row.add(null); + row.add(schema); + row.add(tbl); + row.add(col); + row.add(type); + row.add(typeName); + row.add(null); + row.add(null); + row.add(10); + row.add(nullable ? columnNullable : columnNoNulls); + row.add(null); + row.add(null); + row.add(Integer.MAX_VALUE); + row.add(pos); + row.add("YES"); + row.add(null); + row.add(null); + row.add(null); + row.add(null); + row.add("NO"); + + return row; + } + + /** {@inheritDoc} */ + @Override public ResultSet getColumnPrivileges(String catalog, String schema, String tbl, + String colNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getTablePrivileges(String catalog, String schemaPtrn, + String tblNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getBestRowIdentifier(String catalog, String schema, String tbl, int scope, + boolean nullable) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getVersionColumns(String catalog, String schema, String tbl) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getPrimaryKeys(String catalog, String schema, String tbl) throws SQLException { + updateMetaData(); + + List<List<?>> rows = new LinkedList<>(); + + for (Map.Entry<String, Map<String, Map<String, String>>> s : meta.entrySet()) + if (schema == null || schema.toUpperCase().equals(s.getKey())) + for (Map.Entry<String, Map<String, String>> t : s.getValue().entrySet()) + if (tbl == null || tbl.toUpperCase().equals(t.getKey())) + rows.add(Arrays.<Object>asList(null, s.getKey().toUpperCase(), + t.getKey().toUpperCase(), "_KEY", 1, "_KEY")); + + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), Short.class.getName(), String.class.getName()), + rows, true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getImportedKeys(String catalog, String schema, String tbl) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getExportedKeys(String catalog, String schema, String tbl) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTbl, + String foreignCatalog, String foreignSchema, String foreignTbl) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getTypeInfo() throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getIndexInfo(String catalog, String schema, String tbl, boolean unique, + boolean approximate) throws SQLException { + Collection<List<?>> rows = new ArrayList<>(indexes.size()); + + for (List<Object> idx : indexes) { + String idxSchema = (String)idx.get(0); + String idxTbl = (String)idx.get(1); + + if ((schema == null || schema.equals(idxSchema)) && (tbl == null || tbl.equals(idxTbl))) { + List<Object> row = new ArrayList<>(13); + + row.add(null); + row.add(idxSchema); + row.add(idxTbl); + row.add(idx.get(2)); + row.add(null); + row.add(idx.get(3)); + row.add((int)tableIndexOther); + row.add(idx.get(4)); + row.add(idx.get(5)); + row.add((Boolean)idx.get(6) ? "D" : "A"); + row.add(0); + row.add(0); + row.add(null); + + rows.add(row); + } + } + + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "NON_UNIQUE", "INDEX_QUALIFIER", + "INDEX_NAME", "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC", "CARDINALITY", + "PAGES", "FILTER_CONDITION"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + Boolean.class.getName(), String.class.getName(), String.class.getName(), Short.class.getName(), + Short.class.getName(), String.class.getName(), String.class.getName(), Integer.class.getName(), + Integer.class.getName(), String.class.getName()), + rows, true + ); + } + + /** {@inheritDoc} */ + @Override public boolean supportsResultSetType(int type) throws SQLException { + return true; + } + + /** {@inheritDoc} */ + @Override public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return concurrency == CONCUR_READ_ONLY; + } + + /** {@inheritDoc} */ + @Override public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsBatchUpdates() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public ResultSet getUDTs(String catalog, String schemaPtrn, String typeNamePtrn, + int[] types) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public Connection getConnection() throws SQLException { + return conn; + } + + /** {@inheritDoc} */ + @Override public boolean supportsSavepoints() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsNamedParameters() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsMultipleOpenResults() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsGetGeneratedKeys() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public ResultSet getSuperTypes(String catalog, String schemaPtrn, + String typeNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getSuperTables(String catalog, String schemaPtrn, + String tblNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getAttributes(String catalog, String schemaPtrn, String typeNamePtrn, + String attributeNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return holdability == HOLD_CURSORS_OVER_COMMIT; + } + + /** {@inheritDoc} */ + @Override public int getResultSetHoldability() throws SQLException { + return HOLD_CURSORS_OVER_COMMIT; + } + + /** {@inheritDoc} */ + @Override public int getDatabaseMajorVersion() throws SQLException { + return 1; + } + + /** {@inheritDoc} */ + @Override public int getDatabaseMinorVersion() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getJDBCMajorVersion() throws SQLException { + return 1; + } + + /** {@inheritDoc} */ + @Override public int getJDBCMinorVersion() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public int getSQLStateType() throws SQLException { + return 0; + } + + /** {@inheritDoc} */ + @Override public boolean locatorsUpdateCopy() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean supportsStatementPooling() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public RowIdLifetime getRowIdLifetime() throws SQLException { + return ROWID_UNSUPPORTED; + } + + /** {@inheritDoc} */ + @Override public ResultSet getSchemas(String catalog, String schemaPtrn) throws SQLException { + updateMetaData(); + + List<List<?>> rows = new ArrayList<>(meta.size()); + + for (String schema : meta.keySet()) + if (matches(schema, schemaPtrn)) + rows.add(Arrays.<Object>asList(schema, null)); + + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("TABLE_SCHEM", "TABLE_CATALOG"), + Arrays.asList(String.class.getName(), String.class.getName()), + rows, true + ); + } + + /** {@inheritDoc} */ + @Override public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } + + /** {@inheritDoc} */ + @Override public ResultSet getClientInfoProperties() throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getFunctions(String catalog, String schemaPtrn, + String functionNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("FUNCTION_CAT", "FUNCTION_SCHEM", "FUNCTION_NAME", + "REMARKS", "FUNCTION_TYPE", "SPECIFIC_NAME"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), Short.class.getName(), String.class.getName()), + Collections.<List<?>>emptyList(), true + ); + } + + /** {@inheritDoc} */ + @Override public ResultSet getFunctionColumns(String catalog, String schemaPtrn, String functionNamePtrn, + String colNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Arrays.asList("FUNCTION_CAT", "FUNCTION_SCHEM", "FUNCTION_NAME", + "COLUMN_NAME", "COLUMN_TYPE", "DATA_TYPE", "TYPE_NAME", "PRECISION", + "LENGTH", "SCALE", "RADIX", "NULLABLE", "REMARKS", "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", "IS_NULLABLE", "SPECIFIC_NAME"), + Arrays.asList(String.class.getName(), String.class.getName(), String.class.getName(), + String.class.getName(), Short.class.getName(), Integer.class.getName(), String.class.getName(), + Integer.class.getName(), Integer.class.getName(), Short.class.getName(), Short.class.getName(), + Short.class.getName(), String.class.getName(), Integer.class.getName(), Integer.class.getName(), + String.class.getName(), String.class.getName()), + Collections.<List<?>>emptyList(), true + ); + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public <T> T unwrap(Class<T> iface) throws SQLException { + if (!isWrapperFor(iface)) + throw new SQLException("Database meta data is not a wrapper for " + iface.getName()); + + return (T)this; + } + + /** {@inheritDoc} */ + @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { + return iface != null && iface == DatabaseMetaData.class; + } + + /** {@inheritDoc} */ + @Override public ResultSet getPseudoColumns(String catalog, String schemaPtrn, String tblNamePtrn, + String colNamePtrn) throws SQLException { + return new JdbcResultSet(null, + conn.createStatement0(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<String>emptyList(), + Collections.<List<?>>emptyList(), + true + ); + } + + /** {@inheritDoc} */ + @Override public boolean generatedKeyAlwaysReturned() throws SQLException { + return false; + } + + /** + * Updates meta data. + * + * @throws SQLException In case of error. + */ + @SuppressWarnings("unchecked") + private void updateMetaData() throws SQLException { + if (conn.isClosed()) + throw new SQLException("Connection is closed."); + + try { + Ignite ignite = conn.ignite(); + + UUID nodeId = conn.nodeId(); + + Collection<GridCacheSqlMetadata> metas; + + UpdateMetadataTask task = new UpdateMetadataTask(conn.cacheName(), nodeId == null ? ignite : null); + + metas = nodeId == null ? task.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(task); + + meta = U.newHashMap(metas.size()); + + indexes = new ArrayList<>(); + + for (GridCacheSqlMetadata m : metas) { + String name = m.cacheName(); + + if (name == null) + name = "PUBLIC"; + + Collection<String> types = m.types(); + + Map<String, Map<String, String>> typesMap = U.newHashMap(types.size()); + + for (String type : types) { + typesMap.put(type.toUpperCase(), m.fields(type)); + + for (GridCacheSqlIndexMetadata idx : m.indexes(type)) { + int cnt = 0; + + for (String field : idx.fields()) { + indexes.add(F.<Object>asList(name, type.toUpperCase(), !idx.unique(), + idx.name().toUpperCase(), ++cnt, field, idx.descending(field))); + } + } + } + + meta.put(name, typesMap); + } + } + catch (Exception e) { + throw new SQLException("Failed to get meta data from Ignite.", e); + } + } + + /** + * Checks whether string matches SQL pattern. + * + * @param str String. + * @param ptrn Pattern. + * @return Whether string matches pattern. + */ + private boolean matches(String str, String ptrn) { + return str != null && (ptrn == null || + str.toUpperCase().matches(ptrn.toUpperCase().replace("%", ".*").replace("_", "."))); + } + + /** + * + */ + private static class UpdateMetadataTask implements IgniteCallable<Collection<GridCacheSqlMetadata>> { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Ignite. */ + @IgniteInstanceResource + private Ignite ignite; + + /** Cache name. */ + private final String cacheName; + + /** + * @param cacheName Cache name. + * @param ignite Ignite. + */ + public UpdateMetadataTask(String cacheName, Ignite ignite) { + this.cacheName = cacheName; + this.ignite = ignite; + } + + /** {@inheritDoc} */ + @SuppressWarnings("unchecked") + @Override public Collection<GridCacheSqlMetadata> call() throws Exception { + IgniteCache cache = ignite.cache(cacheName); + + return ((IgniteCacheProxy)cache).context().queries().sqlMetadata(); + } + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ebb9e2e9/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcPreparedStatement.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcPreparedStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcPreparedStatement.java new file mode 100644 index 0000000..a99f24c --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcPreparedStatement.java @@ -0,0 +1,411 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.jdbc2; + +import java.io.*; +import java.math.*; +import java.net.*; +import java.sql.*; +import java.sql.Date; +import java.util.*; + +/** + * JDBC prepared statement implementation. + */ +public class JdbcPreparedStatement extends JdbcStatement implements PreparedStatement { + /** SQL query. */ + private final String sql; + + /** Arguments count. */ + private final int argsCnt; + + /** + * Creates new prepared statement. + * + * @param conn Connection. + * @param sql SQL query. + */ + JdbcPreparedStatement(JdbcConnection conn, String sql) { + super(conn); + + this.sql = sql; + + argsCnt = sql.replaceAll("[^?]", "").length(); + } + + /** {@inheritDoc} */ + @Override public ResultSet executeQuery() throws SQLException { + ResultSet rs = executeQuery(sql); + + args = null; + + return rs; + } + + /** {@inheritDoc} */ + @Override public int executeUpdate() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNull(int paramIdx, int sqlType) throws SQLException { + setArgument(paramIdx, null); + } + + /** {@inheritDoc} */ + @Override public void setBoolean(int paramIdx, boolean x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setByte(int paramIdx, byte x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setShort(int paramIdx, short x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setInt(int paramIdx, int x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setLong(int paramIdx, long x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setFloat(int paramIdx, float x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setDouble(int paramIdx, double x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setBigDecimal(int paramIdx, BigDecimal x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setString(int paramIdx, String x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setBytes(int paramIdx, byte[] x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setDate(int paramIdx, Date x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTime(int paramIdx, Time x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTimestamp(int paramIdx, Timestamp x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setAsciiStream(int paramIdx, InputStream x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setUnicodeStream(int paramIdx, InputStream x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBinaryStream(int paramIdx, InputStream x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void clearParameters() throws SQLException { + ensureNotClosed(); + + args = null; + } + + /** {@inheritDoc} */ + @Override public void setObject(int paramIdx, Object x, int targetSqlType) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setObject(int paramIdx, Object x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public boolean execute() throws SQLException { + return execute(sql); + } + + /** {@inheritDoc} */ + @Override public void addBatch() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setCharacterStream(int paramIdx, Reader x, int len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setRef(int paramIdx, Ref x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBlob(int paramIdx, Blob x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setClob(int paramIdx, Clob x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setArray(int paramIdx, Array x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public ResultSetMetaData getMetaData() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Meta data for prepared statement is not supported."); + } + + /** {@inheritDoc} */ + @Override public void setDate(int paramIdx, Date x, Calendar cal) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTime(int paramIdx, Time x, Calendar cal) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setTimestamp(int paramIdx, Timestamp x, Calendar cal) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setNull(int paramIdx, int sqlType, String typeName) throws SQLException { + setNull(paramIdx, sqlType); + } + + /** {@inheritDoc} */ + @Override public void setURL(int paramIdx, URL x) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public ParameterMetaData getParameterMetaData() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Meta data for prepared statement is not supported."); + } + + /** {@inheritDoc} */ + @Override public void setRowId(int paramIdx, RowId x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNString(int paramIdx, String val) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNCharacterStream(int paramIdx, Reader val, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNClob(int paramIdx, NClob val) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setClob(int paramIdx, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBlob(int paramIdx, InputStream inputStream, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNClob(int paramIdx, Reader reader, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setSQLXML(int paramIdx, SQLXML xmlObj) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setObject(int paramIdx, Object x, int targetSqlType, + int scaleOrLen) throws SQLException { + setArgument(paramIdx, x); + } + + /** {@inheritDoc} */ + @Override public void setAsciiStream(int paramIdx, InputStream x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBinaryStream(int paramIdx, InputStream x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setCharacterStream(int paramIdx, Reader x, long len) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setAsciiStream(int paramIdx, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBinaryStream(int paramIdx, InputStream x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setCharacterStream(int paramIdx, Reader x) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Streams are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNCharacterStream(int paramIdx, Reader val) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setClob(int paramIdx, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setBlob(int paramIdx, InputStream inputStream) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public void setNClob(int paramIdx, Reader reader) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** + * Sets query argument value. + * + * @param paramIdx Index. + * @param val Value. + * @throws SQLException If index is invalid. + */ + private void setArgument(int paramIdx, Object val) throws SQLException { + ensureNotClosed(); + + if (paramIdx < 1 || paramIdx > argsCnt) + throw new SQLException("Parameter index is invalid: " + paramIdx); + + if (args == null) + args = new Object[argsCnt]; + + args[paramIdx - 1] = val; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/ebb9e2e9/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java new file mode 100644 index 0000000..ac711b8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java @@ -0,0 +1,361 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.jdbc2; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteJdbcDriver; +import org.apache.ignite.IgniteSystemProperties; +import org.apache.ignite.cache.query.QueryCursor; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; +import org.apache.ignite.internal.util.typedef.CAX; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.resources.IgniteInstanceResource; + +/** + * Task for SQL queries execution through {@link IgniteJdbcDriver}. + * <p> + * Not closed cursors will be removed after {@link #RMV_DELAY} milliseconds. + * This parameter can be configured via {@link IgniteSystemProperties#IGNITE_JDBC_DRIVER_CURSOR_REMOVE_DELAY} + * system property. + */ +class JdbcQueryTask implements IgniteCallable<JdbcQueryTask.QueryResult> { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** How long to store open cursor. */ + private static final long RMV_DELAY = IgniteSystemProperties.getLong( + IgniteSystemProperties.IGNITE_JDBC_DRIVER_CURSOR_REMOVE_DELAY, 600000); + + /** Scheduler. */ + private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); + + /** Open cursors. */ + private static final ConcurrentMap<UUID, Cursor> CURSORS = new ConcurrentHashMap<>(); + + /** Ignite. */ + @IgniteInstanceResource + private Ignite ignite; + + /** Uuid. */ + private final UUID uuid; + + /** Cache name. */ + private final String cacheName; + + /** Sql. */ + private final String sql; + + /** Args. */ + private final Object[] args; + + /** Fetch size. */ + private final int fetchSize; + + /** Local execution flag. */ + private final boolean loc; + + /** Local query flag. */ + private final boolean locQry; + + /** Collocated query flag. */ + private final boolean collocatedQry; + + /** + * @param ignite Ignite. + * @param cacheName Cache name. + * @param sql Sql query. + * @param loc Local execution flag. + * @param args Args. + * @param fetchSize Fetch size. + * @param uuid UUID. + * @param locQry Local query flag. + * @param collocatedQry Collocated query flag. + */ + public JdbcQueryTask(Ignite ignite, String cacheName, String sql, + boolean loc, Object[] args, int fetchSize, UUID uuid, boolean locQry, boolean collocatedQry) { + this.ignite = ignite; + this.args = args; + this.uuid = uuid; + this.cacheName = cacheName; + this.sql = sql; + this.fetchSize = fetchSize; + this.loc = loc; + this.locQry = locQry; + this.collocatedQry = collocatedQry; + } + + /** {@inheritDoc} */ + @Override public JdbcQueryTask.QueryResult call() throws Exception { + Cursor cursor = CURSORS.get(uuid); + + List<String> tbls = null; + List<String> cols = null; + List<String> types = null; + + boolean first; + + if (first = (cursor == null)) { + IgniteCache<?, ?> cache = ignite.cache(cacheName); + + SqlFieldsQuery qry = new SqlFieldsQuery(sql).setArgs(args); + + qry.setPageSize(fetchSize); + qry.setLocal(locQry); + qry.setCollocated(collocatedQry); + + QueryCursor<List<?>> qryCursor = cache.query(qry); + + Collection<GridQueryFieldMetadata> meta = ((QueryCursorImpl<List<?>>)qryCursor).fieldsMeta(); + + tbls = new ArrayList<>(meta.size()); + cols = new ArrayList<>(meta.size()); + types = new ArrayList<>(meta.size()); + + for (GridQueryFieldMetadata desc : meta) { + tbls.add(desc.typeName()); + cols.add(desc.fieldName().toUpperCase()); + types.add(desc.fieldTypeName()); + } + + CURSORS.put(uuid, cursor = new Cursor(qryCursor, qryCursor.iterator())); + } + + List<List<?>> rows = new ArrayList<>(); + + for (List<?> row : cursor) { + List<Object> row0 = new ArrayList<>(row.size()); + + for (Object val : row) + row0.add(JdbcUtils.sqlType(val) ? val : val.toString()); + + rows.add(row0); + + if (rows.size() == fetchSize) // If fetchSize is 0 then unlimited + break; + } + + boolean finished = !cursor.hasNext(); + + if (finished) + remove(uuid, cursor); + else if (first) { + if (!loc) + scheduleRemoval(uuid, RMV_DELAY); + } + else if (!loc && !CURSORS.replace(uuid, cursor, new Cursor(cursor.cursor, cursor.iter))) + assert !CURSORS.containsKey(uuid) : "Concurrent cursor modification."; + + return new QueryResult(uuid, finished, rows, cols, tbls, types); + } + + /** + * Schedules removal of stored cursor in case of remote query execution. + * + * @param uuid Cursor UUID. + * @param delay Delay in milliseconds. + */ + private void scheduleRemoval(final UUID uuid, long delay) { + assert !loc; + + SCHEDULER.schedule(new CAX() { + @Override public void applyx() { + while (true) { + Cursor c = CURSORS.get(uuid); + + if (c == null) + break; + + // If the cursor was accessed since last scheduling then reschedule. + long untouchedTime = U.currentTimeMillis() - c.lastAccessTime; + + if (untouchedTime < RMV_DELAY) { + scheduleRemoval(uuid, RMV_DELAY - untouchedTime); + + break; + } + else if (remove(uuid, c)) + break; + } + } + }, delay, TimeUnit.MILLISECONDS); + } + + /** + * @param uuid Cursor UUID. + * @param c Cursor. + * @return {@code true} If succeeded. + */ + private static boolean remove(UUID uuid, Cursor c) { + boolean rmv = CURSORS.remove(uuid, c); + + if (rmv) + c.cursor.close(); + + return rmv; + } + + /** + * Closes and removes cursor. + * + * @param uuid Cursor UUID. + */ + static void remove(UUID uuid) { + Cursor c = CURSORS.remove(uuid); + + if (c != null) + c.cursor.close(); + } + + + /** + * Result of query execution. + */ + static class QueryResult implements Serializable { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Uuid. */ + private final UUID uuid; + + /** Finished. */ + private final boolean finished; + + /** Rows. */ + private final List<List<?>> rows; + + /** Tables. */ + private final List<String> tbls; + + /** Columns. */ + private final List<String> cols; + + /** Types. */ + private final List<String> types; + + /** + * @param uuid UUID.. + * @param finished Finished. + * @param rows Rows. + * @param cols Columns. + * @param tbls Tables. + * @param types Types. + */ + public QueryResult(UUID uuid, boolean finished, List<List<?>> rows, List<String> cols, + List<String> tbls, List<String> types) { + this.cols = cols; + this.uuid = uuid; + this.finished = finished; + this.rows = rows; + this.tbls = tbls; + this.types = types; + } + + /** + * @return Query result rows. + */ + public List<List<?>> getRows() { + return rows; + } + + /** + * @return Tables metadata. + */ + public List<String> getTbls() { + return tbls; + } + + /** + * @return Columns metadata. + */ + public List<String> getCols() { + return cols; + } + + /** + * @return Types metadata. + */ + public List<String> getTypes() { + return types; + } + + /** + * @return Query UUID. + */ + public UUID getUuid() { + return uuid; + } + + /** + * @return {@code True} if it is finished query. + */ + public boolean isFinished() { + return finished; + } + } + + /** + * Cursor. + */ + private static final class Cursor implements Iterable<List<?>> { + /** Cursor. */ + final QueryCursor<List<?>> cursor; + + /** Iterator. */ + final Iterator<List<?>> iter; + + /** Last access time. */ + final long lastAccessTime; + + /** + * @param cursor Cursor. + * @param iter Iterator. + */ + private Cursor(QueryCursor<List<?>> cursor, Iterator<List<?>> iter) { + this.cursor = cursor; + this.iter = iter; + this.lastAccessTime = U.currentTimeMillis(); + } + + /** {@inheritDoc} */ + @Override public Iterator<List<?>> iterator() { + return iter; + } + + /** + * @return {@code True} if cursor has next element. + */ + public boolean hasNext() { + return iter.hasNext(); + } + } +}