use of org.h2.table.Column in project ignite by apache.
the class DmlStatementsProcessor method doUpdate.
/**
* Perform UPDATE operation on top of results of SELECT.
* @param cursor SELECT results.
* @param pageSize Batch size for streaming, anything <= 0 for single page operations.
* @return Pair [cursor corresponding to results of UPDATE (contains number of items affected); keys whose values
* had been modified concurrently (arguments for a re-run)].
*/
@SuppressWarnings({ "unchecked", "ThrowableResultOfMethodCallIgnored" })
private UpdateResult doUpdate(UpdatePlan plan, Iterable<List<?>> cursor, int pageSize) throws IgniteCheckedException {
GridH2RowDescriptor desc = plan.tbl.rowDescriptor();
GridCacheContext cctx = desc.context();
boolean bin = cctx.binaryMarshaller();
String[] updatedColNames = plan.colNames;
int valColIdx = plan.valColIdx;
boolean hasNewVal = (valColIdx != -1);
// Statement updates distinct properties if it does not have _val in updated columns list
// or if its list of updated columns includes only _val, i.e. is single element.
boolean hasProps = !hasNewVal || updatedColNames.length > 1;
long res = 0;
Map<Object, EntryProcessor<Object, Object, Boolean>> rows = new LinkedHashMap<>();
// Keys that failed to UPDATE due to concurrent updates.
List<Object> failedKeys = new ArrayList<>();
SQLException resEx = null;
Iterator<List<?>> it = cursor.iterator();
while (it.hasNext()) {
List<?> e = it.next();
Object key = e.get(0);
Object newVal;
Map<String, Object> newColVals = new HashMap<>();
for (int i = 0; i < plan.colNames.length; i++) {
if (hasNewVal && i == valColIdx - 2)
continue;
GridQueryProperty prop = plan.tbl.rowDescriptor().type().property(plan.colNames[i]);
assert prop != null;
newColVals.put(plan.colNames[i], convert(e.get(i + 2), desc, prop.type(), plan.colTypes[i]));
}
newVal = plan.valSupplier.apply(e);
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 < plan.tbl.getColumns().length - DEFAULT_COLUMNS_COUNT; i++) {
Column c = plan.tbl.getColumn(i + DEFAULT_COLUMNS_COUNT);
if (desc.isKeyValueOrVersionColumn(c.getColumnId()))
continue;
GridQueryProperty prop = desc.type().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.
desc.setColumnValue(null, newVal, colVal, i);
}
if (bin && hasProps) {
assert newVal instanceof BinaryObjectBuilder;
newVal = ((BinaryObjectBuilder) newVal).build();
}
Object srcVal = e.get(1);
if (bin && !(srcVal instanceof BinaryObject))
srcVal = cctx.grid().binary().toBinary(srcVal);
rows.put(key, new ModifyingEntryProcessor(srcVal, new EntryValueUpdater(newVal)));
if ((pageSize > 0 && rows.size() == pageSize) || (!it.hasNext())) {
PageProcessingResult pageRes = processPage(cctx, rows);
res += pageRes.cnt;
failedKeys.addAll(F.asList(pageRes.errKeys));
if (pageRes.ex != null) {
if (resEx == null)
resEx = pageRes.ex;
else
resEx.setNextException(pageRes.ex);
}
if (it.hasNext())
// No need to clear after the last batch.
rows.clear();
}
}
if (resEx != null) {
if (!F.isEmpty(failedKeys)) {
// Don't go for a re-run if processing of some keys yielded exceptions and report keys that
// had been modified concurrently right away.
String msg = "Failed to UPDATE some keys because they had been modified concurrently " + "[keys=" + failedKeys + ']';
SQLException dupEx = createJdbcSqlException(msg, IgniteQueryErrorCode.CONCURRENT_UPDATE);
dupEx.setNextException(resEx);
resEx = dupEx;
}
throw new IgniteSQLException(resEx);
}
return new UpdateResult(res, failedKeys.toArray());
}
use of org.h2.table.Column in project ignite by apache.
the class H2TableDescriptor method createSystemIndexes.
/** {@inheritDoc} */
@Override
public ArrayList<Index> createSystemIndexes(GridH2Table tbl) {
ArrayList<Index> idxs = new ArrayList<>();
IndexColumn keyCol = tbl.indexColumn(KEY_COL, SortOrder.ASCENDING);
IndexColumn affCol = tbl.getAffinityKeyColumn();
if (affCol != null && H2Utils.equals(affCol, keyCol))
affCol = null;
GridH2RowDescriptor desc = tbl.rowDescriptor();
Index hashIdx = createHashIndex(tbl, "_key_PK_hash", H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), keyCol, affCol));
if (hashIdx != null)
idxs.add(hashIdx);
// Add primary key index.
Index pkIdx = idx.createSortedIndex(schema, "_key_PK", tbl, true, H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), keyCol, affCol), -1);
idxs.add(pkIdx);
if (type().valueClass() == String.class) {
try {
luceneIdx = new GridLuceneIndex(idx.kernalContext(), schema.offheap(), tbl.cacheName(), type);
} catch (IgniteCheckedException e1) {
throw new IgniteException(e1);
}
}
boolean affIdxFound = false;
GridQueryIndexDescriptor textIdx = type.textIndex();
if (textIdx != null) {
try {
luceneIdx = new GridLuceneIndex(idx.kernalContext(), schema.offheap(), tbl.cacheName(), type);
} catch (IgniteCheckedException e1) {
throw new IgniteException(e1);
}
}
// Locate index where affinity column is first (if any).
if (affCol != null) {
for (GridQueryIndexDescriptor idxDesc : type.indexes().values()) {
if (idxDesc.type() != QueryIndexType.SORTED)
continue;
String firstField = idxDesc.fields().iterator().next();
Column col = tbl.getColumn(firstField);
IndexColumn idxCol = tbl.indexColumn(col.getColumnId(), idxDesc.descending(firstField) ? SortOrder.DESCENDING : SortOrder.ASCENDING);
affIdxFound |= H2Utils.equals(idxCol, affCol);
}
}
// Add explicit affinity key index if nothing alike was found.
if (affCol != null && !affIdxFound) {
idxs.add(idx.createSortedIndex(schema, "AFFINITY_KEY", tbl, false, H2Utils.treeIndexColumns(desc, new ArrayList<IndexColumn>(2), affCol, keyCol), -1));
}
return idxs;
}
use of org.h2.table.Column in project ignite by apache.
the class DmlStatementsProcessor method rowToKeyValue.
/**
* Convert row presented as an array of Objects into key-value pair to be inserted to cache.
* @param cctx Cache context.
* @param row Row to process.
* @param plan Update plan.
* @throws IgniteCheckedException if failed.
*/
@SuppressWarnings({ "unchecked", "ConstantConditions", "ResultOfMethodCallIgnored" })
private IgniteBiTuple<?, ?> rowToKeyValue(GridCacheContext cctx, List<?> row, UpdatePlan plan) throws IgniteCheckedException {
GridH2RowDescriptor rowDesc = plan.tbl.rowDescriptor();
GridQueryTypeDescriptor desc = rowDesc.type();
Object key = plan.keySupplier.apply(row);
if (QueryUtils.isSqlType(desc.keyClass())) {
assert plan.keyColIdx != -1;
key = convert(key, rowDesc, desc.keyClass(), plan.colTypes[plan.keyColIdx]);
}
Object val = plan.valSupplier.apply(row);
if (QueryUtils.isSqlType(desc.valueClass())) {
assert plan.valColIdx != -1;
val = convert(val, rowDesc, desc.valueClass(), plan.colTypes[plan.valColIdx]);
}
if (key == null)
throw new IgniteSQLException("Key for INSERT or MERGE must not be null", IgniteQueryErrorCode.NULL_KEY);
if (val == null)
throw new IgniteSQLException("Value for INSERT or MERGE must not be null", IgniteQueryErrorCode.NULL_VALUE);
Map<String, Object> newColVals = new HashMap<>();
for (int i = 0; i < plan.colNames.length; i++) {
if (i == plan.keyColIdx || i == plan.valColIdx)
continue;
String colName = plan.colNames[i];
GridQueryProperty prop = desc.property(colName);
assert prop != null;
Class<?> expCls = prop.type();
newColVals.put(colName, convert(row.get(i), rowDesc, expCls, plan.colTypes[i]));
}
// 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[] cols = plan.tbl.getColumns();
// First 3 columns are _key, _val and _ver. Skip 'em.
for (int i = DEFAULT_COLUMNS_COUNT; i < cols.length; i++) {
if (plan.tbl.rowDescriptor().isKeyValueOrVersionColumn(i))
continue;
String colName = cols[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();
}
return new IgniteBiTuple<>(key, val);
}
use of org.h2.table.Column in project ignite by apache.
the class DmlStatementsProcessor method convert.
/**
* Convert value to column's expected type by means of H2.
*
* @param val Source value.
* @param desc Row descriptor.
* @param expCls Expected value class.
* @param type Expected column type to convert to.
* @return Converted object.
* @throws IgniteCheckedException if failed.
*/
@SuppressWarnings({ "ConstantConditions", "SuspiciousSystemArraycopy" })
private static Object convert(Object val, GridH2RowDescriptor desc, Class<?> expCls, int type) throws IgniteCheckedException {
if (val == null)
return null;
Class<?> currCls = val.getClass();
if (val instanceof Date && currCls != Date.class && expCls == Date.class) {
// precise Date instance. Let's satisfy it.
return new Date(((Date) val).getTime());
}
// User-given UUID is always serialized by H2 to byte array, so we have to deserialize manually
if (type == Value.UUID && currCls == byte[].class)
return U.unmarshal(desc.context().marshaller(), (byte[]) val, U.resolveClassLoader(desc.context().gridConfig()));
// Still, we only can convert from Object[] to something more precise.
if (type == Value.ARRAY && currCls != expCls) {
if (currCls != Object[].class)
throw new IgniteCheckedException("Unexpected array type - only conversion from Object[] is assumed");
// Why would otherwise type be Value.ARRAY?
assert expCls.isArray();
Object[] curr = (Object[]) val;
Object newArr = Array.newInstance(expCls.getComponentType(), curr.length);
System.arraycopy(curr, 0, newArr, 0, curr.length);
return newArr;
}
int objType = DataType.getTypeFromClass(val.getClass());
if (objType == type)
return val;
Value h2Val = desc.wrap(val, objType);
return h2Val.convertTo(type).getObject();
}
use of org.h2.table.Column in project ignite by apache.
the class H2TableDescriptor method createUserIndex.
/**
* Create user index.
*
* @param idxDesc Index descriptor.
* @return Index.
*/
public GridH2IndexBase createUserIndex(GridQueryIndexDescriptor idxDesc) {
IndexColumn keyCol = tbl.indexColumn(KEY_COL, SortOrder.ASCENDING);
IndexColumn affCol = tbl.getAffinityKeyColumn();
List<IndexColumn> cols = new ArrayList<>(idxDesc.fields().size() + 2);
for (String field : idxDesc.fields()) {
Column col = tbl.getColumn(field);
cols.add(tbl.indexColumn(col.getColumnId(), idxDesc.descending(field) ? SortOrder.DESCENDING : SortOrder.ASCENDING));
}
GridH2RowDescriptor desc = tbl.rowDescriptor();
if (idxDesc.type() == QueryIndexType.SORTED) {
cols = H2Utils.treeIndexColumns(desc, cols, keyCol, affCol);
return idx.createSortedIndex(schema, idxDesc.name(), tbl, false, cols, idxDesc.inlineSize());
} else if (idxDesc.type() == QueryIndexType.GEOSPATIAL) {
return H2Utils.createSpatialIndex(tbl, idxDesc.name(), cols.toArray(new IndexColumn[cols.size()]));
}
throw new IllegalStateException("Index type: " + idxDesc.type());
}
Aggregations