use of org.apache.ignite.binary.BinaryObjectBuilder in project ignite by apache.
the class UpdatePlan method processRowForUpdate.
/**
* Convert a row into value.
*
* @param row Row to process.
* @throws IgniteCheckedException if failed.
* @return Tuple contains: [key, old value, new value]
*/
public T3<Object, Object, Object> processRowForUpdate(List<?> row) throws IgniteCheckedException {
GridH2RowDescriptor rowDesc = tbl.rowDescriptor();
GridQueryTypeDescriptor desc = rowDesc.type();
GridCacheContext cctx = rowDesc.context();
boolean hasNewVal = (valColIdx != -1);
boolean hasProps = !hasNewVal || colNames.length > 1;
Object key = row.get(0);
Object oldVal = row.get(1);
if (cctx.binaryMarshaller() && !(oldVal instanceof BinaryObject))
oldVal = cctx.grid().binary().toBinary(oldVal);
Object newVal;
Map<String, Object> newColVals = new HashMap<>();
for (int i = 0; i < colNames.length; i++) {
if (hasNewVal && i == valColIdx - 2)
continue;
GridQueryProperty prop = tbl.rowDescriptor().type().property(colNames[i]);
assert prop != null : "Unknown property: " + colNames[i];
newColVals.put(colNames[i], DmlUtils.convert(row.get(i + 2), rowDesc, prop.type(), colTypes[i]));
}
newVal = valSupplier.apply(row);
if (newVal == null)
throw new IgniteSQLException("New value for UPDATE must not be null", IgniteQueryErrorCode.NULL_VALUE);
// Skip key and value - that's why we start off with 3rd column
for (int i = 0; i < tbl.getColumns().length - DEFAULT_COLUMNS_COUNT; i++) {
Column c = tbl.getColumn(i + DEFAULT_COLUMNS_COUNT);
if (rowDesc.isKeyValueOrVersionColumn(c.getColumnId()))
continue;
GridQueryProperty prop = desc.property(c.getName());
if (prop.key())
// Don't get values of key's columns - we won't use them anyway
continue;
boolean hasNewColVal = newColVals.containsKey(c.getName());
if (!hasNewColVal)
continue;
Object colVal = newColVals.get(c.getName());
// UPDATE currently does not allow to modify key or its fields, so we must be safe to pass null as key.
rowDesc.setColumnValue(null, newVal, colVal, i);
}
if (cctx.binaryMarshaller() && hasProps) {
assert newVal instanceof BinaryObjectBuilder;
newVal = ((BinaryObjectBuilder) newVal).build();
}
desc.validateKeyAndValue(key, newVal);
return new T3<>(key, oldVal, newVal);
}
use of org.apache.ignite.binary.BinaryObjectBuilder in project ignite by apache.
the class UpdatePlan method processRow.
/**
* Convert a row into key-value pair.
*
* @param row Row to process.
* @throws IgniteCheckedException if failed.
*/
public IgniteBiTuple<?, ?> processRow(List<?> row) throws IgniteCheckedException {
if (mode != BULK_LOAD && row.size() != colNames.length)
throw new IgniteSQLException("Not enough values in a row: " + row.size() + " instead of " + colNames.length, IgniteQueryErrorCode.ENTRY_PROCESSING);
GridH2RowDescriptor rowDesc = tbl.rowDescriptor();
GridQueryTypeDescriptor desc = rowDesc.type();
GridCacheContext cctx = rowDesc.context();
Object key = keySupplier.apply(row);
if (QueryUtils.isSqlType(desc.keyClass())) {
assert keyColIdx != -1;
key = DmlUtils.convert(key, rowDesc, desc.keyClass(), colTypes[keyColIdx]);
}
Object val = valSupplier.apply(row);
if (QueryUtils.isSqlType(desc.valueClass())) {
assert valColIdx != -1;
val = DmlUtils.convert(val, rowDesc, desc.valueClass(), colTypes[valColIdx]);
}
if (key == null) {
if (F.isEmpty(desc.keyFieldName()))
throw new IgniteSQLException("Key for INSERT, COPY, or MERGE must not be null", IgniteQueryErrorCode.NULL_KEY);
else
throw new IgniteSQLException("Null value is not allowed for column '" + desc.keyFieldName() + "'", IgniteQueryErrorCode.NULL_KEY);
}
if (val == null) {
if (F.isEmpty(desc.valueFieldName()))
throw new IgniteSQLException("Value for INSERT, COPY, MERGE, or UPDATE must not be null", IgniteQueryErrorCode.NULL_VALUE);
else
throw new IgniteSQLException("Null value is not allowed for column '" + desc.valueFieldName() + "'", IgniteQueryErrorCode.NULL_VALUE);
}
int actualColCnt = Math.min(colNames.length, row.size());
Map<String, Object> newColVals = new HashMap<>();
for (int i = 0; i < actualColCnt; i++) {
if (i == keyColIdx || i == valColIdx)
continue;
String colName = colNames[i];
GridQueryProperty prop = desc.property(colName);
assert prop != null;
Class<?> expCls = prop.type();
newColVals.put(colName, DmlUtils.convert(row.get(i), rowDesc, expCls, colTypes[i]));
}
desc.setDefaults(key, val);
// We update columns in the order specified by the table for a reason - table's
// column order preserves their precedence for correct update of nested properties.
Column[] tblCols = tbl.getColumns();
// First 3 columns are _key, _val and _ver. Skip 'em.
for (int i = DEFAULT_COLUMNS_COUNT; i < tblCols.length; i++) {
if (tbl.rowDescriptor().isKeyValueOrVersionColumn(i))
continue;
String colName = tblCols[i].getName();
if (!newColVals.containsKey(colName))
continue;
Object colVal = newColVals.get(colName);
desc.setValue(colName, key, val, colVal);
}
if (cctx.binaryMarshaller()) {
if (key instanceof BinaryObjectBuilder)
key = ((BinaryObjectBuilder) key).build();
if (val instanceof BinaryObjectBuilder)
val = ((BinaryObjectBuilder) val).build();
}
desc.validateKeyAndValue(key, val);
return new IgniteBiTuple<>(key, val);
}
use of org.apache.ignite.binary.BinaryObjectBuilder in project ignite by apache.
the class UpdatePlanBuilder method createSupplier.
/**
* Detect appropriate method of instantiating key or value (take from param, create binary builder,
* invoke default ctor, or allocate).
*
* @param cctx Cache context.
* @param desc Table descriptor.
* @param colIdx Column index if key or value is present in columns list, {@code -1} if it's not.
* @param hasProps Whether column list affects individual properties of key or value.
* @param key Whether supplier should be created for key or for value.
* @return Closure returning key or value.
* @throws IgniteCheckedException If failed.
*/
@SuppressWarnings({ "ConstantConditions", "unchecked" })
private static KeyValueSupplier createSupplier(final GridCacheContext<?, ?> cctx, GridQueryTypeDescriptor desc, final int colIdx, boolean hasProps, final boolean key, boolean forUpdate) throws IgniteCheckedException {
final String typeName = key ? desc.keyTypeName() : desc.valueTypeName();
// Try to find class for the key locally.
final Class<?> cls = key ? U.firstNotNull(U.classForName(desc.keyTypeName(), null), desc.keyClass()) : desc.valueClass();
boolean isSqlType = QueryUtils.isSqlType(cls);
// If we don't need to construct anything from scratch, just return value from given list.
if (isSqlType || !hasProps) {
if (colIdx != -1)
return new PlainValueSupplier(colIdx);
else if (isSqlType)
// Non constructable keys and values (SQL types) must be present in the query explicitly.
throw new IgniteCheckedException((key ? "Key" : "Value") + " is missing from query");
}
if (cctx.binaryMarshaller()) {
if (colIdx != -1) {
// If we have key or value explicitly present in query, create new builder upon them...
return new KeyValueSupplier() {
/**
* {@inheritDoc}
*/
@Override
public Object apply(List<?> arg) throws IgniteCheckedException {
Object obj = arg.get(colIdx);
if (obj == null)
return null;
BinaryObject bin = cctx.grid().binary().toBinary(obj);
BinaryObjectBuilder builder = cctx.grid().binary().builder(bin);
cctx.prepareAffinityField(builder);
return builder;
}
};
} else {
// ...and if we don't, just create a new builder.
return new KeyValueSupplier() {
/**
* {@inheritDoc}
*/
@Override
public Object apply(List<?> arg) throws IgniteCheckedException {
BinaryObjectBuilder builder = cctx.grid().binary().builder(typeName);
cctx.prepareAffinityField(builder);
return builder;
}
};
}
} else {
if (colIdx != -1) {
if (forUpdate && colIdx == 1) {
// so we have to clone it. And on UPDATE we don't expect any key supplier.
assert !key;
return new KeyValueSupplier() {
/**
* {@inheritDoc}
*/
@Override
public Object apply(List<?> arg) throws IgniteCheckedException {
byte[] oldPropBytes = cctx.marshaller().marshal(arg.get(1));
// colVal is another object now, we can mutate it
return cctx.marshaller().unmarshal(oldPropBytes, U.resolveClassLoader(cctx.gridConfig()));
}
};
} else
// We either are not updating, or the new value is given explicitly, no cloning needed.
return new PlainValueSupplier(colIdx);
}
Constructor<?> ctor;
try {
ctor = cls.getDeclaredConstructor();
ctor.setAccessible(true);
} catch (NoSuchMethodException | SecurityException ignored) {
ctor = null;
}
if (ctor != null) {
final Constructor<?> ctor0 = ctor;
// Use default ctor, if it's present...
return new KeyValueSupplier() {
/**
* {@inheritDoc}
*/
@Override
public Object apply(List<?> arg) throws IgniteCheckedException {
try {
return ctor0.newInstance();
} catch (Exception e) {
if (S.INCLUDE_SENSITIVE)
throw new IgniteCheckedException("Failed to instantiate " + (key ? "key" : "value") + " [type=" + typeName + ']', e);
else
throw new IgniteCheckedException("Failed to instantiate " + (key ? "key" : "value") + '.', e);
}
}
};
} else {
// ...or allocate new instance with unsafe, if it's not
return new KeyValueSupplier() {
/**
* {@inheritDoc}
*/
@Override
public Object apply(List<?> arg) throws IgniteCheckedException {
try {
return GridUnsafe.allocateInstance(cls);
} catch (InstantiationException e) {
if (S.INCLUDE_SENSITIVE)
throw new IgniteCheckedException("Failed to instantiate " + (key ? "key" : "value") + " [type=" + typeName + ']', e);
else
throw new IgniteCheckedException("Failed to instantiate " + (key ? "key" : "value") + '.', e);
}
}
};
}
}
}
use of org.apache.ignite.binary.BinaryObjectBuilder in project ignite by apache.
the class BinaryMarshallerSelfTest method testFieldOrderByBuilder.
/**
* The test must be refactored after {@link IgniteSystemProperties#IGNITE_BINARY_SORT_OBJECT_FIELDS}
* is removed.
*
* @throws Exception If failed.
*/
public void testFieldOrderByBuilder() throws Exception {
if (BinaryUtils.FIELDS_SORTED_ORDER)
return;
BinaryMarshaller m = binaryMarshaller();
BinaryObjectBuilder builder = new BinaryObjectBuilderImpl(binaryContext(m), "MyFakeClass");
String[] fieldNames = { "field9", "field8", "field0", "field1", "field2" };
for (String fieldName : fieldNames) builder.setField(fieldName, 0);
BinaryObject binObj = builder.build();
Collection<String> fieldsBin = binObj.type().fieldNames();
assertEquals(fieldNames.length, fieldsBin.size());
int i = 0;
for (String fieldName : fieldsBin) {
assertEquals(fieldNames[i], fieldName);
++i;
}
}
use of org.apache.ignite.binary.BinaryObjectBuilder in project ignite by apache.
the class BinaryMarshallerSelfTest method testThreadLocalArrayReleased.
/**
* @throws IgniteCheckedException If failed.
*/
public void testThreadLocalArrayReleased() throws Exception {
// Checking the writer directly.
assertEquals(false, INSTANCE.isAcquired());
BinaryMarshaller marsh = binaryMarshaller();
try (BinaryWriterExImpl writer = new BinaryWriterExImpl(binaryContext(marsh))) {
assertEquals(true, INSTANCE.isAcquired());
writer.writeString("Thread local test");
writer.array();
assertEquals(true, INSTANCE.isAcquired());
}
// Checking the binary marshaller.
assertEquals(false, INSTANCE.isAcquired());
marsh = binaryMarshaller();
marsh.marshal(new SimpleObject());
assertEquals(false, INSTANCE.isAcquired());
marsh = binaryMarshaller();
// Checking the builder.
BinaryObjectBuilder builder = new BinaryObjectBuilderImpl(binaryContext(marsh), "org.gridgain.foo.bar.TestClass");
builder.setField("a", "1");
BinaryObject binaryObj = builder.build();
assertEquals(false, INSTANCE.isAcquired());
}
Aggregations