http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java b/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java new file mode 100644 index 0000000..4ca9ce1 --- /dev/null +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/QueryState.java @@ -0,0 +1,466 @@ +/* + * 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.calcite.avatica; + +import org.apache.calcite.avatica.proto.Common; +import org.apache.calcite.avatica.proto.Common.MetaDataOperationArgument; +import org.apache.calcite.avatica.proto.Common.MetaDataOperationArgument.ArgumentType; +import org.apache.calcite.avatica.remote.MetaDataOperation; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.Objects; + +/** + * A struct used to encapsulate the necessary information to reconstitute a ResultSet in the + * Avatica server. + */ +public class QueryState { + + /** + * An enumeration that represents how a ResultSet was created. + */ + public enum StateType { + SQL, + METADATA; + + public Common.StateType toProto() { + switch (this) { + case SQL: + return Common.StateType.SQL; + case METADATA: + return Common.StateType.METADATA; + default: + return Common.StateType.UNRECOGNIZED; + } + } + + public static StateType fromProto(Common.StateType protoType) { + switch (protoType) { + case SQL: + return StateType.SQL; + case METADATA: + return StateType.METADATA; + default: + throw new IllegalArgumentException("Unhandled StateType " + protoType); + } + } + } + + @JsonProperty("type") + public final StateType type; + + @JsonProperty("sql") + public final String sql; + + @JsonProperty("metaDataOperation") + public final MetaDataOperation metaDataOperation; + @JsonProperty("operationArgs") + public final Object[] operationArgs; + + /** + * Constructor encapsulating a SQL query used to create a result set. + * + * @param sql The SQL query. + */ + public QueryState(String sql) { + // This doesn't to be non-null + this.sql = sql; + this.type = StateType.SQL; + + // Null out the members we don't use. + this.metaDataOperation = null; + this.operationArgs = null; + } + + /** + * Constructor encapsulating a metadata operation's result set. + * + * @param op A pointer to the {@link DatabaseMetaData} operation being invoked. + * @param args The arguments to the method being invoked. + */ + public QueryState(MetaDataOperation op, Object... args) { + this.metaDataOperation = Objects.requireNonNull(op); + this.operationArgs = Arrays.copyOf(Objects.requireNonNull(args), args.length); + this.type = StateType.METADATA; + + // Null out the members we won't use + this.sql = null; + } + + /** + * Not intended for external use. For Jackson-databind only. + */ + public QueryState(StateType type, String sql, MetaDataOperation op, Object... args) { + this.type = Objects.requireNonNull(type); + switch (type) { + case SQL: + this.sql = Objects.requireNonNull(sql); + if (null != op) { + throw new IllegalArgumentException("Expected null MetaDataOperation, but got " + op); + } + this.metaDataOperation = null; + if (null != args) { + throw new IllegalArgumentException("Expected null arguments, but got " + + Arrays.toString(args)); + } + this.operationArgs = null; + break; + case METADATA: + this.metaDataOperation = Objects.requireNonNull(op); + this.operationArgs = Objects.requireNonNull(args); + if (null != sql) { + throw new IllegalArgumentException("Expected null SQl but got " + sql); + } + this.sql = null; + break; + default: + throw new IllegalArgumentException("Unable to handle StateType " + type); + } + } + + /** + * Not intended for external use. For Jackson-databind only. + */ + public QueryState() { + this.sql = null; + this.metaDataOperation = null; + this.type = null; + this.operationArgs = null; + } + + /** + * @return The {@link StateType} for this encapsulated state. + */ + public StateType getType() { + return type; + } + + /** + * @return The SQL expression to invoke. + */ + public String getSql() { + assert type == StateType.SQL; + return sql; + } + + /** + * @return The metadata operation to invoke. + */ + public MetaDataOperation getMetaDataOperation() { + assert type == StateType.METADATA; + return metaDataOperation; + } + + /** + * @return The Arguments for the given metadata operation. + */ + public Object[] getOperationArgs() { + assert type == StateType.METADATA; + return operationArgs; + } + + public ResultSet invoke(Connection conn, Statement statement) throws SQLException { + switch (type) { + case SQL: + boolean ret = Objects.requireNonNull(statement).execute(sql); + ResultSet results = statement.getResultSet(); + + // Either execute(sql) returned true or the resultSet was null + assert ret || null == results; + + return results; + case METADATA: + DatabaseMetaData metadata = Objects.requireNonNull(conn).getMetaData(); + switch (metaDataOperation) { + case GET_ATTRIBUTES: + verifyOpArgs(4); + return metadata.getAttributes((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String) operationArgs[3]); + case GET_BEST_ROW_IDENTIFIER: + verifyOpArgs(5); + return metadata.getBestRowIdentifier((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (int) operationArgs[3], + (boolean) operationArgs[4]); + case GET_CATALOGS: + verifyOpArgs(0); + return metadata.getCatalogs(); + case GET_COLUMNS: + verifyOpArgs(4); + return metadata.getColumns((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String) operationArgs[3]); + case GET_COLUMN_PRIVILEGES: + verifyOpArgs(4); + return metadata.getColumnPrivileges((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String) operationArgs[3]); + case GET_CROSS_REFERENCE: + verifyOpArgs(6); + return metadata.getCrossReference((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String) operationArgs[3], + (String) operationArgs[4], + (String) operationArgs[5]); + case GET_EXPORTED_KEYS: + verifyOpArgs(3); + return metadata.getExportedKeys((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_FUNCTIONS: + verifyOpArgs(3); + return metadata.getFunctions((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_FUNCTION_COLUMNS: + verifyOpArgs(4); + return metadata.getFunctionColumns((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String) operationArgs[3]); + case GET_IMPORTED_KEYS: + verifyOpArgs(3); + return metadata.getImportedKeys((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_INDEX_INFO: + verifyOpArgs(5); + return metadata.getIndexInfo((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (boolean) operationArgs[3], + (boolean) operationArgs[4]); + case GET_PRIMARY_KEYS: + verifyOpArgs(3); + return metadata.getPrimaryKeys((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_PROCEDURES: + verifyOpArgs(3); + return metadata.getProcedures((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_PROCEDURE_COLUMNS: + verifyOpArgs(4); + return metadata.getProcedureColumns((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String) operationArgs[3]); + case GET_PSEUDO_COLUMNS: + verifyOpArgs(4); + return metadata.getPseudoColumns((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String) operationArgs[3]); + case GET_SCHEMAS: + verifyOpArgs(0); + return metadata.getSchemas(); + case GET_SCHEMAS_WITH_ARGS: + verifyOpArgs(2); + return metadata.getSchemas((String) operationArgs[0], + (String) operationArgs[1]); + case GET_SUPER_TABLES: + verifyOpArgs(3); + return metadata.getSuperTables((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_SUPER_TYPES: + verifyOpArgs(3); + return metadata.getSuperTypes((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_TABLES: + verifyOpArgs(4); + return metadata.getTables((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (String[]) operationArgs[3]); + case GET_TABLE_PRIVILEGES: + verifyOpArgs(3); + return metadata.getTablePrivileges((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + case GET_TABLE_TYPES: + verifyOpArgs(0); + return metadata.getTableTypes(); + case GET_TYPE_INFO: + verifyOpArgs(0); + return metadata.getTypeInfo(); + case GET_UDTS: + verifyOpArgs(4); + return metadata.getUDTs((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2], + (int[]) operationArgs[3]); + case GET_VERSION_COLUMNS: + verifyOpArgs(3); + return metadata.getVersionColumns((String) operationArgs[0], + (String) operationArgs[1], + (String) operationArgs[2]); + default: + throw new IllegalArgumentException("Unhandled Metadata operation: " + metaDataOperation); + } + default: + throw new IllegalArgumentException("Unable to process QueryState of type " + type); + } + } + + private void verifyOpArgs(int expectedArgs) { + if (expectedArgs != operationArgs.length) { + throw new RuntimeException("Expected " + expectedArgs + " arguments, but got " + + Arrays.toString(operationArgs)); + } + } + + public Common.QueryState toProto() { + Common.QueryState.Builder builder = Common.QueryState.newBuilder(); + + // Required + switch (type) { + case SQL: + builder.setType(Common.StateType.SQL); + break; + case METADATA: + builder.setType(Common.StateType.METADATA); + break; + default: + throw new IllegalStateException("Unhandled type: " + type); + } + + // Optional SQL + if (null != sql) { + builder.setSql(sql).setHasSql(true); + } + + // Optional metaDataOperation + if (null != metaDataOperation) { + builder.setOp(metaDataOperation.toProto()).setHasOp(true); + } + + // Optional operationArgs + if (null != operationArgs) { + builder.setHasArgs(true); + for (Object arg : operationArgs) { + MetaDataOperationArgument.Builder argBuilder = MetaDataOperationArgument.newBuilder(); + + if (null == arg) { + builder.addArgs(argBuilder.setType(ArgumentType.NULL).build()); + } else if (arg instanceof String) { + builder.addArgs(argBuilder.setType(ArgumentType.STRING) + .setStringValue((String) arg).build()); + } else if (arg instanceof Integer) { + builder.addArgs(argBuilder.setType(ArgumentType.INT).setIntValue((int) arg).build()); + } else if (arg instanceof Boolean) { + builder.addArgs( + argBuilder.setType(ArgumentType.BOOL).setBoolValue((boolean) arg).build()); + } else if (arg instanceof String[]) { + argBuilder.setType(ArgumentType.REPEATED_STRING); + for (String strArg : (String[]) arg) { + argBuilder.addStringArrayValues(strArg); + } + builder.addArgs(argBuilder.build()); + } else if (arg instanceof int[]) { + argBuilder.setType(ArgumentType.REPEATED_INT); + for (int intArg : (int[]) arg) { + argBuilder.addIntArrayValues(intArg); + } + builder.addArgs(argBuilder.build()); + } else { + throw new RuntimeException("Unexpected operation argument: " + arg.getClass()); + } + } + } else { + builder.setHasArgs(false); + } + + return builder.build(); + } + + public static QueryState fromProto(Common.QueryState protoState) { + StateType type = StateType.fromProto(protoState.getType()); + String sql = protoState.getHasSql() ? protoState.getSql() : null; + MetaDataOperation op = protoState.getHasOp() + ? MetaDataOperation.fromProto(protoState.getOp()) : null; + Object[] opArgs = null; + if (protoState.getHasArgs()) { + opArgs = new Object[protoState.getArgsCount()]; + int i = 0; + for (Common.MetaDataOperationArgument arg : protoState.getArgsList()) { + switch (arg.getType()) { + case STRING: + opArgs[i] = arg.getStringValue(); + break; + case BOOL: + opArgs[i] = arg.getBoolValue(); + break; + case INT: + opArgs[i] = arg.getIntValue(); + break; + case REPEATED_STRING: + opArgs[i] = arg.getStringArrayValuesList().toArray( + new String[arg.getStringArrayValuesCount()]); + break; + case REPEATED_INT: + int[] arr = new int[arg.getIntArrayValuesCount()]; + int offset = 0; + for (Integer val : arg.getIntArrayValuesList()) { + arr[offset] = val; + offset++; + } + opArgs[i] = arr; + break; + case NULL: + opArgs[i] = null; + break; + default: + throw new RuntimeException("Could not interpret " + arg.getType()); + } + + i++; + } + } + + return new QueryState(type, sql, op, opArgs); + } + + @Override public int hashCode() { + return Objects.hash(metaDataOperation, Arrays.hashCode(operationArgs), sql); + } + + @Override public boolean equals(Object o) { + return o == this + || o instanceof QueryState + && metaDataOperation == ((QueryState) o).metaDataOperation + && Arrays.deepEquals(operationArgs, ((QueryState) o).operationArgs) + && Objects.equals(sql, ((QueryState) o).sql); + } +} + +// End QueryState.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java b/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java new file mode 100644 index 0000000..e34bee6 --- /dev/null +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/SqlType.java @@ -0,0 +1,559 @@ +/* + * 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.calcite.avatica; + +import org.apache.calcite.avatica.util.ByteString; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.Ref; +import java.sql.RowId; +import java.sql.Struct; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** Extends the information in {@link java.sql.Types}. + * + * <p>The information in the following conversions tables + * (from the JDBC 4.1 specification) is held in members of this class. + * + * <p>Table B-1: JDBC Types Mapped to Java Types + * + * <pre> + * JDBC Type Java Type + * ============= ========================= + * CHAR String + * VARCHAR String + * LONGVARCHAR String + * NUMERIC java.math.BigDecimal + * DECIMAL java.math.BigDecimal + * BIT boolean + * BOOLEAN boolean + * TINYINT byte + * SMALLINT short + * INTEGER int + * BIGINT long + * REAL float + * FLOAT double + * DOUBLE double + * BINARY byte[] + * VARBINARY byte[] + * LONGVARBINARY byte[] + * DATE java.sql.Date + * TIME java.sql.Time + * TIMESTAMP java.sql.Timestamp + * CLOB java.sql.Clob + * BLOB java.sql.Blob + * ARRAY java.sql.Array + * DISTINCT mapping of underlying type + * STRUCT java.sql.Struct + * REF java.sql.Ref + * DATALINK java.net.URL + * JAVA_OBJECT underlying Java class + * ROWID java.sql.RowId + * NCHAR String + * NVARCHAR String + * LONGNVARCHAR String + * NCLOB java.sql.NClob + * SQLXML java.sql.SQLXML + * </pre> + * + * <p>Table B-2: Standard Mapping from Java Types to JDBC Types + * + * <pre> + * Java Type JDBC Type + * ==================== ============================================== + * String CHAR, VARCHAR, LONGVARCHAR, NCHAR, NVARCHAR or + * LONGNVARCHAR + * java.math.BigDecimal NUMERIC + * boolean BIT or BOOLEAN + * byte TINYINT + * short SMALLINT + * int INTEGER + * long BIGINT + * float REAL + * double DOUBLE + * byte[] BINARY, VARBINARY, or LONGVARBINARY + * java.sql.Date DATE + * java.sql.Time TIME + * java.sql.Timestamp TIMESTAMP + * java.sql.Clob CLOB + * java.sql.Blob BLOB + * java.sql.Array ARRAY + * java.sql.Struct STRUCT + * java.sql.Ref REF + * java.net.URL DATALINK + * Java class JAVA_OBJECT + * java.sql.RowId ROWID + * java.sql.NClob NCLOB + * java.sql.SQLXML SQLXML + * </pre> + * + * <p>TABLE B-3: Mapping from JDBC Types to Java Object Types + * + * <pre> + * JDBC Type Java Object Type + * ============= ====================== + * CHAR String + * VARCHAR String + * LONGVARCHAR String + * NUMERIC java.math.BigDecimal + * DECIMAL java.math.BigDecimal + * BIT Boolean + * BOOLEAN Boolean + * TINYINT Integer + * SMALLINT Integer + * INTEGER Integer + * BIGINT Long + * REAL Float + * FLOAT Double + * DOUBLE Double + * BINARY byte[] + * VARBINARY byte[] + * LONGVARBINARY byte[] + * DATE java.sql.Date + * TIME java.sql.Time + * TIMESTAMP java.sql.Timestamp + * DISTINCT Object type of underlying type + * CLOB java.sql.Clob + * BLOB java.sql.Blob + * ARRAY java.sql.Array + * STRUCT java.sql.Struct or java.sql.SQLData + * REF java.sql.Ref + * DATALINK java.net.URL + * JAVA_OBJECT underlying Java class + * ROWID java.sql.RowId + * NCHAR String + * NVARCHAR String + * LONGNVARCHAR String + * NCLOB java.sql.NClob + * SQLXML java.sql.SQLXML + * </pre> + * + * <p>TABLE B-4: Mapping from Java Object Types to JDBC Types + * + * <pre> + * Java Object Type JDBC Type + * ==================== =========================================== + * String CHAR, VARCHAR, LONGVARCHAR, NCHAR, NVARCHAR + * or LONGNVARCHAR + * java.math.BigDecimal NUMERIC + * Boolean BIT or BOOLEAN + * Byte TINYINT + * Short SMALLINT + * Integer INTEGER + * Long BIGINT + * Float REAL + * Double DOUBLE + * byte[] BINARY, VARBINARY, or LONGVARBINARY + * java.math.BigInteger BIGINT + * java.sql.Date DATE + * java.sql.Time TIME + * java.sql.Timestamp TIMESTAMP + * java.sql.Clob CLOB + * java.sql.Blob BLOB + * java.sql.Array ARRAY + * java.sql.Struct STRUCT + * java.sql.Ref REF + * java.net.URL DATALINK + * Java class JAVA_OBJECT + * java.sql.RowId ROWID + * java.sql.NClob NCLOB + * java.sql.SQLXML SQLXML + * java.util.Calendar TIMESTAMP + * java.util.Date TIMESTAMP + * </pre> + * + * <p><a name="B5">TABLE B-5</a>: Conversions performed by {@code setObject} and + * {@code setNull} between Java object types and target JDBC types + * + * <!-- + * CHECKSTYLE: OFF + * --> + * <pre> + * T S I B R F D D N B B C V L B V L D T T A B C S R D J R N N L N S + * I M N I E L O E U I O H A O I A O A I I R L L T E A A O C V O C Q + * N A T G A O U C M T O A R N N R N T M M R O O R F T V W H A N L L + * Y L E I L A B I E L R C G A B G E E E A B B U A A I A R G O X + * I L G N T L M R E H V R I V E S Y C L _ D R C N B M + * N I E T E A I A A A Y N A T T I O H V L + * T N R L C N R R A R A N B A A + * T C R B M K J R R + * H Y I P C + * Java type + * ==================== = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + * String x x x x x x x x x x x x x x x x x x x x . . . . . . . . x x x . . + * java.math.BigDecimal x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * Boolean x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * Byte x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * Short x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * Integer x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * Long x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * Float x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * Double x x x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * byte[] . . . . . . . . . . . . . . x x x . . . . . . . . . . . . . . . . + * java.math.BigInteger . . . x . . . . . . . x x x . . . . . . . . . . . . . . . . . . . + * java.sql.Date . . . . . . . . . . . x x x . . . x . x . . . . . . . . . . . . . + * java.sql.Time . . . . . . . . . . . x x x . . . . x x . . . . . . . . . . . . . + * java.sql.Timestamp . . . . . . . . . . . x x x . . . x x x . . . . . . . . . . . . . + * java.sql.Array . . . . . . . . . . . . . . . . . . . . x . . . . . . . . . . . . + * java.sql.Blob . . . . . . . . . . . . . . . . . . . . . x . . . . . . . . . . . + * java.sql.Clob . . . . . . . . . . . . . . . . . . . . . . x . . . . . . . . . . + * java.sql.Struct . . . . . . . . . . . . . . . . . . . . . . . x . . . . . . . . . + * java.sql.Ref . . . . . . . . . . . . . . . . . . . . . . . . x . . . . . . . . + * java.net.URL . . . . . . . . . . . . . . . . . . . . . . . . . x . . . . . . . + * Java class . . . . . . . . . . . . . . . . . . . . . . . . . . x . . . . . . + * java.sql.Rowid . . . . . . . . . . . . . . . . . . . . . . . . . . . x . . . . . + * java.sql.NClob . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x . + * java.sql.SQLXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x + * java.util.Calendar . . . . . . . . . . . x x x . . . x x x . . . . . . . . . . . . . + * java.util.Date . . . . . . . . . . . x x x . . . x x x . . . . . . . . . . . . . + * </pre> + * <!-- + * CHECKSTYLE: ON + * --> + * + * <p><a name="B6">TABLE B-6</a>: Use of {@code ResultSet} getter methods to + * retrieve JDBC data types + * + * <!-- + * CHECKSTYLE: OFF + * --> + * <pre> + * T S I B R F D D N B B C V L B V L D T T C B A R D S J R N N L N S + * I M N I E L O E U I O H A O I A O A I I L L R E A T A O C V O C Q + * N A T G A O U C M T O A R N N R N T M M O O R F T R V W H A N L L + * Y L E I L A B I E L R C G A B G E E E B B A A U A I A R G O X + * I L G N T L M R E H V R I V E S Y L C _ D R C N B M + * N I E T E A I A A A Y N A T I T O H V L + * T N R L C N R R A R A N B A A + * T C R B M K J R R + * H Y I P C + * Java type + * ==================== = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + * getByte X x x x x x x x x x x x x . . . . . . . . . . . . . . x . . . . . + * getShort x X x x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * getInt x x X x x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * getLong x x x X x x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * getFloat x x x x X x x x x x x x x . . . . . . . . . . . . . . . . . . . . + * getDouble x x x x x X X x x x x x x . . . . . . . . . . . . . . . . . . . . + * getBigDecimal x x x x x x x X X x x x x . . . . . . . . . . . . . . . . . . . . + * getBoolean x x x x x x x x x X x x x . . . . . . . . . . . . . . . . . . . . + * getString x x x x x x x x x x x X X x x x x x x x . . . . x . . . x x x . . + * getNString x x x x x x x x x x x x x x x x x x x x . . . . x . . . X X x . . + * getBytes . . . . . . . . . . . . . . X X x . . . . . . . . . . . . . . . . + * getDate . . . . . . . . . . . x x x . . . X . x . . . . . . . . . . . . . + * getTime . . . . . . . . . . . x x x . . . . X x . . . . . . . . . . . . . + * getTimestamp . . . . . . . . . . . x x x . . . x x X . . . . . . . . . . . x . + * getAsciiStream . . . . . . . . . . . x x X x x x . . . x . . . . . . . . . . . x + * getBinaryStream . . . . . . . . . . . . . . x x X . . . . x . . . . . . . . . x x + * getCharacterStream . . . . . . . . . . . x x X x x x . . . x . . . . . . . x x x x x + * getNCharacterStream . . . . . . . . . . . x x x x x x . . . x . . . . . . . x x X x x + * getClob . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . x . + * getNClob . . . . . . . . . . . . . . . . . . . . x . . . . . . . . . . X . + * getBlob . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . + * getArray . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . + * getRef . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . + * getURL . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . + * getObject x x x x x x x x x x x x x x x x x x x x x x x x x X X x x x x x x + * getRowId . . . . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . + * getSQLXML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . X + * </pre> + * <!-- + * CHECKSTYLE: ON + * --> + */ +public enum SqlType { + BIT(Types.BIT, boolean.class), + BOOLEAN(Types.BOOLEAN, boolean.class), + TINYINT(Types.TINYINT, byte.class), + SMALLINT(Types.SMALLINT, short.class), + INTEGER(Types.INTEGER, int.class), + BIGINT(Types.BIGINT, long.class), + NUMERIC(Types.NUMERIC, BigDecimal.class), + DECIMAL(Types.DECIMAL, BigDecimal.class), + FLOAT(Types.FLOAT, double.class), + REAL(Types.REAL, float.class), + DOUBLE(Types.DOUBLE, double.class), + DATE(Types.DATE, java.sql.Date.class, int.class), + TIME(Types.TIME, Time.class, int.class), + TIMESTAMP(Types.TIMESTAMP, Timestamp.class, long.class), + INTERVAL_YEAR_MONTH(Types.OTHER, Boolean.class), + INTERVAL_DAY_TIME(Types.OTHER, Boolean.class), + CHAR(Types.CHAR, String.class), + VARCHAR(Types.VARCHAR, String.class), + LONGVARCHAR(Types.LONGVARCHAR, String.class), + BINARY(Types.BINARY, byte[].class, ByteString.class, String.class), + VARBINARY(Types.VARBINARY, byte[].class, ByteString.class, String.class), + LONGVARBINARY(Types.LONGVARBINARY, byte[].class, ByteString.class, + String.class), + NULL(Types.NULL, Void.class), + ANY(Types.JAVA_OBJECT, Object.class), + SYMBOL(Types.OTHER, Object.class), + MULTISET(Types.ARRAY, List.class), + ARRAY(Types.ARRAY, Array.class), + BLOB(Types.BLOB, Blob.class), + CLOB(Types.CLOB, Clob.class), + SQLXML(Types.SQLXML, java.sql.SQLXML.class), + MAP(Types.OTHER, Map.class), + DISTINCT(Types.DISTINCT, Object.class), + STRUCT(Types.STRUCT, Struct.class), + REF(Types.REF, Ref.class), + DATALINK(Types.DATALINK, URL.class), + JAVA_OBJECT(Types.JAVA_OBJECT, Object.class), + ROWID(Types.ROWID, RowId.class), + NCHAR(Types.NCHAR, String.class), + NVARCHAR(Types.NVARCHAR, String.class), + LONGNVARCHAR(Types.LONGNVARCHAR, String.class), + NCLOB(Types.NCLOB, NClob.class), + ROW(Types.STRUCT, Object.class), + OTHER(Types.OTHER, Object.class), + CURSOR(2012, Object.class), + COLUMN_LIST(Types.OTHER + 2, Object.class); + + /** Type id as appears in {@link java.sql.Types}, + * e.g. {@link java.sql.Types#INTEGER}. */ + public final int id; + + /** Default Java type for this SQL type, as described in table B-1. */ + public final Class clazz; + + /** Class used internally in Calcite to represent instances of this type. */ + public final Class internal; + + /** Class used to serialize values of this type as JSON. */ + public final Class serial; + + private static final Map<Integer, SqlType> BY_ID = new HashMap<>(); + static { + for (SqlType sqlType : values()) { + BY_ID.put(sqlType.id, sqlType); + } + } + + SqlType(int id, Class clazz, Class internal, Class serial) { + this.id = id; + this.clazz = clazz; + this.internal = internal; + this.serial = serial; + } + + SqlType(int id, Class clazz, Class internal) { + this(id, clazz, internal, internal); + } + + SqlType(int id, Class clazz) { + this(id, clazz, clazz, clazz); + } + + public static SqlType valueOf(int type) { + final SqlType sqlType = BY_ID.get(type); + if (sqlType == null) { + throw new IllegalArgumentException("Unknown SQL type " + type); + } + return sqlType; + } + + /** Returns the boxed type. */ + public Class boxedClass() { + return AvaticaUtils.box(clazz); + } + + /** Returns the entries in JDBC table B-5. */ + public static Iterable<Map.Entry<Class, SqlType>> getSetConversions() { + final ArrayList<Map.Entry<Class, SqlType>> list = new ArrayList<>(); + for (Map.Entry<Class, EnumSet<SqlType>> entry : SET_LIST.entrySet()) { + for (SqlType sqlType : entry.getValue()) { + list.add(new AbstractMap.SimpleEntry<>(entry.getKey(), sqlType)); + } + } + return list; + } + + public static final Map<Class, EnumSet<SqlType>> SET_LIST; + public static final Map<Method, EnumSet<SqlType>> GET_LIST; + + static { + SET_LIST = new HashMap<>(); + GET_LIST = new HashMap<>(); + + EnumSet<SqlType> numericTypes = EnumSet.of(TINYINT, SMALLINT, INTEGER, + BIGINT, REAL, FLOAT, DOUBLE, DECIMAL, NUMERIC, BIT, BOOLEAN); + Class[] numericClasses = { + BigDecimal.class, Boolean.class, Byte.class, Short.class, Integer.class, + Long.class, Float.class, Double.class + }; + EnumSet<SqlType> charTypes = EnumSet.of(CHAR, VARCHAR, LONGVARCHAR); + EnumSet<SqlType> ncharTypes = EnumSet.of(NCHAR, NVARCHAR, LONGNVARCHAR); + EnumSet<SqlType> binaryTypes = EnumSet.of(BINARY, VARBINARY, LONGVARBINARY); + EnumSet<SqlType> dateTimeTypes = EnumSet.of(DATE, TIME, TIMESTAMP); + final EnumSet<SqlType> numericCharTypes = concat(numericTypes, charTypes); + SET_LIST.put(String.class, + concat(numericCharTypes, binaryTypes, dateTimeTypes, ncharTypes)); + for (Class clazz : numericClasses) { + SET_LIST.put(clazz, numericCharTypes); + } + SET_LIST.put(byte[].class, binaryTypes); + SET_LIST.put(BigInteger.class, + EnumSet.of(BIGINT, CHAR, VARCHAR, LONGVARCHAR)); + SET_LIST.put(java.sql.Date.class, + concat(charTypes, EnumSet.of(DATE, TIMESTAMP))); + SET_LIST.put(Time.class, + concat(charTypes, EnumSet.of(TIME, TIMESTAMP))); + SET_LIST.put(Timestamp.class, + concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP))); + SET_LIST.put(Array.class, EnumSet.of(ARRAY)); + SET_LIST.put(Blob.class, EnumSet.of(BLOB)); + SET_LIST.put(Clob.class, EnumSet.of(CLOB)); + SET_LIST.put(Struct.class, EnumSet.of(STRUCT)); + SET_LIST.put(Ref.class, EnumSet.of(REF)); + SET_LIST.put(URL.class, EnumSet.of(DATALINK)); + SET_LIST.put(Class.class, EnumSet.of(JAVA_OBJECT)); + SET_LIST.put(RowId.class, EnumSet.of(ROWID)); + SET_LIST.put(NClob.class, EnumSet.of(NCLOB)); + SET_LIST.put(java.sql.SQLXML.class, EnumSet.of(SQLXML)); + SET_LIST.put(Calendar.class, + concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP))); + SET_LIST.put(java.util.Date.class, + concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP))); + + EnumSet<Method> numericMethods = + EnumSet.of(Method.GET_BYTE, Method.GET_SHORT, Method.GET_INT, + Method.GET_LONG, Method.GET_FLOAT, Method.GET_DOUBLE, + Method.GET_BIG_DECIMAL, Method.GET_BOOLEAN); + for (Method method : numericMethods) { + GET_LIST.put(method, numericCharTypes); + } + GET_LIST.put(Method.GET_BYTE, EnumSet.of(ROWID)); + for (Method method : EnumSet.of(Method.GET_STRING, Method.GET_N_STRING)) { + GET_LIST.put(method, + concat(numericCharTypes, binaryTypes, dateTimeTypes, + EnumSet.of(DATALINK), ncharTypes)); + } + GET_LIST.put(Method.GET_BYTES, binaryTypes); + GET_LIST.put(Method.GET_DATE, + concat(charTypes, EnumSet.of(DATE, TIMESTAMP))); + GET_LIST.put(Method.GET_TIME, + concat(charTypes, EnumSet.of(TIME, TIMESTAMP))); + GET_LIST.put(Method.GET_TIMESTAMP, + concat(charTypes, EnumSet.of(DATE, TIME, TIMESTAMP))); + GET_LIST.put(Method.GET_ASCII_STREAM, + concat(charTypes, binaryTypes, EnumSet.of(CLOB, NCLOB))); + GET_LIST.put(Method.GET_BINARY_STREAM, + concat(binaryTypes, EnumSet.of(BLOB, SQLXML))); + GET_LIST.put(Method.GET_CHARACTER_STREAM, + concat(charTypes, binaryTypes, ncharTypes, + EnumSet.of(CLOB, NCLOB, SQLXML))); + GET_LIST.put(Method.GET_N_CHARACTER_STREAM, + concat( + charTypes, binaryTypes, ncharTypes, EnumSet.of(CLOB, NCLOB, SQLXML))); + GET_LIST.put(Method.GET_CLOB, EnumSet.of(CLOB, NCLOB)); + GET_LIST.put(Method.GET_N_CLOB, EnumSet.of(CLOB, NCLOB)); + GET_LIST.put(Method.GET_BLOB, EnumSet.of(BLOB)); + GET_LIST.put(Method.GET_ARRAY, EnumSet.of(ARRAY)); + GET_LIST.put(Method.GET_REF, EnumSet.of(REF)); + GET_LIST.put(Method.GET_BLOB, EnumSet.of(BLOB)); + GET_LIST.put(Method.GET_URL, EnumSet.of(DATALINK)); + GET_LIST.put(Method.GET_OBJECT, EnumSet.allOf(SqlType.class)); + GET_LIST.put(Method.GET_ROW_ID, EnumSet.of(ROWID)); + GET_LIST.put(Method.GET_SQLXML, EnumSet.of(SQLXML)); + } + + @SafeVarargs + private static <E extends Enum<E>> EnumSet<E> concat(Collection<E>... ess) { + final List<E> list = new ArrayList<>(); + for (Collection<E> es : ess) { + list.addAll(es); + } + return EnumSet.copyOf(list); + } + + /** Returns whether {@link java.sql.PreparedStatement#setObject} and + * {@link PreparedStatement#setNull} can assign a value of a particular class + * to a column of a particular SQL type. + * + * <p>The JDBC standard describes the mapping in table <a href="#B5">B-5</a>. + */ + public static boolean canSet(Class aClass, SqlType sqlType) { + final EnumSet<SqlType> sqlTypes = SET_LIST.get(aClass); + return sqlTypes != null && sqlTypes.contains(sqlType); + } + + /** Returns whether {@link java.sql.ResultSet#getInt(int)} and similar methods + * can convert a value to a particular SQL type. + * + * <p>The JDBC standard describes the mapping in table <a href="#B6">B-6</a>. + */ + public static boolean canGet(Method method, SqlType sqlType) { + final EnumSet<SqlType> sqlTypes = GET_LIST.get(method); + return sqlTypes != null && sqlTypes.contains(sqlType); + } + + /** Getter methods in {@link java.sql.ResultSet}. */ + public enum Method { + GET_BYTE("getByte"), + GET_SHORT("getShort"), + GET_INT("getInt"), + GET_LONG("getLong"), + GET_FLOAT("getFloat"), + GET_DOUBLE("getDouble"), + GET_BIG_DECIMAL("getBigDecimal"), + GET_BOOLEAN("getBoolean"), + GET_STRING("getString"), + GET_N_STRING("getNString"), + GET_BYTES("getBytes"), + GET_DATE("getDate"), + GET_TIME("getTime"), + GET_TIMESTAMP("getTimestamp"), + GET_ASCII_STREAM("getAsciiStream"), + GET_BINARY_STREAM("getBinaryStream"), + GET_CHARACTER_STREAM("getCharacterStream"), + GET_N_CHARACTER_STREAM("getNCharacterStream"), + GET_CLOB("getClob"), + GET_N_CLOB("getNClob"), + GET_BLOB("getBlob"), + GET_ARRAY("getArray"), + GET_REF("getRef"), + GET_URL("getURL"), + GET_OBJECT("getObject"), + GET_ROW_ID("getRowId"), + GET_SQLXML("getSQLXML"); + + public final String methodName; + + Method(String methodName) { + this.methodName = methodName; + } + } +} + +// End SqlType.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java b/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java new file mode 100644 index 0000000..b1fe787 --- /dev/null +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/UnregisteredDriver.java @@ -0,0 +1,255 @@ +/* + * 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.calcite.avatica; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation of JDBC driver that does not register itself. + * + * <p>You can easily create a "vanity driver" that recognizes its own + * URL prefix as a sub-class of this class. Per the JDBC specification it + * must register itself when the class is loaded.</p> + * + * <p>Derived classes must implement {@link #createDriverVersion()} and + * {@link #getConnectStringPrefix()}, and may override + * {@link #createFactory()}.</p> + * + * <p>The provider must implement:</p> + * <ul> + * <li>{@link Meta#prepare(Meta.ConnectionHandle, String, long)} + * <li>{@link Meta#createIterable(org.apache.calcite.avatica.Meta.StatementHandle, org.apache.calcite.avatica.QueryState, org.apache.calcite.avatica.Meta.Signature, java.util.List, Meta.Frame)} + * </ul> + */ +public abstract class UnregisteredDriver implements java.sql.Driver { + final DriverVersion version; + protected final AvaticaFactory factory; + public final Handler handler; + + protected UnregisteredDriver() { + this.factory = createFactory(); + this.version = createDriverVersion(); + this.handler = createHandler(); + } + + /** + * Creates a factory for JDBC objects (connection, statement). + * Called from the driver constructor. + * + * <p>The default implementation calls {@link JdbcVersion#current}, + * then {@link #getFactoryClassName} with that version, + * then passes that class name to {@link #instantiateFactory(String)}. + * This approach is recommended it does not include in the code references + * to classes that may not be instantiable in all JDK versions. + * But drivers are free to do it their own way.</p> + * + * @return JDBC object factory + */ + protected AvaticaFactory createFactory() { + return instantiateFactory(getFactoryClassName(JdbcVersion.current())); + } + + /** Creates a Handler. */ + protected Handler createHandler() { + return new HandlerImpl(); + } + + /** + * Returns the name of a class to be factory for JDBC objects + * (connection, statement) appropriate for the current JDBC version. + */ + protected String getFactoryClassName(JdbcVersion jdbcVersion) { + switch (jdbcVersion) { + case JDBC_30: + case JDBC_40: + throw new IllegalArgumentException("JDBC version not supported: " + + jdbcVersion); + case JDBC_41: + default: + return "org.apache.calcite.avatica.AvaticaJdbc41Factory"; + } + } + + /** + * Creates an object describing the name and version of this driver. + * Called from the driver constructor. + */ + protected abstract DriverVersion createDriverVersion(); + + /** + * Returns the connection properties supported by this driver. + */ + protected Collection<ConnectionProperty> getConnectionProperties() { + return Arrays.<ConnectionProperty>asList( + BuiltInConnectionProperty.values()); + } + + /** Helper method for creating factories. */ + protected static AvaticaFactory instantiateFactory(String factoryClassName) { + try { + final Class<?> clazz = Class.forName(factoryClassName); + return (AvaticaFactory) clazz.newInstance(); + } catch (ClassNotFoundException e) { + throw handle("Error loading factory " + factoryClassName, e); + } catch (IllegalAccessException e) { + throw handle("Error loading factory " + factoryClassName, e); + } catch (InstantiationException e) { + throw handle("Error loading factory " + factoryClassName, e); + } catch (Throwable e) { + // It is not usually good to catch Throwable. But class loading can fail + // with serious errors such as java.lang.NoClassDefFoundError + throw handle("Error loading factory " + factoryClassName, e); + } + } + + private static RuntimeException handle(String msg, Throwable e) { + Logger.getLogger("").log(Level.SEVERE, msg, e); + throw new RuntimeException(msg, e); + } + + public Connection connect(String url, Properties info) throws SQLException { + if (!acceptsURL(url)) { + return null; + } + final String prefix = getConnectStringPrefix(); + assert url.startsWith(prefix); + final String urlSuffix = url.substring(prefix.length()); + final Properties info2 = ConnectStringParser.parse(urlSuffix, info); + final AvaticaConnection connection = + factory.newConnection(this, factory, url, info2); + handler.onConnectionInit(connection); + return connection; + } + + public boolean acceptsURL(String url) throws SQLException { + return url.startsWith(getConnectStringPrefix()); + } + + /** Returns the prefix of the connect string that this driver will recognize + * as its own. For example, "jdbc:calcite:". */ + protected abstract String getConnectStringPrefix(); + + public DriverPropertyInfo[] getPropertyInfo( + String url, Properties info) throws SQLException { + List<DriverPropertyInfo> list = new ArrayList<DriverPropertyInfo>(); + + // First, add the contents of info + for (Map.Entry<Object, Object> entry : info.entrySet()) { + list.add( + new DriverPropertyInfo( + (String) entry.getKey(), + (String) entry.getValue())); + } + // Next, add property definitions not mentioned in info + for (ConnectionProperty p : getConnectionProperties()) { + if (info.containsKey(p.name())) { + continue; + } + list.add(new DriverPropertyInfo(p.name(), null)); + } + return list.toArray(new DriverPropertyInfo[list.size()]); + } + + // JDBC 4.1 support (JDK 1.7 and higher) + public Logger getParentLogger() { + return Logger.getLogger(""); + } + + /** + * Returns the driver version object. Not in the JDBC API. + * + * @return Driver version + */ + public DriverVersion getDriverVersion() { + return version; + } + + public final int getMajorVersion() { + return version.majorVersion; + } + + public final int getMinorVersion() { + return version.minorVersion; + } + + public boolean jdbcCompliant() { + return version.jdbcCompliant; + } + + /** + * Registers this driver with the driver manager. + */ + protected void register() { + try { + DriverManager.registerDriver(this); + } catch (SQLException e) { + System.out.println( + "Error occurred while registering JDBC driver " + + this + ": " + e.toString()); + } + } + + /** Creates a service handler that will give connections from this Driver + * their behavior. */ + public abstract Meta createMeta(AvaticaConnection connection); + + /** JDBC version. */ + protected enum JdbcVersion { + /** Unknown JDBC version. */ + JDBC_UNKNOWN, + /** JDBC version 3.0. Generally associated with JDK 1.5. */ + JDBC_30, + /** JDBC version 4.0. Generally associated with JDK 1.6. */ + JDBC_40, + /** JDBC version 4.1. Generally associated with JDK 1.7. */ + JDBC_41; + + /** Deduces the current JDBC version. */ + public static JdbcVersion current() { + try { + // If java.sql.PseudoColumnUsage is present, we are running JDBC + // 4.1 or later. + Class.forName("java.sql.PseudoColumnUsage"); + return JDBC_41; + } catch (ClassNotFoundException e) { + // java.sql.PseudoColumnUsage is not present. This means we are + // running JDBC 4.0 or earlier. + try { + Class.forName("java.sql.Wrapper"); + return JDBC_40; + } catch (ClassNotFoundException e2) { + // java.sql.Wrapper is not present. This means we are + // running JDBC 3.0 or earlier (probably JDK 1.5). + return JDBC_30; + } + } + } + } +} + +// End UnregisteredDriver.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java b/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java new file mode 100644 index 0000000..89a9fbb --- /dev/null +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/package-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/** + * Avatica JDBC framework. + */ +@PackageMarker +package org.apache.calcite.avatica; + +import org.apache.calcite.avatica.util.PackageMarker; + +// End package-info.java
