private static RowKeySchema buildSchema(int[] widths) { RowKeySchemaBuilder builder = new RowKeySchemaBuilder(10); for (final int width : widths) { builder.addField( new PDatum() { @Override public boolean isNullable() { return false; } @Override public PDataType getDataType() { return PChar.INSTANCE; } @Override public Integer getMaxLength() { return width; } @Override public Integer getScale() { return null; } @Override public SortOrder getSortOrder() { return SortOrder.getDefault(); } }, false, SortOrder.getDefault()); } return builder.build(); }
private LiteralExpression( Object value, PDataType type, byte[] byteValue, Determinism determinism) { this( value, type, byteValue, type == null || !type.isFixedWidth() ? null : type.getMaxLength(value), null, SortOrder.getDefault(), determinism); }
private static MutationState upsertSelect( PhoenixStatement statement, TableRef tableRef, RowProjector projector, ResultIterator iterator, int[] columnIndexes, int[] pkSlotIndexes) throws SQLException { try { PhoenixConnection connection = statement.getConnection(); ConnectionQueryServices services = connection.getQueryServices(); int maxSize = services .getProps() .getInt( QueryServices.MAX_MUTATION_SIZE_ATTRIB, QueryServicesOptions.DEFAULT_MAX_MUTATION_SIZE); int batchSize = Math.min(connection.getMutateBatchSize(), maxSize); boolean isAutoCommit = connection.getAutoCommit(); byte[][] values = new byte[columnIndexes.length][]; int rowCount = 0; Map<ImmutableBytesPtr, Map<PColumn, byte[]>> mutation = Maps.newHashMapWithExpectedSize(batchSize); PTable table = tableRef.getTable(); ResultSet rs = new PhoenixResultSet(iterator, projector, statement); ImmutableBytesWritable ptr = new ImmutableBytesWritable(); while (rs.next()) { for (int i = 0; i < values.length; i++) { PColumn column = table.getColumns().get(columnIndexes[i]); byte[] bytes = rs.getBytes(i + 1); ptr.set(bytes == null ? ByteUtil.EMPTY_BYTE_ARRAY : bytes); Object value = rs.getObject(i + 1); int rsPrecision = rs.getMetaData().getPrecision(i + 1); Integer precision = rsPrecision == 0 ? null : rsPrecision; int rsScale = rs.getMetaData().getScale(i + 1); Integer scale = rsScale == 0 ? null : rsScale; // We are guaranteed that the two column will have compatible types, // as we checked that before. if (!column .getDataType() .isSizeCompatible( ptr, value, column.getDataType(), precision, scale, column.getMaxLength(), column.getScale())) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.DATA_EXCEEDS_MAX_CAPACITY) .setColumnName(column.getName().getString()) .setMessage("value=" + column.getDataType().toStringLiteral(ptr, null)) .build() .buildException(); } column .getDataType() .coerceBytes( ptr, value, column.getDataType(), precision, scale, SortOrder.getDefault(), column.getMaxLength(), column.getScale(), column.getSortOrder()); values[i] = ByteUtil.copyKeyBytesIfNecessary(ptr); } setValues(values, pkSlotIndexes, columnIndexes, table, mutation); rowCount++; // Commit a batch if auto commit is true and we're at our batch size if (isAutoCommit && rowCount % batchSize == 0) { MutationState state = new MutationState(tableRef, mutation, 0, maxSize, connection); connection.getMutationState().join(state); connection.commit(); mutation.clear(); } } // If auto commit is true, this last batch will be committed upon return return new MutationState( tableRef, mutation, rowCount / batchSize * batchSize, maxSize, connection); } finally { iterator.close(); } }
/** * Static class for various schema-related utilities * * @since 0.1 */ public class SchemaUtil { private static final int VAR_LENGTH_ESTIMATE = 10; private static final int VAR_KV_LENGTH_ESTIMATE = 50; public static final String ESCAPE_CHARACTER = "\""; public static final DataBlockEncoding DEFAULT_DATA_BLOCK_ENCODING = DataBlockEncoding.FAST_DIFF; public static final PDatum VAR_BINARY_DATUM = new PDatum() { @Override public boolean isNullable() { return false; } @Override public PDataType getDataType() { return PVarbinary.INSTANCE; } @Override public Integer getMaxLength() { return null; } @Override public Integer getScale() { return null; } @Override public SortOrder getSortOrder() { return SortOrder.getDefault(); } }; public static final RowKeySchema VAR_BINARY_SCHEMA = new RowKeySchemaBuilder(1).addField(VAR_BINARY_DATUM, false, SortOrder.getDefault()).build(); /** May not be instantiated */ private SchemaUtil() {} public static boolean isPKColumn(PColumn column) { return column.getFamilyName() == null; } /** * Imperfect estimate of row size given a PTable TODO: keep row count in stats table and use total * size / row count instead * * @param table * @return estimate of size in bytes of a row */ public static long estimateRowSize(PTable table) { int keyLength = estimateKeyLength(table); long rowSize = 0; for (PColumn column : table.getColumns()) { if (!SchemaUtil.isPKColumn(column)) { PDataType type = column.getDataType(); Integer maxLength = column.getMaxLength(); int valueLength = !type.isFixedWidth() ? VAR_KV_LENGTH_ESTIMATE : maxLength == null ? type.getByteSize() : maxLength; rowSize += KeyValue.getKeyValueDataStructureSize( keyLength, column.getFamilyName().getBytes().length, column.getName().getBytes().length, valueLength); } } // Empty key value rowSize += KeyValue.getKeyValueDataStructureSize( keyLength, getEmptyColumnFamily(table).length, QueryConstants.EMPTY_COLUMN_BYTES.length, 0); return rowSize; } /** * Estimate the max key length in bytes of the PK for a given table * * @param table the table * @return the max PK length */ public static int estimateKeyLength(PTable table) { int maxKeyLength = 0; // Calculate the max length of a key (each part must currently be of a fixed width) int i = 0; List<PColumn> columns = table.getPKColumns(); while (i < columns.size()) { PColumn keyColumn = columns.get(i++); PDataType type = keyColumn.getDataType(); Integer maxLength = keyColumn.getMaxLength(); maxKeyLength += !type.isFixedWidth() ? VAR_LENGTH_ESTIMATE : maxLength == null ? type.getByteSize() : maxLength; } return maxKeyLength; } /** * Normalize an identifier. If name is surrounded by double quotes, it is used as-is, otherwise * the name is upper caased. * * @param name the parsed identifier * @return the normalized identifier */ public static String normalizeIdentifier(String name) { if (name == null) { return name; } if (isCaseSensitive(name)) { // Don't upper case if in quotes return name.substring(1, name.length() - 1); } return name.toUpperCase(); } /** * Normalizes the fulltableName . Uses {@linkplain normalizeIdentifier} * * @param fullTableName * @return */ public static String normalizeFullTableName(String fullTableName) { String schemaName = SchemaUtil.getSchemaNameFromFullName(fullTableName); String tableName = SchemaUtil.getTableNameFromFullName(fullTableName); String normalizedTableName = StringUtil.EMPTY_STRING; if (!schemaName.isEmpty()) { normalizedTableName = normalizeIdentifier(schemaName) + QueryConstants.NAME_SEPARATOR; } return normalizedTableName + normalizeIdentifier(tableName); } public static boolean isCaseSensitive(String name) { return name != null && name.length() > 0 && name.charAt(0) == '"'; } public static <T> List<T> concat(List<T> l1, List<T> l2) { int size1 = l1.size(); if (size1 == 0) { return l2; } int size2 = l2.size(); if (size2 == 0) { return l1; } List<T> l3 = new ArrayList<T>(size1 + size2); l3.addAll(l1); l3.addAll(l2); return l3; } /** * Get the key used in the Phoenix metadata row for a table definition * * @param schemaName * @param tableName */ public static byte[] getTableKey(byte[] tenantId, byte[] schemaName, byte[] tableName) { return ByteUtil.concat( tenantId, QueryConstants.SEPARATOR_BYTE_ARRAY, schemaName, QueryConstants.SEPARATOR_BYTE_ARRAY, tableName); } /** * Get the key used in the Phoenix function data row for a function definition * * @param tenantId * @param functionName */ public static byte[] getFunctionKey(byte[] tenantId, byte[] functionName) { return ByteUtil.concat(tenantId, QueryConstants.SEPARATOR_BYTE_ARRAY, functionName); } public static byte[] getTableKey(String tenantId, String schemaName, String tableName) { return ByteUtil.concat( tenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(tenantId), QueryConstants.SEPARATOR_BYTE_ARRAY, schemaName == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(schemaName), QueryConstants.SEPARATOR_BYTE_ARRAY, Bytes.toBytes(tableName)); } public static String getTableName(String schemaName, String tableName) { return getName(schemaName, tableName, false); } private static String getName(String optionalQualifier, String name, boolean caseSensitive) { String cq = caseSensitive ? "\"" + name + "\"" : name; if (optionalQualifier == null || optionalQualifier.isEmpty()) { return cq; } String cf = caseSensitive ? "\"" + optionalQualifier + "\"" : optionalQualifier; return cf + QueryConstants.NAME_SEPARATOR + cq; } public static String getTableName(byte[] schemaName, byte[] tableName) { return getName(schemaName, tableName); } public static String getColumnDisplayName(byte[] cf, byte[] cq) { return getName(cf == null || cf.length == 0 ? ByteUtil.EMPTY_BYTE_ARRAY : cf, cq); } public static String getColumnDisplayName(String cf, String cq) { return getName(cf == null || cf.isEmpty() ? null : cf, cq, false); } public static String getCaseSensitiveColumnDisplayName(String cf, String cq) { return getName(cf == null || cf.isEmpty() ? null : cf, cq, true); } public static String getMetaDataEntityName( String schemaName, String tableName, String familyName, String columnName) { if ((schemaName == null || schemaName.isEmpty()) && (tableName == null || tableName.isEmpty())) { if (columnName == null || columnName.isEmpty()) { return familyName; } return getName(familyName, columnName, false); } if ((familyName == null || familyName.isEmpty()) && (columnName == null || columnName.isEmpty())) { return getName(schemaName, tableName, false); } return getName( getName(schemaName, tableName, false), getName(familyName, columnName, false), false); } public static String getColumnName(String familyName, String columnName) { return getName(familyName, columnName, false); } public static byte[] getTableNameAsBytes(String schemaName, String tableName) { if (schemaName == null || schemaName.length() == 0) { return StringUtil.toBytes(tableName); } return getTableNameAsBytes(StringUtil.toBytes(schemaName), StringUtil.toBytes(tableName)); } public static byte[] getTableNameAsBytes(byte[] schemaName, byte[] tableName) { return getNameAsBytes(schemaName, tableName); } private static byte[] getNameAsBytes(byte[] nameOne, byte[] nameTwo) { if (nameOne == null || nameOne.length == 0) { return nameTwo; } else if ((nameTwo == null || nameTwo.length == 0)) { return nameOne; } else { return ByteUtil.concat(nameOne, QueryConstants.NAME_SEPARATOR_BYTES, nameTwo); } } public static String getName(byte[] nameOne, byte[] nameTwo) { return Bytes.toString(getNameAsBytes(nameOne, nameTwo)); } public static int getVarCharLength(byte[] buf, int keyOffset, int maxLength) { return getVarCharLength(buf, keyOffset, maxLength, 1); } public static int getVarCharLength(byte[] buf, int keyOffset, int maxLength, int skipCount) { int length = 0; for (int i = 0; i < skipCount; i++) { while (length < maxLength && buf[keyOffset + length] != QueryConstants.SEPARATOR_BYTE) { length++; } if (i != skipCount - 1) { // skip over the separator if it's not the last one. length++; } } return length; } public static int getVarChars(byte[] rowKey, byte[][] rowKeyMetadata) { return getVarChars(rowKey, 0, rowKey.length, 0, rowKeyMetadata); } public static int getVarChars(byte[] rowKey, int colMetaDataLength, byte[][] colMetaData) { return getVarChars(rowKey, 0, rowKey.length, 0, colMetaDataLength, colMetaData); } public static int getVarChars( byte[] rowKey, int keyOffset, int keyLength, int colMetaDataOffset, byte[][] colMetaData) { return getVarChars( rowKey, keyOffset, keyLength, colMetaDataOffset, colMetaData.length, colMetaData); } public static int getVarChars( byte[] rowKey, int keyOffset, int keyLength, int colMetaDataOffset, int colMetaDataLength, byte[][] colMetaData) { int i, offset = keyOffset; for (i = colMetaDataOffset; i < colMetaDataLength && keyLength > 0; i++) { int length = getVarCharLength(rowKey, offset, keyLength); byte[] b = new byte[length]; System.arraycopy(rowKey, offset, b, 0, length); offset += length + 1; keyLength -= length + 1; colMetaData[i] = b; } return i; } public static String findExistingColumn(PTable table, List<PColumn> columns) { for (PColumn column : columns) { PName familyName = column.getFamilyName(); if (familyName == null) { try { return table.getPKColumn(column.getName().getString()).getName().getString(); } catch (ColumnNotFoundException e) { continue; } } else { try { return table .getColumnFamily(familyName.getString()) .getColumn(column.getName().getString()) .getName() .getString(); } catch (ColumnFamilyNotFoundException e) { continue; // Shouldn't happen } catch (ColumnNotFoundException e) { continue; } } } return null; } public static String toString(byte[][] values) { if (values == null) { return "null"; } StringBuilder buf = new StringBuilder("["); for (byte[] value : values) { buf.append(Bytes.toStringBinary(value)); buf.append(','); } buf.setCharAt(buf.length() - 1, ']'); return buf.toString(); } public static String toString(PDataType type, byte[] value) { boolean isString = type.isCoercibleTo(PVarchar.INSTANCE); return isString ? ("'" + type.toObject(value).toString() + "'") : type.toObject(value).toString(); } public static byte[] getEmptyColumnFamily( PName defaultColumnFamily, List<PColumnFamily> families) { return families.isEmpty() ? defaultColumnFamily == null ? QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES : defaultColumnFamily.getBytes() : families.get(0).getName().getBytes(); } public static byte[] getEmptyColumnFamily(PTable table) { List<PColumnFamily> families = table.getColumnFamilies(); return families.isEmpty() ? table.getDefaultFamilyName() == null ? QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES : table.getDefaultFamilyName().getBytes() : families.get(0).getName().getBytes(); } public static String getEmptyColumnFamilyAsString(PTable table) { List<PColumnFamily> families = table.getColumnFamilies(); return families.isEmpty() ? table.getDefaultFamilyName() == null ? QueryConstants.DEFAULT_COLUMN_FAMILY : table.getDefaultFamilyName().getString() : families.get(0).getName().getString(); } public static ImmutableBytesPtr getEmptyColumnFamilyPtr(PTable table) { List<PColumnFamily> families = table.getColumnFamilies(); return families.isEmpty() ? table.getDefaultFamilyName() == null ? QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES_PTR : table.getDefaultFamilyName().getBytesPtr() : families.get(0).getName().getBytesPtr(); } public static boolean isMetaTable(byte[] tableName) { return Bytes.compareTo(tableName, SYSTEM_CATALOG_NAME_BYTES) == 0; } public static boolean isFunctionTable(byte[] tableName) { return Bytes.compareTo(tableName, SYSTEM_FUNCTION_NAME_BYTES) == 0; } public static boolean isStatsTable(byte[] tableName) { return Bytes.compareTo(tableName, SYSTEM_STATS_NAME_BYTES) == 0; } public static boolean isSequenceTable(byte[] tableName) { return Bytes.compareTo(tableName, PhoenixDatabaseMetaData.SYSTEM_SEQUENCE_NAME_BYTES) == 0; } public static boolean isSequenceTable(PTable table) { return PhoenixDatabaseMetaData.SYSTEM_SEQUENCE_NAME.equals(table.getName().getString()); } public static boolean isMetaTable(PTable table) { return PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA.equals(table.getSchemaName().getString()) && PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE.equals(table.getTableName().getString()); } public static boolean isMetaTable(byte[] schemaName, byte[] tableName) { return Bytes.compareTo(schemaName, PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA_BYTES) == 0 && Bytes.compareTo(tableName, PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE_BYTES) == 0; } public static boolean isMetaTable(String schemaName, String tableName) { return PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA.equals(schemaName) && PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE.equals(tableName); } public static boolean isSystemTable(byte[] fullTableName) { String schemaName = SchemaUtil.getSchemaNameFromFullName(fullTableName); if (QueryConstants.SYSTEM_SCHEMA_NAME.equals(schemaName)) return true; return false; } // Given the splits and the rowKeySchema, find out the keys that public static byte[][] processSplits( byte[][] splits, LinkedHashSet<PColumn> pkColumns, Integer saltBucketNum, boolean defaultRowKeyOrder) throws SQLException { // FIXME: shouldn't this return if splits.length == 0? if (splits == null) return null; // We do not accept user specified splits if the table is salted and we specify // defaultRowKeyOrder. In this case, // throw an exception. if (splits.length > 0 && saltBucketNum != null && defaultRowKeyOrder) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.NO_SPLITS_ON_SALTED_TABLE) .build() .buildException(); } // If the splits are not specified and table is salted, pre-split the table. if (splits.length == 0 && saltBucketNum != null) { splits = SaltingUtil.getSalteByteSplitPoints(saltBucketNum); } byte[][] newSplits = new byte[splits.length][]; for (int i = 0; i < splits.length; i++) { newSplits[i] = processSplit(splits[i], pkColumns); } return newSplits; } // Go through each slot in the schema and try match it with the split byte array. If the split // does not confer to the schema, extends its length to match the schema. private static byte[] processSplit(byte[] split, LinkedHashSet<PColumn> pkColumns) { int pos = 0, offset = 0, maxOffset = split.length; Iterator<PColumn> iterator = pkColumns.iterator(); while (pos < pkColumns.size()) { PColumn column = iterator.next(); if (column.getDataType().isFixedWidth()) { // Fixed width int length = SchemaUtil.getFixedByteSize(column); if (maxOffset - offset < length) { // The split truncates the field. Fill in the rest of the part and any fields that // are missing after this field. int fillInLength = length - (maxOffset - offset); fillInLength += estimatePartLength(pos + 1, iterator); return ByteUtil.fillKey(split, split.length + fillInLength); } // Account for this field, move to next position; offset += length; pos++; } else { // Variable length // If we are the last slot, then we are done. Nothing needs to be filled in. if (pos == pkColumns.size() - 1) { break; } while (offset < maxOffset && split[offset] != QueryConstants.SEPARATOR_BYTE) { offset++; } if (offset == maxOffset) { // The var-length field does not end with a separator and it's not the last field. int fillInLength = 1; // SEPARATOR byte for the current var-length slot. fillInLength += estimatePartLength(pos + 1, iterator); return ByteUtil.fillKey(split, split.length + fillInLength); } // Move to the next position; offset += 1; // skip separator; pos++; } } return split; } // Estimate the key length after pos slot for schema. private static int estimatePartLength(int pos, Iterator<PColumn> iterator) { int length = 0; while (iterator.hasNext()) { PColumn column = iterator.next(); if (column.getDataType().isFixedWidth()) { length += SchemaUtil.getFixedByteSize(column); } else { length += 1; // SEPARATOR byte. } } return length; } public static String getEscapedTableName(String schemaName, String tableName) { if (schemaName == null || schemaName.length() == 0) { return "\"" + tableName + "\""; } return "\"" + schemaName + "\"." + "\"" + tableName + "\""; } protected static PhoenixConnection addMetaDataColumn( PhoenixConnection conn, long scn, String columnDef) throws SQLException { PhoenixConnection metaConnection = null; Statement stmt = null; try { metaConnection = new PhoenixConnection(conn.getQueryServices(), conn, scn); try { stmt = metaConnection.createStatement(); stmt.executeUpdate("ALTER TABLE SYSTEM.\"TABLE\" ADD IF NOT EXISTS " + columnDef); return metaConnection; } finally { if (stmt != null) { stmt.close(); } } } finally { if (metaConnection != null) { metaConnection.close(); } } } public static boolean columnExists(PTable table, String columnName) { try { table.getColumn(columnName); return true; } catch (ColumnNotFoundException e) { return false; } catch (AmbiguousColumnException e) { return true; } } public static String getSchemaNameFromFullName(String tableName) { int index = tableName.indexOf(QueryConstants.NAME_SEPARATOR); if (index < 0) { return StringUtil.EMPTY_STRING; } return tableName.substring(0, index); } private static int indexOf(byte[] bytes, byte b) { for (int i = 0; i < bytes.length; i++) { if (bytes[i] == b) { return i; } } return -1; } public static String getSchemaNameFromFullName(byte[] tableName) { if (tableName == null) { return null; } int index = indexOf(tableName, QueryConstants.NAME_SEPARATOR_BYTE); if (index < 0) { return StringUtil.EMPTY_STRING; } return Bytes.toString(tableName, 0, index); } public static String getTableNameFromFullName(byte[] tableName) { if (tableName == null) { return null; } int index = indexOf(tableName, QueryConstants.NAME_SEPARATOR_BYTE); if (index < 0) { return Bytes.toString(tableName); } return Bytes.toString(tableName, index + 1, tableName.length - index - 1); } public static String getTableNameFromFullName(String tableName) { int index = tableName.indexOf(QueryConstants.NAME_SEPARATOR); if (index < 0) { return tableName; } return tableName.substring(index + 1, tableName.length()); } public static byte[] getTableKeyFromFullName(String fullTableName) { int index = fullTableName.indexOf(QueryConstants.NAME_SEPARATOR); if (index < 0) { return getTableKey(null, null, fullTableName); } String schemaName = fullTableName.substring(0, index); String tableName = fullTableName.substring(index + 1); return getTableKey(null, schemaName, tableName); } private static int getTerminatorCount(RowKeySchema schema) { int nTerminators = 0; for (int i = 0; i < schema.getFieldCount(); i++) { Field field = schema.getField(i); // We won't have a terminator on the last PK column // unless it is variable length and exclusive, but // having the extra byte irregardless won't hurt anything if (!field.getDataType().isFixedWidth()) { nTerminators++; } } return nTerminators; } public static int getMaxKeyLength(RowKeySchema schema, List<List<KeyRange>> slots) { int maxKeyLength = getTerminatorCount(schema) * 2; for (List<KeyRange> slot : slots) { int maxSlotLength = 0; for (KeyRange range : slot) { int maxRangeLength = Math.max(range.getLowerRange().length, range.getUpperRange().length); if (maxSlotLength < maxRangeLength) { maxSlotLength = maxRangeLength; } } maxKeyLength += maxSlotLength; } return maxKeyLength; } public static int getFixedByteSize(PDatum e) { assert (e.getDataType().isFixedWidth()); Integer maxLength = e.getMaxLength(); return maxLength == null ? e.getDataType().getByteSize() : maxLength; } public static short getMaxKeySeq(PTable table) { int offset = 0; if (table.getBucketNum() != null) { offset++; } // TODO: for tenant-specific table on tenant-specific connection, // we should subtract one for tenant column and another one for // index ID return (short) (table.getPKColumns().size() - offset); } public static int getPKPosition(PTable table, PColumn column) { // TODO: when PColumn has getPKPosition, use that instead return table.getPKColumns().indexOf(column); } public static String getEscapedFullColumnName(String fullColumnName) { if (fullColumnName.startsWith(ESCAPE_CHARACTER)) { return fullColumnName; } int index = fullColumnName.indexOf(QueryConstants.NAME_SEPARATOR); if (index < 0) { return getEscapedArgument(fullColumnName); } String columnFamily = fullColumnName.substring(0, index); String columnName = fullColumnName.substring(index + 1); return getEscapedArgument(columnFamily) + QueryConstants.NAME_SEPARATOR + getEscapedArgument(columnName); } public static String getEscapedFullTableName(String fullTableName) { final String schemaName = getSchemaNameFromFullName(fullTableName); final String tableName = getTableNameFromFullName(fullTableName); return getEscapedTableName(schemaName, tableName); } /** * Escapes the given argument with {@value #ESCAPE_CHARACTER} * * @param argument any non null value. * @return */ public static String getEscapedArgument(String argument) { Preconditions.checkNotNull(argument, "Argument passed cannot be null"); return ESCAPE_CHARACTER + argument + ESCAPE_CHARACTER; } /** * @return a fully qualified column name in the format: "CFNAME"."COLNAME" or "COLNAME" depending * on whether or not there is a column family name present. */ public static String getQuotedFullColumnName(PColumn pCol) { checkNotNull(pCol); String columnName = pCol.getName().getString(); String columnFamilyName = pCol.getFamilyName() != null ? pCol.getFamilyName().getString() : null; return getQuotedFullColumnName(columnFamilyName, columnName); } /** * @return a fully qualified column name in the format: "CFNAME"."COLNAME" or "COLNAME" depending * on whether or not there is a column family name present. */ public static String getQuotedFullColumnName( @Nullable String columnFamilyName, String columnName) { checkArgument(!isNullOrEmpty(columnName), "Column name cannot be null or empty"); return columnFamilyName == null ? ("\"" + columnName + "\"") : ("\"" + columnFamilyName + "\"" + QueryConstants.NAME_SEPARATOR + "\"" + columnName + "\""); } public static boolean hasHTableDescriptorProps(Map<String, Object> tableProps) { int pTablePropCount = 0; for (String prop : tableProps.keySet()) { if (TableProperty.isPhoenixTableProperty(prop)) { pTablePropCount++; } } return tableProps.size() - pTablePropCount > 0; } /** * Replaces all occurrences of {@link #ESCAPE_CHARACTER} with an empty character. * * @param fullColumnName * @return */ public static String getUnEscapedFullColumnName(String fullColumnName) { checkArgument(!isNullOrEmpty(fullColumnName), "Column name cannot be null or empty"); fullColumnName = fullColumnName.replaceAll(ESCAPE_CHARACTER, ""); return fullColumnName.trim(); } /** * Return the separator byte to use based on: * * @param rowKeyOrderOptimizable whether or not the table may optimize descending row keys. If the * table has no descending row keys, this will be true. Also, if the table has been upgraded * (using a new -u option for psql.py), then it'll be true * @param isNullValue whether or not the value is null. We use a null byte still if the value is * null regardless of sort order since nulls will always sort first this way. * @param sortOrder whether the value sorts ascending or descending. * @return the byte to use as the separator */ public static byte getSeparatorByte( boolean rowKeyOrderOptimizable, boolean isNullValue, SortOrder sortOrder) { return !rowKeyOrderOptimizable || isNullValue || sortOrder == SortOrder.ASC ? QueryConstants.SEPARATOR_BYTE : QueryConstants.DESC_SEPARATOR_BYTE; } public static byte getSeparatorByte( boolean rowKeyOrderOptimizable, boolean isNullValue, Field f) { return getSeparatorByte(rowKeyOrderOptimizable, isNullValue, f.getSortOrder()); } public static byte getSeparatorByte( boolean rowKeyOrderOptimizable, boolean isNullValue, Expression e) { return getSeparatorByte(rowKeyOrderOptimizable, isNullValue, e.getSortOrder()); } /** * Get list of ColumnInfos that contain Column Name and its associated PDataType for an import. * The supplied list of columns can be null -- if it is non-null, it represents a user-supplied * list of columns to be imported. * * @param conn Phoenix connection from which metadata will be read * @param tableName Phoenix table name whose columns are to be checked. Can include a schema name * @param columns user-supplied list of import columns, can be null * @param strict if true, an exception will be thrown if unknown columns are supplied */ public static List<ColumnInfo> generateColumnInfo( Connection conn, String tableName, List<String> columns, boolean strict) throws SQLException { Map<String, Integer> columnNameToTypeMap = Maps.newLinkedHashMap(); Set<String> ambiguousColumnNames = new HashSet<String>(); Map<String, Integer> fullColumnNameToTypeMap = Maps.newLinkedHashMap(); DatabaseMetaData dbmd = conn.getMetaData(); int unfoundColumnCount = 0; // TODO: escape wildcard characters here because we don't want that // behavior here String escapedTableName = StringUtil.escapeLike(tableName); String[] schemaAndTable = escapedTableName.split("\\."); ResultSet rs = null; try { rs = dbmd.getColumns( null, (schemaAndTable.length == 1 ? "" : schemaAndTable[0]), (schemaAndTable.length == 1 ? escapedTableName : schemaAndTable[1]), null); while (rs.next()) { String colName = rs.getString(QueryUtil.COLUMN_NAME_POSITION); String colFam = rs.getString(QueryUtil.COLUMN_FAMILY_POSITION); // use family qualifier, if available, otherwise, use column name String fullColumn = (colFam == null ? colName : String.format("%s.%s", colFam, colName)); String sqlTypeName = rs.getString(QueryUtil.DATA_TYPE_NAME_POSITION); // allow for both bare and family qualified names. if (columnNameToTypeMap.keySet().contains(colName)) { ambiguousColumnNames.add(colName); } columnNameToTypeMap.put(colName, PDataType.fromSqlTypeName(sqlTypeName).getSqlType()); fullColumnNameToTypeMap.put( fullColumn, PDataType.fromSqlTypeName(sqlTypeName).getSqlType()); } if (columnNameToTypeMap.isEmpty()) { throw new IllegalArgumentException("Table " + tableName + " not found"); } } finally { if (rs != null) { rs.close(); } } List<ColumnInfo> columnInfoList = Lists.newArrayList(); Set<String> unresolvedColumnNames = new TreeSet<String>(); if (columns == null) { // use family qualified names by default, if no columns are specified. for (Map.Entry<String, Integer> entry : fullColumnNameToTypeMap.entrySet()) { columnInfoList.add(new ColumnInfo(entry.getKey(), entry.getValue())); } } else { // Leave "null" as indication to skip b/c it doesn't exist for (int i = 0; i < columns.size(); i++) { String columnName = columns.get(i).trim(); Integer sqlType = null; if (fullColumnNameToTypeMap.containsKey(columnName)) { sqlType = fullColumnNameToTypeMap.get(columnName); } else if (columnNameToTypeMap.containsKey(columnName)) { if (ambiguousColumnNames.contains(columnName)) { unresolvedColumnNames.add(columnName); } // fall back to bare column name. sqlType = columnNameToTypeMap.get(columnName); } if (unresolvedColumnNames.size() > 0) { StringBuilder exceptionMessage = new StringBuilder(); boolean first = true; exceptionMessage.append( "Unable to resolve these column names to a single column family:\n"); for (String col : unresolvedColumnNames) { if (first) first = false; else exceptionMessage.append(","); exceptionMessage.append(col); } exceptionMessage.append("\nAvailable columns with column families:\n"); first = true; for (String col : fullColumnNameToTypeMap.keySet()) { if (first) first = false; else exceptionMessage.append(","); exceptionMessage.append(col); } throw new SQLException(exceptionMessage.toString()); } if (sqlType == null) { if (strict) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_NOT_FOUND) .setColumnName(columnName) .setTableName(tableName) .build() .buildException(); } unfoundColumnCount++; } else { columnInfoList.add(new ColumnInfo(columnName, sqlType)); } } if (unfoundColumnCount == columns.size()) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_NOT_FOUND) .setColumnName(Arrays.toString(columns.toArray(new String[0]))) .setTableName(tableName) .build() .buildException(); } } return columnInfoList; } public static boolean hasRowTimestampColumn(PTable table) { return table.getRowTimestampColPos() > 0; } public static byte[] getTableKey(PTable dataTable) { PName tenantId = dataTable.getTenantId(); PName schemaName = dataTable.getSchemaName(); return getTableKey( tenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : tenantId.getBytes(), schemaName == null ? ByteUtil.EMPTY_BYTE_ARRAY : schemaName.getBytes(), dataTable.getTableName().getBytes()); } }
@Override public SortOrder getSortOrder() { return SortOrder.getDefault(); }
public static LiteralExpression newConstant( Object value, PDataType type, Integer maxLength, Integer scale, Determinism determinism) throws SQLException { // remove? return newConstant(value, type, maxLength, scale, SortOrder.getDefault(), determinism); }
public static LiteralExpression newConstant(Object value, PDataType type, Determinism determinism) throws SQLException { return newConstant(value, type, SortOrder.getDefault(), determinism); }