/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb; import java.util.SortedSet; import java.util.TreeSet; import org.json_voltpatches.JSONException; import org.json_voltpatches.JSONObject; import org.voltcore.logging.VoltLogger; import org.voltdb.VoltTable.ColumnInfo; import org.voltdb.catalog.Catalog; import org.voltdb.catalog.Column; import org.voltdb.catalog.ColumnRef; import org.voltdb.catalog.Connector; import org.voltdb.catalog.Constraint; import org.voltdb.catalog.Database; import org.voltdb.catalog.Function; import org.voltdb.catalog.Index; import org.voltdb.catalog.ProcParameter; import org.voltdb.catalog.Procedure; import org.voltdb.catalog.Table; import org.voltdb.types.ConstraintType; import org.voltdb.types.IndexType; import org.voltdb.types.VoltDecimalHelper; import org.voltdb.utils.CatalogUtil; import org.voltdb.utils.InMemoryJarfile; public class JdbcDatabaseMetaDataGenerator { private static final VoltLogger hostLog = new VoltLogger("HOST"); public static final String JSON_PARTITION_PARAMETER = "partitionParameter"; public static final String JSON_PARTITION_PARAMETER_TYPE = "partitionParameterType"; public static final String JSON_SINGLE_PARTITION = "singlePartition"; public static final String JSON_READ_ONLY = "readOnly"; public static final String JSON_PARTITION_COLUMN = "partitionColumn"; public static final String JSON_SOURCE_TABLE = "sourceTable"; public static final String JSON_LIMIT_PARTITION_ROWS_DELETE_STMT = "limitPartitionRowsDeleteStmt"; public static final String JSON_DRED_TABLE = "drEnabled"; public static final String JSON_ERROR = "error"; static public final ColumnInfo[] TABLE_SCHEMA = new ColumnInfo[] { new ColumnInfo("TABLE_CAT", VoltType.STRING), new ColumnInfo("TABLE_SCHEM", VoltType.STRING), new ColumnInfo("TABLE_NAME", VoltType.STRING), new ColumnInfo("TABLE_TYPE", VoltType.STRING), new ColumnInfo("REMARKS", VoltType.STRING), new ColumnInfo("TYPE_CAT", VoltType.STRING), new ColumnInfo("TYPE_SCHEM", VoltType.STRING), new ColumnInfo("TYPE_NAME", VoltType.STRING), new ColumnInfo("SELF_REFERENCING_COL_NAME", VoltType.STRING), new ColumnInfo("REF_GENERATION", VoltType.STRING) }; static public final ColumnInfo[] COLUMN_SCHEMA = new ColumnInfo[] { new ColumnInfo("TABLE_CAT", VoltType.STRING), new ColumnInfo("TABLE_SCHEM", VoltType.STRING), new ColumnInfo("TABLE_NAME", VoltType.STRING), new ColumnInfo("COLUMN_NAME", VoltType.STRING), new ColumnInfo("DATA_TYPE", VoltType.INTEGER), new ColumnInfo("TYPE_NAME", VoltType.STRING), new ColumnInfo("COLUMN_SIZE", VoltType.INTEGER), new ColumnInfo("BUFFER_LENGTH", VoltType.INTEGER), new ColumnInfo("DECIMAL_DIGITS", VoltType.INTEGER), new ColumnInfo("NUM_PREC_RADIX", VoltType.INTEGER), new ColumnInfo("NULLABLE", VoltType.INTEGER), new ColumnInfo("REMARKS", VoltType.STRING), new ColumnInfo("COLUMN_DEF", VoltType.STRING), new ColumnInfo("SQL_DATA_TYPE", VoltType.INTEGER), new ColumnInfo("SQL_DATETIME_SUB", VoltType.INTEGER), new ColumnInfo("CHAR_OCTET_LENGTH", VoltType.INTEGER), new ColumnInfo("ORDINAL_POSITION", VoltType.INTEGER), new ColumnInfo("IS_NULLABLE", VoltType.STRING), new ColumnInfo("SCOPE_CATALOG", VoltType.STRING), new ColumnInfo("SCOPE_SCHEMA", VoltType.STRING), new ColumnInfo("SCOPE_TABLE", VoltType.STRING), new ColumnInfo("SOURCE_DATA_TYPE", VoltType.SMALLINT), new ColumnInfo("IS_AUTOINCREMENT", VoltType.STRING) }; static public final ColumnInfo[] INDEXINFO_SCHEMA = new ColumnInfo[] { new ColumnInfo("TABLE_CAT", VoltType.STRING), new ColumnInfo("TABLE_SCHEM", VoltType.STRING), new ColumnInfo("TABLE_NAME", VoltType.STRING), new ColumnInfo("NON_UNIQUE", VoltType.TINYINT), // SHould be bool, but... new ColumnInfo("INDEX_QUALIFIER", VoltType.STRING), new ColumnInfo("INDEX_NAME", VoltType.STRING), new ColumnInfo("TYPE", VoltType.SMALLINT), new ColumnInfo("ORDINAL_POSITION", VoltType.SMALLINT), new ColumnInfo("COLUMN_NAME", VoltType.STRING), new ColumnInfo("ASC_OR_DESC", VoltType.STRING), new ColumnInfo("CARDINALITY", VoltType.INTEGER), new ColumnInfo("PAGES", VoltType.INTEGER), new ColumnInfo("FILTER_CONDITION", VoltType.STRING) }; static public final ColumnInfo[] PRIMARYKEYS_SCHEMA = new ColumnInfo[] { new ColumnInfo("TABLE_CAT", VoltType.STRING), new ColumnInfo("TABLE_SCHEM", VoltType.STRING), new ColumnInfo("TABLE_NAME", VoltType.STRING), new ColumnInfo("COLUMN_NAME", VoltType.STRING), new ColumnInfo("KEY_SEQ", VoltType.SMALLINT), new ColumnInfo("PK_NAME", VoltType.STRING) }; static public final ColumnInfo[] FUNCTIONS_SCHEMA = new ColumnInfo[] { new ColumnInfo("FUNCTION_TYPE", VoltType.STRING), new ColumnInfo("FUNCTION_NAME", VoltType.STRING), new ColumnInfo("CLASS_NAME", VoltType.STRING), new ColumnInfo("METHOD_NAME", VoltType.STRING) }; static public final ColumnInfo[] PROCEDURES_SCHEMA = new ColumnInfo[] { new ColumnInfo("PROCEDURE_CAT", VoltType.STRING), new ColumnInfo("PROCEDURE_SCHEM", VoltType.STRING), new ColumnInfo("PROCEDURE_NAME", VoltType.STRING), new ColumnInfo("RESERVED1", VoltType.STRING), new ColumnInfo("RESERVED2", VoltType.STRING), new ColumnInfo("RESERVED3", VoltType.STRING), new ColumnInfo("REMARKS", VoltType.STRING), new ColumnInfo("PROCEDURE_TYPE", VoltType.SMALLINT), new ColumnInfo("SPECIFIC_NAME", VoltType.STRING) }; static public final ColumnInfo[] PROCEDURECOLUMNS_SCHEMA = new ColumnInfo[] { new ColumnInfo("PROCEDURE_CAT", VoltType.STRING), new ColumnInfo("PROCEDURE_SCHEM", VoltType.STRING), new ColumnInfo("PROCEDURE_NAME", VoltType.STRING), new ColumnInfo("COLUMN_NAME", VoltType.STRING), new ColumnInfo("COLUMN_TYPE", VoltType.SMALLINT), new ColumnInfo("DATA_TYPE", VoltType.INTEGER), new ColumnInfo("TYPE_NAME", VoltType.STRING), new ColumnInfo("PRECISION", VoltType.INTEGER), new ColumnInfo("LENGTH", VoltType.INTEGER), new ColumnInfo("SCALE", VoltType.SMALLINT), new ColumnInfo("RADIX", VoltType.SMALLINT), new ColumnInfo("NULLABLE", VoltType.SMALLINT), new ColumnInfo("REMARKS", VoltType.STRING), new ColumnInfo("COLUMN_DEF", VoltType.STRING), new ColumnInfo("SQL_DATA_TYPE", VoltType.INTEGER), new ColumnInfo("SQL_DATETIME_SUB", VoltType.INTEGER), new ColumnInfo("CHAR_OCTET_LENGTH", VoltType.INTEGER), new ColumnInfo("ORDINAL_POSITION", VoltType.INTEGER), new ColumnInfo("IS_NULLABLE", VoltType.STRING), new ColumnInfo("SPECIFIC_NAME", VoltType.STRING) }; static public final ColumnInfo[] TYPEINFO_SCHEMA = new ColumnInfo[] { new ColumnInfo("TYPE_NAME", VoltType.STRING), new ColumnInfo("DATA_TYPE", VoltType.INTEGER), new ColumnInfo("PRECISION", VoltType.INTEGER), new ColumnInfo("LITERAL_PREFIX", VoltType.STRING), new ColumnInfo("LITERAL_SUFFIX", VoltType.STRING), new ColumnInfo("CREATE_PARAMS", VoltType.STRING), new ColumnInfo("NULLABLE", VoltType.SMALLINT), new ColumnInfo("CASE_SENSITIVE", VoltType.TINYINT), //should be bool... new ColumnInfo("SEARCHABLE", VoltType.SMALLINT), new ColumnInfo("UNSIGNED_ATTRIBUTE", VoltType.TINYINT), //should be bool new ColumnInfo("FIXED_PREC_SCALE", VoltType.TINYINT), //should be bool new ColumnInfo("AUTO_INCREMENT", VoltType.TINYINT), //should be bool new ColumnInfo("LOCAL_TYPE_NAME", VoltType.STRING), new ColumnInfo("MINIMUM_SCALE", VoltType.SMALLINT), new ColumnInfo("MAXIMUM_SCALE", VoltType.SMALLINT), new ColumnInfo("SQL_DATA_TYPE", VoltType.INTEGER), new ColumnInfo("SQL_DATETIME_SUB", VoltType.INTEGER), new ColumnInfo("NUM_PREC_RADIX", VoltType.INTEGER) }; static public final ColumnInfo[] CLASS_SCHEMA = new ColumnInfo[] { new ColumnInfo("CLASS_NAME", VoltType.STRING), new ColumnInfo("VOLT_PROCEDURE", VoltType.TINYINT), new ColumnInfo("ACTIVE_PROC", VoltType.TINYINT) }; static public final ColumnInfo[] CONFIG_SCHEMA = new ColumnInfo[] { new ColumnInfo("CONFIG_NAME", VoltType.STRING), new ColumnInfo("CONFIG_VALUE", VoltType.STRING), new ColumnInfo("CONFIG_DESCRIPTION", VoltType.STRING) }; JdbcDatabaseMetaDataGenerator(Catalog catalog, DefaultProcedureManager defaultProcs, InMemoryJarfile jarfile) { m_catalog = catalog; m_defaultProcs = defaultProcs; m_database = m_catalog.getClusters().get("cluster").getDatabases().get("database"); m_jarfile = jarfile; } public VoltTable getMetaData(String selector) { VoltTable result = null; if (selector.equalsIgnoreCase("TABLES")) { result = getTables(); } else if (selector.equalsIgnoreCase("COLUMNS")) { result = getColumns(); } else if (selector.equalsIgnoreCase("INDEXINFO")) { result = getIndexInfo(); } else if (selector.equalsIgnoreCase("PRIMARYKEYS")) { result = getPrimaryKeys(); } else if (selector.equalsIgnoreCase("PROCEDURES")) { result = getProcedures(); } else if (selector.equalsIgnoreCase("FUNCTIONS")) { result = getFunctions(); } else if (selector.equalsIgnoreCase("PROCEDURECOLUMNS")) { result = getProcedureColumns(); } else if (selector.equalsIgnoreCase("TYPEINFO")) { result = getTypeInfo(); } // This selector is not part of the JDBC standard, but we pile on here // because it's a convenient way to get information about the application else if (selector.equalsIgnoreCase("CLASSES")) { result = getClasses(); } return result; } private String getTableType(Table table) { String type = "TABLE"; if (table.getMaterializer() != null) { type = "VIEW"; } else if (m_database.getConnectors() != null) { for (Connector conn : m_database.getConnectors()) { if (conn.getTableinfo() != null && conn.getTableinfo().getIgnoreCase(table.getTypeName()) != null) { type = "EXPORT"; break; } } } return type; } VoltTable getTables() { VoltTable results = new VoltTable(TABLE_SCHEMA); for (Table table : m_database.getTables()) { String type = getTableType(table); Column partColumn; if (type.equals("VIEW")) { partColumn = table.getMaterializer().getPartitioncolumn(); } else { partColumn = table.getPartitioncolumn(); } String remark = null; try { JSONObject jsObj = new JSONObject(); if (partColumn != null) { jsObj.put(JSON_PARTITION_COLUMN, partColumn.getName()); if (type.equals("VIEW")) { jsObj.put(JSON_SOURCE_TABLE, table.getMaterializer().getTypeName()); } } String deleteStmt = CatalogUtil.getLimitPartitionRowsDeleteStmt(table); if (deleteStmt != null) { jsObj.put(JSON_LIMIT_PARTITION_ROWS_DELETE_STMT, deleteStmt); } if (table.getIsdred()) { jsObj.put(JSON_DRED_TABLE, "true"); } remark = jsObj.length() > 0 ? jsObj.toString() : null; } catch (JSONException e) { hostLog.warn("You have encountered an unexpected error while generating results for the " + "@SystemCatalog procedure call. This error will not affect your database's " + "operation. Please contact VoltDB support with your log files and a " + "description of what you were doing when this error occured.", e); remark = "{\"" + JSON_ERROR + "\":\"" + e.getMessage() + "\"}"; } results.addRow(null, null, // no schema name table.getTypeName(), type, remark, // REMARKS null, // unused TYPE_CAT null, // unused TYPE_SCHEM null, // unused TYPE_NAME null, // unused SELF_REFERENCING_COL_NAME null // unused REF_GENERATION ); } return results; } // Might consider consolidating this into VoltType if we go big on JDBC stuff. // Considered and done private int getColumnSqlDataType(VoltType type) { return type.getJdbcSqlType(); } private String getColumnSqlTypeName(VoltType type) { String jdbc_sql_typename = type.toSQLString(); if (jdbc_sql_typename == null) { jdbc_sql_typename = "OTHER"; } return jdbc_sql_typename.toUpperCase(); } // Integer[0] is the column size and Integer[1] is the radix private Integer[] getColumnSizeAndRadix(Column column) { Integer[] col_size_radix = {null, null}; // This looks similar to VoltType.getTypePrecisionAndRadix. However, // the String/VARBINARY values depend on the schema, not an intrinsic property // of the type, so it stays here for now. VoltType type = VoltType.get((byte) column.getType()); switch(type) { // case TINYINT: case SMALLINT: case INTEGER: case BIGINT: case TIMESTAMP: col_size_radix[0] = (column.getSize() * 8) - 1; col_size_radix[1] = 2; break; case FLOAT: col_size_radix[0] = 53; // magic for double col_size_radix[1] = 2; break; case STRING: col_size_radix[0] = column.getSize(); col_size_radix[1] = null; break; case DECIMAL: col_size_radix[0] = VoltDecimalHelper.kDefaultPrecision; col_size_radix[1] = 10; break; case VARBINARY: col_size_radix[0] = column.getSize(); col_size_radix[1] = null; break; default: // XXX What's the right behavior here? } return col_size_radix; } private Integer getColumnDecimalDigits(VoltType type) { // Would be nice to push this into VoltType someday Integer num_dec_digits = null; switch(type) { // case TINYINT: case SMALLINT: case INTEGER: case BIGINT: case TIMESTAMP: case FLOAT: case STRING: case VARBINARY: num_dec_digits = null; break; case DECIMAL: num_dec_digits = VoltDecimalHelper.kDefaultScale; break; default: // XXX What's the right behavior here? } return num_dec_digits; } private int getColumnNullable(Column column) { int nullable = java.sql.DatabaseMetaData.columnNoNulls; if (column.getNullable()) { nullable = java.sql.DatabaseMetaData.columnNullable; } return nullable; } private String getColumnRemarks(Column column, Table table) { String remarks = null; if (table.getPartitioncolumn() != null && table.getPartitioncolumn().getTypeName().equals(column.getTypeName())) { remarks = "PARTITION_COLUMN"; } return remarks; } private String getDefaultValue(Column column) { String value = column.getDefaultvalue(); if (value != null && VoltType.get((byte)column.getDefaulttype()) == VoltType.STRING) { value = "'" + value + "'"; } return value; } private Integer getCharOctetLength(Column column) { Integer length = null; VoltType type = VoltType.get((byte)column.getType()); if (type == VoltType.STRING || type == VoltType.VARBINARY) { length = column.getSize(); } return length; } private String getColumnIsNullable(Column column) { String is_nullable = "NO"; if (column.getNullable()) { is_nullable = "YES"; } return is_nullable; } VoltTable getColumns() { VoltTable results = new VoltTable(COLUMN_SCHEMA); for (Table table : m_database.getTables()) { for (Column column: table.getColumns()) { results.addRow( null, null, // no schema name table.getTypeName(), column.getTypeName(), getColumnSqlDataType(VoltType.get((byte) column.getType())), getColumnSqlTypeName(VoltType.get((byte) column.getType())), getColumnSizeAndRadix(column)[0], null, getColumnDecimalDigits(VoltType.get((byte) column.getType())), getColumnSizeAndRadix(column)[1], getColumnNullable(column), getColumnRemarks(column, table), // REMARKS getDefaultValue(column), // default value null, // unused SQL_DATA_TYPE null, // unused SQL_DATETIME_SUB getCharOctetLength(column), // char_octet_length column.getIndex() + 1, // ordinal position, starts from 1 getColumnIsNullable(column), // IS_NULLABLE null, // unused SCOPE_CATALOG null, // unused SCOPE_SCHEMA null, // unused SCOPE_TABLE null, // unused SOURCE_DATA_TYPE "NO" // no auto-increment yet ); } } return results; } private short getIndexType(Index index) { short type = java.sql.DatabaseMetaData.tableIndexOther; if (index.getType() == IndexType.HASH_TABLE.getValue()) { type = java.sql.DatabaseMetaData.tableIndexHashed; } return type; } private String getSortOrder(Index index) { String sort_order = null; if (index.getType() == IndexType.BALANCED_TREE.getValue()) { sort_order = "A"; } return sort_order; } VoltTable getIndexInfo() { VoltTable results = new VoltTable(INDEXINFO_SCHEMA); for (Table table : m_database.getTables()) { for (Index index : table.getIndexes()) { for (ColumnRef column : index.getColumns()) { results.addRow(null, null, // table_schema table.getTypeName(), // table name index.getUnique() ? 0 : 1, // non-unique, 0 is unique, 1 is not null, // index qualifier (always null for us) index.getTypeName(), // index name getIndexType(index), // type column.getRelativeIndex(), // ordinal position column.getTypeName(), // column name getSortOrder(index), // ascending or descending null, // cardinality null, // pages (always null for us) null // filter condition, also null for us ); } } } return results; } VoltTable getPrimaryKeys() { VoltTable results = new VoltTable(PRIMARYKEYS_SCHEMA); for (Table table : m_database.getTables()) { for (Constraint c : table.getConstraints()) { if (c.getType() == ConstraintType.PRIMARY_KEY.getValue()) { for (ColumnRef column : c.getIndex().getColumns()) { results.addRow(null, null, // table schema table.getTypeName(), // table name column.getTypeName(), // column name column.getRelativeIndex(), // key_seq c.getTypeName() // PK_NAME ); } } } } return results; } VoltTable getFunctions() { VoltTable results = new VoltTable(FUNCTIONS_SCHEMA); for (Function func : m_database.getFunctions()) { results.addRow( "scalar", // Function Type func.getFunctionname(), // Function Name func.getClassname(), // Class Name func.getMethodname()); // Method Name } return results; } VoltTable getProcedures() { VoltTable results = new VoltTable(PROCEDURES_SCHEMA); // merge catalog and default procedures SortedSet<Procedure> procedures = new TreeSet<>(); for (Procedure proc : m_database.getProcedures()) { procedures.add(proc); } if (m_defaultProcs != null) { for (Procedure proc : m_defaultProcs.m_defaultProcMap.values()) { procedures.add(proc); } } for (Procedure proc : procedures) { String remark = null; try { JSONObject jsObj = new JSONObject(); jsObj.put(JSON_READ_ONLY, proc.getReadonly()); jsObj.put(JSON_SINGLE_PARTITION, proc.getSinglepartition()); if (proc.getSinglepartition()) { jsObj.put(JSON_PARTITION_PARAMETER, proc.getPartitionparameter()); jsObj.put(JSON_PARTITION_PARAMETER_TYPE, proc.getPartitioncolumn().getType()); } remark = jsObj.toString(); } catch (JSONException e) { hostLog.warn("You have encountered an unexpected error while generating results for the " + "@SystemCatalog procedure call. This error will not affect your database's " + "operation. Please contact VoltDB support with your log files and a " + "description of what you were doing when this error occured.", e); remark = "{\"" + JSON_ERROR + "\",\"" + e.getMessage() + "\"}"; } results.addRow( null, null, // procedure schema proc.getTypeName(), // procedure name null, // reserved null, // reserved null, // reserved remark, // REMARKS java.sql.DatabaseMetaData.procedureResultUnknown, // procedure time proc.getTypeName() // specific name ); } return results; } private String getProcedureColumnRemarks(ProcParameter param, Procedure proc) { String remarks = null; if (proc.getPartitioncolumn() != null) { if (proc.getPartitionparameter() == param.getIndex()) { remarks = "PARTITION_PARAMETER"; } } if (param.getIsarray()) { if (remarks != null) { remarks = remarks + ","; } else { remarks = ""; } remarks = remarks + "ARRAY_PARAMETER"; } return remarks; } // Integer[0] is the column size and Integer[1] is the radix private Integer[] getParamPrecisionAndRadix(ProcParameter param) { VoltType type = VoltType.get((byte) param.getType()); return type.getTypePrecisionAndRadix(); } private int getParamLength(ProcParameter param) { VoltType type = VoltType.get((byte) param.getType()); return type.getMaxLengthInBytes(); } private Integer getParamCharOctetLength(ProcParameter param) { Integer length = null; // Would be nice to push this type-dependent stuff to VoltType someday. VoltType type = VoltType.get((byte) param.getType()); switch(type) { case TINYINT: case SMALLINT: case INTEGER: case BIGINT: case TIMESTAMP: case FLOAT: case DECIMAL: length = null; break; case STRING: case VARBINARY: length = VoltType.MAX_VALUE_LENGTH; break; default: // XXX What's the right behavior here? } return length; } VoltTable getProcedureColumns() { VoltTable results = new VoltTable(PROCEDURECOLUMNS_SCHEMA); // merge catalog and default procedures SortedSet<Procedure> procedures = new TreeSet<>(); for (Procedure proc : m_database.getProcedures()) { procedures.add(proc); } if (m_defaultProcs != null) { for (Procedure proc : m_defaultProcs.m_defaultProcMap.values()) { procedures.add(proc); } } for (Procedure proc : procedures) { for (ProcParameter param : proc.getParameters()) { Integer paramPrecisionAndRadix[] = getParamPrecisionAndRadix(param); results.addRow( null, // procedure catalog null, // procedure schema proc.getTypeName(), // procedure name param.getTypeName(), // param name java.sql.DatabaseMetaData.procedureColumnIn, // param type, all are IN getColumnSqlDataType(VoltType.get((byte)param.getType())), // data type getColumnSqlTypeName(VoltType.get((byte)param.getType())), // type name paramPrecisionAndRadix[0], // precision getParamLength(param), // length getColumnDecimalDigits(VoltType.get((byte)param.getType())), paramPrecisionAndRadix[1], // radix java.sql.DatabaseMetaData.procedureNullableUnknown, // nullable getProcedureColumnRemarks(param, proc), // remarks null, // column default. always null for us null, // reserved null, // reserved getParamCharOctetLength(param), // char octet length param.getIndex() + 1, // ordinal position "", // is_nullable proc.getTypeName() // specific name ); } } return results; } VoltTable getTypeInfo() { VoltTable results = new VoltTable(TYPEINFO_SCHEMA); for (VoltType type : VoltType.values()) { if (!type.isJdbcVisible()) { continue; } Byte unsigned = null; if (type.isUnsigned() != null) { unsigned = (byte)(type.isUnsigned() ? 1 : 0); } Integer typePrecisionAndRadix[] = type.getTypePrecisionAndRadix(); results.addRow(type.toSQLString().toUpperCase(), type.getJdbcSqlType(), typePrecisionAndRadix[0], type.getLiteralPrefix(), type.getLiteralSuffix(), type.getCreateParams(), type.getNullable(), type.isCaseSensitive() ? 1 : 0, type.getSearchable(), unsigned, 0, // no money types (according to definition) in Volt? 0, // no auto-increment type.toSQLString().toUpperCase(), type.getMinimumScale(), type.getMaximumScale(), null, null, typePrecisionAndRadix[1] ); } return results; } VoltTable getClasses() { VoltTable results = new VoltTable(CLASS_SCHEMA); for (String classname : m_jarfile.getLoader().getClassNames()) { try { Class<?> clazz = m_jarfile.getLoader().loadClass(classname); boolean isProc = VoltProcedure.class.isAssignableFrom(clazz); boolean isActive = false; if (isProc) { for (Procedure proc : m_database.getProcedures()) { if (proc.getClassname().equals(clazz.getCanonicalName())) { isActive = true; break; } } } results.addRow(classname, isProc ? 1 : 0, isActive ? 1 : 0); } catch (Exception e) { // if we can't load a class from the jarfile, just pretend it doesn't // exist. Other checks when we actually load the classes should // ensure that we don't end up in this state. } } return results; } private final Catalog m_catalog; private final DefaultProcedureManager m_defaultProcs; private final Database m_database; private final InMemoryJarfile m_jarfile; }