use of org.gridgain.internal.h2.table.Column 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], colNames[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 - QueryUtils.DEFAULT_COLUMNS_COUNT; i++) {
Column c = tbl.getColumn(i + QueryUtils.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.gridgain.internal.h2.table.Column 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], colNames[keyColIdx]);
}
Object val = valSupplier.apply(row);
if (QueryUtils.isSqlType(desc.valueClass())) {
assert valColIdx != -1;
val = DmlUtils.convert(val, rowDesc, desc.valueClass(), colTypes[valColIdx], colNames[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], colNames[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 2 columns are _key and _val Skip 'em.
for (int i = QueryUtils.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.gridgain.internal.h2.table.Column in project ignite by apache.
the class UpdatePlanBuilder method verifyDmlColumns.
/**
* Checks that DML query (insert, merge, update, bulk load aka copy) columns: <br/>
* 1) doesn't contain both entire key (_key or alias) and columns referring to part of the key; <br/>
* 2) doesn't contain both entire value (_val or alias) and columns referring to part of the value. <br/>
*
* @param tab - updated table.
* @param affectedCols - table's column names affected by dml query. Their order should be the same as in the
* dml statement only to have the same columns order in the error message.
* @throws IgniteSQLException if check failed.
*/
private static void verifyDmlColumns(GridH2Table tab, Collection<Column> affectedCols) {
GridH2RowDescriptor desc = tab.rowDescriptor();
// _key (_val) or it alias exist in the update columns.
String keyColName = null;
String valColName = null;
// Whether fields that are part of the key (value) exist in the updated columns.
boolean hasKeyProps = false;
boolean hasValProps = false;
for (Column col : affectedCols) {
int colId = col.getColumnId();
// Checking that it's not specified both _key(_val) and its alias by the way.
if (desc.isKeyColumn(colId)) {
if (keyColName == null)
keyColName = col.getName();
else
throw new IgniteSQLException("Columns " + keyColName + " and " + col + " both refer to entire cache key object.", IgniteQueryErrorCode.PARSING);
} else if (desc.isValueColumn(colId)) {
if (valColName == null)
valColName = col.getName();
else
throw new IgniteSQLException("Columns " + valColName + " and " + col + " both refer to entire cache value object.", IgniteQueryErrorCode.PARSING);
} else {
// Column ids 0..2 are _key, _val, _ver
assert colId >= QueryUtils.DEFAULT_COLUMNS_COUNT : "Unexpected column [name=" + col + ", id=" + colId + "].";
if (desc.isColumnKeyProperty(colId - QueryUtils.DEFAULT_COLUMNS_COUNT))
hasKeyProps = true;
else
hasValProps = true;
}
// And check invariants for the fast fail.
boolean hasEntireKeyCol = keyColName != null;
boolean hasEntireValcol = valColName != null;
if (hasEntireKeyCol && hasKeyProps)
throw new IgniteSQLException("Column " + keyColName + " refers to entire key cache object. " + "It must not be mixed with other columns that refer to parts of key.", IgniteQueryErrorCode.PARSING);
if (hasEntireValcol && hasValProps)
throw new IgniteSQLException("Column " + valColName + " refers to entire value cache object. " + "It must not be mixed with other columns that refer to parts of value.", IgniteQueryErrorCode.PARSING);
if (!ALLOW_KEY_VAL_UPDATES) {
if (desc.isKeyColumn(colId) && !QueryUtils.isSqlType(desc.type().keyClass())) {
throw new IgniteSQLException("Update of composite key column is not supported", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
if (desc.isValueColumn(colId) && !QueryUtils.isSqlType(desc.type().valueClass())) {
throw new IgniteSQLException("Update of composite value column is not supported", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
}
}
}
use of org.gridgain.internal.h2.table.Column in project ignite by apache.
the class DmlAstUtils method elementOrDefault.
/**
* Do what we can to compute default value for this column (mimics H2 behavior).
* @see Table#getDefaultValue
* @see Column#validateConvertUpdateSequence
* @param el SQL element.
* @param col Column.
* @return {@link GridSqlConst#NULL}, if {@code el} is null, or {@code el} if
* it's not {@link GridSqlKeyword#DEFAULT}, or computed default value.
*/
private static GridSqlElement elementOrDefault(GridSqlElement el, GridSqlColumn col) {
if (el == null)
return GridSqlConst.NULL;
if (el != GridSqlKeyword.DEFAULT)
return el;
Column h2Col = col.column();
Expression dfltExpr = h2Col.getDefaultExpression();
Value dfltVal;
try {
dfltVal = dfltExpr != null ? dfltExpr.getValue(null) : null;
} catch (Exception ignored) {
throw new IgniteSQLException("Failed to evaluate default value for a column " + col.columnName());
}
if (dfltVal != null)
return new GridSqlConst(dfltVal);
int type = h2Col.getType();
DataType dt = DataType.getDataType(type);
if (dt.decimal)
dfltVal = ValueInt.get(0).convertTo(type);
else if (dt.type == Value.TIMESTAMP)
dfltVal = ValueTimestamp.fromMillis(U.currentTimeMillis());
else if (dt.type == Value.TIME)
dfltVal = ValueTime.fromNanos(0);
else if (dt.type == Value.DATE)
dfltVal = ValueDate.fromMillis(U.currentTimeMillis());
else
dfltVal = ValueString.get("").convertTo(type);
return new GridSqlConst(dfltVal);
}
use of org.gridgain.internal.h2.table.Column in project ignite by apache.
the class PartitionExtractor method extractSingle.
/**
* Extract single partition.
*
* @param leftCol Left column.
* @param rightConst Right constant.
* @param rightParam Right parameter.
* @param tblModel Table model.
* @return Partition or {@code null} if failed to extract.
*/
@Nullable
private PartitionSingleNode extractSingle(GridSqlColumn leftCol, GridSqlConst rightConst, GridSqlParameter rightParam, PartitionTableModel tblModel) throws IgniteCheckedException {
assert leftCol != null;
Column leftCol0 = leftCol.column();
assert leftCol0.getTable() != null;
assert leftCol0.getTable() instanceof GridH2Table;
GridH2Table tbl = (GridH2Table) leftCol0.getTable();
if (!tbl.isColumnForPartitionPruning(leftCol0))
return null;
PartitionTable tbl0 = tblModel.table(leftCol.tableAlias());
// If table is in ignored set, then we cannot use it for partition extraction.
if (tbl0 == null)
return null;
if (rightConst != null) {
int part = partResolver.partition(rightConst.value().getObject(), leftCol0.getType(), tbl.cacheName());
return new PartitionConstantNode(tbl0, part);
} else if (rightParam != null) {
int colType = leftCol0.getType();
return new PartitionParameterNode(tbl0, partResolver, rightParam.index(), leftCol0.getType(), mappedType(colType));
} else
return null;
}
Aggregations