private String combineWithEqualClause(String prefix, Collection<Field<?>> keys, String suffix) { StringJoiner joiner = new StringJoiner(" AND ", prefix, suffix + ";"); for (Field<?> key : keys) { joiner.add(key.getName() + "=?"); } return joiner.toString(); }
private void appendScanBound(StringBuilder sb, Collection<Field<?>> keys, String comparator) { if (keys.isEmpty()) { return; } StringJoiner keyJoiner = new StringJoiner(",", "(", ")"); StringJoiner valueJoiner = new StringJoiner(",", "(", ")"); for (Field<?> field : keys) { keyJoiner.add(field.getName()); valueJoiner.add("?"); } sb.append(keyJoiner.toString()) .append(comparator) .append(valueJoiner.toString()); }
/** * Get the write sql query for PreparedStatement for the fields given. For example, if "simpletable" has 5 columns, * (key1, key2, col1, col2, col3), this write query will generate the following query: * INSERT INTO simpletable (key1,key2,col1,col2,col3) VALUES (?,?,?,?,?) ON CONFLICT (key1,key2) * DO UPDATE SET col1=EXCLUDED.col1,col2=EXCLUDED.col2,col3=EXCLUDED.col3; * * @param fields fields to write * @return the sql query */ private String getWriteSqlQuery(Collection<Field<?>> fields) { StringJoiner insertPart = new StringJoiner(",", "INSERT INTO " + tableSchema.getTableId().getName() + " (", ") "); StringJoiner valuePart = new StringJoiner(",", "VALUES (", ") "); StringJoiner conflictPart = new StringJoiner(",", "ON CONFLICT (", ") "); StringJoiner updatePart = new StringJoiner(",", "DO UPDATE SET ", ";"); for (Field<?> field : fields) { insertPart.add(field.getName()); valuePart.add("?"); if (tableSchema.isPrimaryKeyColumn(field.getName())) { conflictPart.add(field.getName()); } else { updatePart.add(field.getName() + "=EXCLUDED." + field.getName()); } } return insertPart.toString() + valuePart.toString() + conflictPart.toString() + updatePart.toString(); }
fieldValidator.validateField(field); Object value = field.getValue(); FieldType.Type type = tableSchema.getType(field.getName()); if (type == null) { throw new InvalidFieldException(tableSchema.getTableId(), field.getName()); default: throw new InvalidFieldException(tableSchema.getTableId(), field.getName());
@Override public boolean compareAndSwap(Collection<Field<?>> keys, Field<?> oldValue, Field<?> newValue) { LOG.trace("Table {}: CompareAndSwap with keys {}, oldValue {}, newValue {}", schema.getTableId(), keys, oldValue, newValue); fieldValidator.validateField(oldValue); if (oldValue.getFieldType() != newValue.getFieldType()) { throw new IllegalArgumentException( String.format("Field types of oldValue (%s) and newValue (%s) are not the same", oldValue.getFieldType(), newValue.getFieldType())); } if (!oldValue.getName().equals(newValue.getName())) { throw new IllegalArgumentException( String.format("Trying to compare and swap different fields. Old Value = %s, New Value = %s", oldValue, newValue)); } if (schema.isPrimaryKeyColumn(oldValue.getName())) { throw new IllegalArgumentException("Cannot use compare and swap on a primary key field"); } return table.compareAndSwap(convertKeyToBytes(keys, false), Bytes.toBytes(oldValue.getName()), fieldToBytes(oldValue, oldValue.getFieldType()), fieldToBytes(newValue, newValue.getFieldType())); }
for (Field<?> key : keys) { validateField(key); if (!key.getName().equals(primaryKeys.get(i))) { throw new InvalidFieldException( tableSchema.getTableId(), keys,
oldValue.getFieldType(), newValue.getFieldType())); if (!oldValue.getName().equals(newValue.getName())) { throw new IllegalArgumentException( String.format("Trying to compare and swap different fields. Old Value = %s, New Value = %s", oldValue, newValue)); if (tableSchema.isPrimaryKeyColumn(oldValue.getName())) { throw new IllegalArgumentException("Cannot use compare and swap on a primary key field"); String readQuery = getReadQuery(keys, Collections.singleton(oldValue.getName()), true); try (PreparedStatement statement = connection.prepareStatement(readQuery)) { int index = 1; Field<?> dbValue = createField(oldValue.getName(), oldValue.getFieldType(), colValue); if (!oldValue.equals(dbValue)) { return false;
for (Field<?> field : fields) { fieldValidator.validateField(field); if (schema.isPrimaryKeyColumn(field.getName())) { addKey(key, field, schema.getType(field.getName())); } else { if (schema.getType(field.getName()) == null) { throw new InvalidFieldException(schema.getTableId(), field.getName()); columns[i] = Bytes.toBytes(field.getName()); values[i] = fieldToBytes(field, schema.getType(field.getName())); i++;
/** * Convert the keys to corresponding byte array. The keys can either be a prefix or complete primary keys depending * on the value of allowPrefix. The method will always prepend the table name as a prefix for the row keys. * * @param keys keys to convert * @param allowPrefix true if the keys can be prefix false if the keys have to contain all the primary keys. * @return the byte array converted * @throws InvalidFieldException if the key are not prefix or complete primary keys */ private byte[] convertKeyToBytes(Collection<Field<?>> keys, boolean allowPrefix) throws InvalidFieldException { fieldValidator.validatePrimaryKeys(keys, allowPrefix); MDSKey.Builder mdsKey = new MDSKey.Builder(keyPrefix); for (Field<?> key : keys) { addKey(mdsKey, key, schema.getType(key.getName())); } return mdsKey.build().getKey(); }
private void addKey(MDSKey.Builder key, Field<?> field, FieldType.Type type) throws InvalidFieldException { if (field.getValue() == null) { throw new InvalidFieldException(schema.getTableId(), field.getName(), "is a primary key and value is null"); } switch (type) { case INTEGER: key.add((Integer) field.getValue()); return; case LONG: key.add((Long) field.getValue()); return; case STRING: key.add((String) field.getValue()); return; case BYTES: key.add((byte[]) field.getValue()); return; default: throw new InvalidFieldException(schema.getTableId(), field.getName()); } }
/** * Validate if the given field matches the schema. The given field is invalid if: it is not present in the given * schema, its type is different than the given schema, or if it is a primary key but the given value is null. * * @param field the field to validate * @throws InvalidFieldException if the field does not pass the validation */ public void validateField(Field<?> field) throws InvalidFieldException { String fieldName = field.getName(); FieldType.Type expected = tableSchema.getType(fieldName); FieldType.Type actual = field.getFieldType(); if (expected == null) { throw new InvalidFieldException(tableSchema.getTableId(), fieldName); } if (!expected.equals(actual)) { throw new InvalidFieldException(tableSchema.getTableId(), fieldName, expected, actual); } if (tableSchema.isPrimaryKeyColumn(fieldName) && field.getValue() == null) { throw new InvalidFieldException(tableSchema.getTableId(), fieldName, "is a primary key but the value is null"); } }
oldValues.put(field.getName(), field);
private byte[] fieldToBytes(Field<?> field, FieldType.Type type) throws InvalidFieldException { if (field.getValue() == null) { return null; } switch (type) { case INTEGER: return Bytes.toBytes((Integer) field.getValue()); case LONG: return Bytes.toBytes((Long) field.getValue()); case FLOAT: return Bytes.toBytes((Float) field.getValue()); case DOUBLE: return Bytes.toBytes((Double) field.getValue()); case STRING: return Bytes.toBytes((String) field.getValue()); case BYTES: return (byte[]) field.getValue(); default: throw new InvalidFieldException(schema.getTableId(), field.getName()); } }
getTransactionRunner().run(context -> { StructuredTable table = context.getTable(SIMPLE_TABLE); table.increment(keys, longField.getName(), increment); try { table.increment(keys, FLOAT_COL, increment);