All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.calcite.avatica.MetaImpl Maven / Gradle / Ivy

There is a newer version: 1.6.0
Show newest version
/*
 * 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.ArrayIteratorCursor;
import org.apache.calcite.avatica.util.Cursor;
import org.apache.calcite.avatica.util.IteratorCursor;
import org.apache.calcite.avatica.util.ListIteratorCursor;
import org.apache.calcite.avatica.util.MapIteratorCursor;
import org.apache.calcite.avatica.util.RecordIteratorCursor;

import com.fasterxml.jackson.annotation.JsonIgnore;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Basic implementation of {@link Meta}.
 *
 * 

Each sub-class must implement the two remaining abstract methods, * {@link #prepare} and * {@link #prepareAndExecute}. * It should also override metadata methods such as {@link #getCatalogs()} and * {@link #getTables} for the element types for which it has instances; the * default metadata methods return empty collections. */ public abstract class MetaImpl implements Meta { /** The {@link AvaticaConnection} backing {@code this}. */ protected final AvaticaConnection connection; /** Represents the various states specific to {@link #connection}. * *

Note: this instance is used recursively with {@link #connection}'s getter and setter * methods.

*/ protected final ConnectionPropertiesImpl connProps; public MetaImpl(AvaticaConnection connection) { this.connection = connection; this.connProps = new ConnectionPropertiesImpl(); } /** Uses a {@link org.apache.calcite.avatica.Meta.CursorFactory} to convert * an {@link Iterable} into a * {@link org.apache.calcite.avatica.util.Cursor}. */ public static Cursor createCursor(CursorFactory cursorFactory, Iterable iterable) { switch (cursorFactory.style) { case OBJECT: return new IteratorCursor(iterable.iterator()) { protected Getter createGetter(int ordinal) { return new ObjectGetter(ordinal); } }; case ARRAY: @SuppressWarnings("unchecked") final Iterable iterable1 = (Iterable) (Iterable) iterable; return new ArrayIteratorCursor(iterable1.iterator()); case RECORD: @SuppressWarnings("unchecked") final Class clazz = cursorFactory.clazz; return new RecordIteratorCursor(iterable.iterator(), clazz); case RECORD_PROJECTION: @SuppressWarnings("unchecked") final Class clazz2 = cursorFactory.clazz; return new RecordIteratorCursor(iterable.iterator(), clazz2, cursorFactory.fields); case LIST: @SuppressWarnings("unchecked") final Iterable> iterable2 = (Iterable>) (Iterable) iterable; return new ListIteratorCursor(iterable2.iterator()); case MAP: @SuppressWarnings("unchecked") final Iterable> iterable3 = (Iterable>) (Iterable) iterable; return new MapIteratorCursor(iterable3.iterator(), cursorFactory.fieldNames); default: throw new AssertionError("unknown style: " + cursorFactory.style); } } public static List> collect(CursorFactory cursorFactory, Iterable iterable, List> list) { switch (cursorFactory.style) { case OBJECT: for (Object o : iterable) { list.add(Collections.singletonList(o)); } return list; case ARRAY: @SuppressWarnings("unchecked") final Iterable iterable1 = (Iterable) (Iterable) iterable; for (Object[] objects : iterable1) { list.add(Arrays.asList(objects)); } return list; case RECORD: case RECORD_PROJECTION: final Field[] fields; switch (cursorFactory.style) { case RECORD: fields = cursorFactory.clazz.getFields(); break; default: fields = cursorFactory.fields.toArray( new Field[cursorFactory.fields.size()]); } for (Object o : iterable) { final Object[] objects = new Object[fields.length]; for (int i = 0; i < fields.length; i++) { Field field = fields[i]; try { objects[i] = field.get(o); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } list.add(Arrays.asList(objects)); } return list; case LIST: @SuppressWarnings("unchecked") final Iterable> iterable2 = (Iterable>) (Iterable) iterable; for (List objects : iterable2) { list.add(objects); } return list; case MAP: @SuppressWarnings("unchecked") final Iterable> iterable3 = (Iterable>) (Iterable) iterable; for (Map map : iterable3) { final List objects = new ArrayList(); for (String fieldName : cursorFactory.fieldNames) { objects.add(map.get(fieldName)); } list.add(objects); } return list; default: throw new AssertionError("unknown style: " + cursorFactory.style); } } @Override public void closeConnection(ConnectionHandle ch) { // TODO: implement // // lots of Calcite tests break with this simple implementation, // requires investigation // try { // connection.close(); // } catch (SQLException e) { // throw new RuntimeException(e); // } } @Override public ConnectionProperties connectionSync(ConnectionHandle ch, ConnectionProperties connProps) { this.connProps.merge(connProps); this.connProps.setDirty(false); return this.connProps; } public StatementHandle createStatement(ConnectionHandle ch) { return new StatementHandle(ch.id, connection.statementCount++, null); } /** Creates an empty result set. Useful for JDBC metadata methods that are * not implemented or which query entities that are not supported (e.g. * triggers in Lingual). */ protected MetaResultSet createEmptyResultSet(final Class clazz) { return createResultSet(Collections.emptyMap(), fieldMetaData(clazz).columns, CursorFactory.deduce(fieldMetaData(clazz).columns, null), Frame.EMPTY); } protected static ColumnMetaData columnMetaData(String name, int index, Class type) { TypeInfo pair = TypeInfo.m.get(type); ColumnMetaData.Rep rep = ColumnMetaData.Rep.VALUE_MAP.get(type); ColumnMetaData.AvaticaType scalarType = ColumnMetaData.scalar(pair.sqlType, pair.sqlTypeName, rep); return new ColumnMetaData( index, false, true, false, false, pair.primitive ? DatabaseMetaData.columnNullable : DatabaseMetaData.columnNoNulls, true, -1, name, name, null, 0, 0, null, null, scalarType, true, false, false, scalarType.columnClassName()); } protected static ColumnMetaData.StructType fieldMetaData(Class clazz) { final List list = new ArrayList(); for (Field field : clazz.getFields()) { if (Modifier.isPublic(field.getModifiers()) && !Modifier.isStatic(field.getModifiers())) { list.add( columnMetaData( AvaticaUtils.camelToUpper(field.getName()), list.size() + 1, field.getType())); } } return ColumnMetaData.struct(list); } protected MetaResultSet createResultSet( Map internalParameters, List columns, CursorFactory cursorFactory, Frame firstFrame) { try { final AvaticaStatement statement = connection.createStatement(); final Signature signature = new Signature(columns, "", Collections.emptyList(), internalParameters, cursorFactory); return MetaResultSet.create(connection.id, statement.getId(), true, signature, firstFrame); } catch (SQLException e) { throw new RuntimeException(e); } } /** An object that has a name. */ public interface Named { @JsonIgnore String getName(); } /** Metadata describing a column. */ public static class MetaColumn implements Named { public final String tableCat; public final String tableSchem; public final String tableName; public final String columnName; public final int dataType; public final String typeName; public final int columnSize; public final String bufferLength = null; public final Integer decimalDigits; public final int numPrecRadix; public final int nullable; public final String remarks = null; public final String columnDef = null; public final String sqlDataType = null; public final String sqlDatetimeSub = null; public final int charOctetLength; public final int ordinalPosition; public final String isNullable; public final String scopeCatalog = null; public final String scopeTable = null; public final String sourceDataType = null; public final String isAutoincrement = null; public final String isGeneratedcolumn = null; public MetaColumn( String tableCat, String tableSchem, String tableName, String columnName, int dataType, String typeName, int columnSize, Integer decimalDigits, int numPrecRadix, int nullable, int charOctetLength, int ordinalPosition, String isNullable) { this.tableCat = tableCat; this.tableSchem = tableSchem; this.tableName = tableName; this.columnName = columnName; this.dataType = dataType; this.typeName = typeName; this.columnSize = columnSize; this.decimalDigits = decimalDigits; this.numPrecRadix = numPrecRadix; this.nullable = nullable; this.charOctetLength = charOctetLength; this.ordinalPosition = ordinalPosition; this.isNullable = isNullable; } public String getName() { return columnName; } } /** Metadata describing a table. */ public static class MetaTable implements Named { public final String tableCat; public final String tableSchem; public final String tableName; public final String tableType; public final String remarks = null; public final String typeCat = null; public final String typeSchem = null; public final String typeName = null; public final String selfReferencingColName = null; public final String refGeneration = null; public MetaTable(String tableCat, String tableSchem, String tableName, String tableType) { this.tableCat = tableCat; this.tableSchem = tableSchem; this.tableName = tableName; this.tableType = tableType; } public String getName() { return tableName; } } /** Metadata describing a schema. */ public static class MetaSchema implements Named { public final String tableCatalog; public final String tableSchem; public MetaSchema( String tableCatalog, String tableSchem) { this.tableCatalog = tableCatalog; this.tableSchem = tableSchem; } public String getName() { return tableSchem; } } /** Metadata describing a catalog. */ public static class MetaCatalog implements Named { public final String tableCatalog; public MetaCatalog( String tableCatalog) { this.tableCatalog = tableCatalog; } public String getName() { return tableCatalog; } } /** Metadata describing a table type. */ public static class MetaTableType { public final String tableType; public MetaTableType(String tableType) { this.tableType = tableType; } } /** Metadata describing a procedure. */ public static class MetaProcedure { } /** Metadata describing a procedure column. */ public static class MetaProcedureColumn { } /** Metadata describing a column privilege. */ public static class MetaColumnPrivilege { } /** Metadata describing a table privilege. */ public static class MetaTablePrivilege { } /** Metadata describing the best identifier for a row. */ public static class MetaBestRowIdentifier { } /** Metadata describing a version column. */ public static class MetaVersionColumn { public final short scope; public final String columnName; public final int dataType; public final String typeName; public final int columnSize; public final int bufferLength; public final short decimalDigits; public final short pseudoColumn; MetaVersionColumn(short scope, String columnName, int dataType, String typeName, int columnSize, int bufferLength, short decimalDigits, short pseudoColumn) { this.scope = scope; this.columnName = columnName; this.dataType = dataType; this.typeName = typeName; this.columnSize = columnSize; this.bufferLength = bufferLength; this.decimalDigits = decimalDigits; this.pseudoColumn = pseudoColumn; } } /** Metadata describing a primary key. */ public static class MetaPrimaryKey { public final String tableCat; public final String tableSchem; public final String tableName; public final String columnName; public final short keySeq; public final String pkName; MetaPrimaryKey(String tableCat, String tableSchem, String tableName, String columnName, short keySeq, String pkName) { this.tableCat = tableCat; this.tableSchem = tableSchem; this.tableName = tableName; this.columnName = columnName; this.keySeq = keySeq; this.pkName = pkName; } } /** Metadata describing an imported key. */ public static class MetaImportedKey { } /** Metadata describing an exported key. */ public static class MetaExportedKey { } /** Metadata describing a cross reference. */ public static class MetaCrossReference { } /** Metadata describing type info. */ public static class MetaTypeInfo { } /** Metadata describing index info. */ public static class MetaIndexInfo { } /** Metadata describing a user-defined type. */ public static class MetaUdt { } /** Metadata describing a super-type. */ public static class MetaSuperType { } /** Metadata describing an attribute. */ public static class MetaAttribute { } /** Metadata describing a client info property. */ public static class MetaClientInfoProperty { } /** Metadata describing a function. */ public static class MetaFunction { } /** Metadata describing a function column. */ public static class MetaFunctionColumn { } /** Metadata describing a pseudo column. */ public static class MetaPseudoColumn { } /** Metadata describing a super-table. */ public static class MetaSuperTable { } public String getSqlKeywords() { return ""; } public String getNumericFunctions() { return ""; } public String getStringFunctions() { return ""; } public String getSystemFunctions() { return ""; } public String getTimeDateFunctions() { return ""; } public MetaResultSet getTables(String catalog, Pat schemaPattern, Pat tableNamePattern, List typeList) { return createEmptyResultSet(MetaTable.class); } public MetaResultSet getColumns(String catalog, Pat schemaPattern, Pat tableNamePattern, Pat columnNamePattern) { return createEmptyResultSet(MetaColumn.class); } public MetaResultSet getSchemas(String catalog, Pat schemaPattern) { return createEmptyResultSet(MetaSchema.class); } public MetaResultSet getCatalogs() { return createEmptyResultSet(MetaCatalog.class); } public MetaResultSet getTableTypes() { return createEmptyResultSet(MetaTableType.class); } public MetaResultSet getProcedures(String catalog, Pat schemaPattern, Pat procedureNamePattern) { return createEmptyResultSet(MetaProcedure.class); } public MetaResultSet getProcedureColumns(String catalog, Pat schemaPattern, Pat procedureNamePattern, Pat columnNamePattern) { return createEmptyResultSet(MetaProcedureColumn.class); } public MetaResultSet getColumnPrivileges(String catalog, String schema, String table, Pat columnNamePattern) { return createEmptyResultSet(MetaColumnPrivilege.class); } public MetaResultSet getTablePrivileges(String catalog, Pat schemaPattern, Pat tableNamePattern) { return createEmptyResultSet(MetaTablePrivilege.class); } public MetaResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) { return createEmptyResultSet(MetaBestRowIdentifier.class); } public MetaResultSet getVersionColumns(String catalog, String schema, String table) { return createEmptyResultSet(MetaVersionColumn.class); } public MetaResultSet getPrimaryKeys(String catalog, String schema, String table) { return createEmptyResultSet(MetaPrimaryKey.class); } public MetaResultSet getImportedKeys(String catalog, String schema, String table) { return createEmptyResultSet(MetaImportedKey.class); } public MetaResultSet getExportedKeys(String catalog, String schema, String table) { return createEmptyResultSet(MetaExportedKey.class); } public MetaResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) { return createEmptyResultSet(MetaCrossReference.class); } public MetaResultSet getTypeInfo() { return createEmptyResultSet(MetaTypeInfo.class); } public MetaResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) { return createEmptyResultSet(MetaIndexInfo.class); } public MetaResultSet getUDTs(String catalog, Pat schemaPattern, Pat typeNamePattern, int[] types) { return createEmptyResultSet(MetaUdt.class); } public MetaResultSet getSuperTypes(String catalog, Pat schemaPattern, Pat typeNamePattern) { return createEmptyResultSet(MetaSuperType.class); } public MetaResultSet getSuperTables(String catalog, Pat schemaPattern, Pat tableNamePattern) { return createEmptyResultSet(MetaSuperTable.class); } public MetaResultSet getAttributes(String catalog, Pat schemaPattern, Pat typeNamePattern, Pat attributeNamePattern) { return createEmptyResultSet(MetaAttribute.class); } public MetaResultSet getClientInfoProperties() { return createEmptyResultSet(MetaClientInfoProperty.class); } public MetaResultSet getFunctions(String catalog, Pat schemaPattern, Pat functionNamePattern) { return createEmptyResultSet(MetaFunction.class); } public MetaResultSet getFunctionColumns(String catalog, Pat schemaPattern, Pat functionNamePattern, Pat columnNamePattern) { return createEmptyResultSet(MetaFunctionColumn.class); } public MetaResultSet getPseudoColumns(String catalog, Pat schemaPattern, Pat tableNamePattern, Pat columnNamePattern) { return createEmptyResultSet(MetaPseudoColumn.class); } public Iterable createIterable(StatementHandle handle, Signature signature, List parameterValues, Frame firstFrame) { if (firstFrame != null && firstFrame.done) { return firstFrame.rows; } return new FetchIterable(handle, firstFrame, parameterValues); } public Frame fetch(StatementHandle h, List parameterValues, int offset, int fetchMaxRowCount) { return null; } /** Information about a type. */ private static class TypeInfo { private static Map, TypeInfo> m = new HashMap, TypeInfo>(); static { put(boolean.class, true, Types.BOOLEAN, "BOOLEAN"); put(Boolean.class, false, Types.BOOLEAN, "BOOLEAN"); put(byte.class, true, Types.TINYINT, "TINYINT"); put(Byte.class, false, Types.TINYINT, "TINYINT"); put(short.class, true, Types.SMALLINT, "SMALLINT"); put(Short.class, false, Types.SMALLINT, "SMALLINT"); put(int.class, true, Types.INTEGER, "INTEGER"); put(Integer.class, false, Types.INTEGER, "INTEGER"); put(long.class, true, Types.BIGINT, "BIGINT"); put(Long.class, false, Types.BIGINT, "BIGINT"); put(float.class, true, Types.FLOAT, "FLOAT"); put(Float.class, false, Types.FLOAT, "FLOAT"); put(double.class, true, Types.DOUBLE, "DOUBLE"); put(Double.class, false, Types.DOUBLE, "DOUBLE"); put(String.class, false, Types.VARCHAR, "VARCHAR"); put(java.sql.Date.class, false, Types.DATE, "DATE"); put(Time.class, false, Types.TIME, "TIME"); put(Timestamp.class, false, Types.TIMESTAMP, "TIMESTAMP"); } private final boolean primitive; private final int sqlType; private final String sqlTypeName; public TypeInfo(boolean primitive, int sqlType, String sqlTypeName) { this.primitive = primitive; this.sqlType = sqlType; this.sqlTypeName = sqlTypeName; } static void put(Class clazz, boolean primitive, int sqlType, String sqlTypeName) { m.put(clazz, new TypeInfo(primitive, sqlType, sqlTypeName)); } } /** Iterator that never returns any elements. */ private static class EmptyIterator implements Iterator { public static final Iterator INSTANCE = new EmptyIterator(); public void remove() { throw new UnsupportedOperationException(); } public boolean hasNext() { return false; } public Object next() { throw new NoSuchElementException(); } } /** Iterable that yields an iterator over rows coming from a sequence of * {@link Frame}s. */ private class FetchIterable implements Iterable { private final StatementHandle handle; private final Frame firstFrame; private final List parameterValues; public FetchIterable(StatementHandle handle, Frame firstFrame, List parameterValues) { this.handle = handle; this.firstFrame = firstFrame; this.parameterValues = parameterValues; } public Iterator iterator() { return new FetchIterator(handle, firstFrame, parameterValues); } } /** Iterator over rows coming from a sequence of {@link Frame}s. */ private class FetchIterator implements Iterator { private final StatementHandle handle; private Frame frame; private Iterator rows; private List parameterValues; public FetchIterator(StatementHandle handle, Frame firstFrame, List parameterValues) { this.handle = handle; this.parameterValues = parameterValues; if (firstFrame == null) { frame = Frame.MORE; rows = EmptyIterator.INSTANCE; } else { frame = firstFrame; rows = firstFrame.rows.iterator(); } moveNext(); } public void remove() { throw new UnsupportedOperationException("remove"); } public boolean hasNext() { return rows != null; } public Object next() { if (rows == null) { throw new NoSuchElementException(); } final Object o = rows.next(); moveNext(); return o; } private void moveNext() { for (;;) { if (rows.hasNext()) { break; } if (frame.done) { rows = null; break; } frame = fetch(handle, parameterValues, frame.offset, 100); parameterValues = null; // don't execute next time if (frame == null) { rows = null; break; } // It is valid for rows to be empty, so we go around the loop again to // check rows = frame.rows.iterator(); } } } } // End MetaImpl.java