use of io.cdap.cdap.spi.data.table.field.Field in project cdap by caskdata.
the class PostgreSqlStructuredTable method compareAndSwap.
@Override
public boolean compareAndSwap(Collection<Field<?>> keys, Field<?> oldValue, Field<?> newValue) throws InvalidFieldException, IOException {
LOG.trace("Table {}: CompareAndSwap with keys {}, oldValue {}, newValue {}", tableSchema.getTableId(), keys, oldValue, newValue);
fieldValidator.validatePrimaryKeys(keys, false);
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 (tableSchema.isPrimaryKeyColumn(oldValue.getName())) {
throw new IllegalArgumentException("Cannot use compare and swap on a primary key field");
}
// First compare
String readQuery = getReadQuery(keys, Collections.singleton(oldValue.getName()), true);
try (PreparedStatement statement = connection.prepareStatement(readQuery)) {
int index = 1;
for (Field<?> key : keys) {
setField(statement, key, index);
index++;
}
LOG.trace("SQL statement: {}", statement);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
// Compare the value in the DB to oldValue
Object colValue = resultSet.getObject(1);
Field<?> dbValue = createField(oldValue.getName(), oldValue.getFieldType(), colValue);
if (!oldValue.equals(dbValue)) {
return false;
}
} else {
// There is no data for the field in the DB, hence oldValue should be null to continue
if (oldValue.getValue() != null) {
return false;
}
}
}
} catch (SQLException e) {
throw new IOException(String.format("Failed to read from table %s with keys %s", tableSchema.getTableId().getName(), keys), e);
}
// Then write
Collection<Field<?>> fields = new HashSet<>(keys);
fields.add(newValue);
upsertInternal(fields);
return true;
}
use of io.cdap.cdap.spi.data.table.field.Field in project cdap by caskdata.
the class PostgreSqlStructuredTable method updateInternal.
private void updateInternal(Collection<Field<?>> fields) throws IOException {
String sqlQuery = getUpdateSqlQuery(fields);
try (PreparedStatement statement = connection.prepareStatement(sqlQuery)) {
Map<Boolean, List<Field<?>>> lists = fields.stream().collect(Collectors.partitioningBy(field -> tableSchema.isPrimaryKeyColumn(field.getName())));
int index = 1;
// set field values to update
for (Field<?> field : lists.get(false)) {
setField(statement, field, index);
index++;
}
// set field values in the WHERE clause
for (Field<?> field : lists.get(true)) {
setField(statement, field, index);
index++;
}
LOG.trace("SQL statement: {}", statement);
statement.executeUpdate();
} catch (SQLException e) {
throw new IOException(String.format("Failed to write to table %s with fields %s", tableSchema.getTableId().getName(), fields), e);
}
}
use of io.cdap.cdap.spi.data.table.field.Field in project cdap by caskdata.
the class PostgreSqlStructuredTable method multiRead.
@Override
public Collection<StructuredRow> multiRead(Collection<? extends Collection<Field<?>>> multiKeys) throws InvalidFieldException, IOException {
LOG.trace("Table {}: Read with multiple keys {}", tableSchema.getTableId(), multiKeys);
if (multiKeys.isEmpty()) {
return Collections.emptyList();
}
for (Collection<Field<?>> keys : multiKeys) {
fieldValidator.validatePrimaryKeys(keys, false);
}
// Collapse values of each key
Map<String, Set<Field<?>>> keyFields = new LinkedHashMap<>();
multiKeys.stream().flatMap(Collection::stream).forEach(field -> keyFields.computeIfAbsent(field.getName(), k -> new LinkedHashSet<>()).add(field));
try (PreparedStatement statement = prepareMultiReadQuery(keyFields)) {
LOG.trace("SQL statement: {}", statement);
Collection<StructuredRow> result = new ArrayList<>();
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
result.add(resultSetToRow(resultSet));
}
return result;
}
} catch (SQLException e) {
throw new IOException(String.format("Failed to read from table %s with multi keys %s", tableSchema.getTableId().getName(), multiKeys), e);
}
}
use of io.cdap.cdap.spi.data.table.field.Field in project cdap by caskdata.
the class ArtifactStore method getApplicationClasses.
/**
* Get all application classes that belong to the specified namespace.
* Results are returned as a sorted map from artifact to application classes in that artifact.
* Map entries are sorted by the artifact.
*
* @param namespace the namespace from which to get application classes
* @return an unmodifiable map of artifact to a list of all application classes in that artifact.
* The map will never be null. If there are no application classes, an empty map will be returned.
*/
public SortedMap<ArtifactDescriptor, List<ApplicationClass>> getApplicationClasses(NamespaceId namespace) {
return TransactionRunners.run(transactionRunner, context -> {
SortedMap<ArtifactDescriptor, List<ApplicationClass>> result = Maps.newTreeMap();
StructuredTable table = getTable(context, StoreDefinition.ArtifactStore.APP_DATA_TABLE);
Collection<Field<?>> keys = Collections.singleton(Fields.stringField(StoreDefinition.ArtifactStore.NAMESPACE_FIELD, namespace.getNamespace()));
try (CloseableIterator<StructuredRow> iterator = table.scan(Range.singleton(keys), Integer.MAX_VALUE)) {
while (iterator.hasNext()) {
StructuredRow row = iterator.next();
Map.Entry<ArtifactDescriptor, ApplicationClass> entry = extractApplicationClass(row);
List<ApplicationClass> existingAppClasses = result.computeIfAbsent(entry.getKey(), k -> new ArrayList<>());
existingAppClasses.add(entry.getValue());
}
}
return Collections.unmodifiableSortedMap(result);
});
}
use of io.cdap.cdap.spi.data.table.field.Field in project cdap by caskdata.
the class ArtifactStore method getApplicationClasses.
/**
* Get all application classes that belong to the specified namespace of the specified classname.
* Results are returned as a sorted map from artifact to application classes in that artifact.
* Map entries are sorted by the artifact.
*
* @param namespace the namespace from which to get application classes
* @param className the classname of application classes to get
* @return an unmodifiable map of artifact the application classes in that artifact.
* The map will never be null. If there are no application classes, an empty map will be returned.
*/
public SortedMap<ArtifactDescriptor, ApplicationClass> getApplicationClasses(final NamespaceId namespace, final String className) {
return TransactionRunners.run(transactionRunner, context -> {
StructuredTable table = getTable(context, StoreDefinition.ArtifactStore.APP_DATA_TABLE);
SortedMap<ArtifactDescriptor, ApplicationClass> result = Maps.newTreeMap();
Collection<Field<?>> keys = ImmutableList.of(Fields.stringField(StoreDefinition.ArtifactStore.NAMESPACE_FIELD, namespace.getNamespace()), Fields.stringField(StoreDefinition.ArtifactStore.CLASS_NAME_FIELD, className));
try (CloseableIterator<StructuredRow> iterator = table.scan(Range.singleton(keys), Integer.MAX_VALUE)) {
while (iterator.hasNext()) {
StructuredRow row = iterator.next();
Map.Entry<ArtifactDescriptor, ApplicationClass> entry = extractApplicationClass(row);
result.put(entry.getKey(), entry.getValue());
}
}
return Collections.unmodifiableSortedMap(result);
});
}
Aggregations