Search in sources :

Example 11 with Column

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());
}
Also used : SQLException(java.sql.SQLException) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) GridBoundedConcurrentLinkedHashMap(org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) GridBoundedConcurrentLinkedHashMap(org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap) GridH2RowDescriptor(org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor) BinaryObject(org.apache.ignite.binary.BinaryObject) Column(org.h2.table.Column) List(java.util.List) ArrayList(java.util.ArrayList) BinaryObjectBuilder(org.apache.ignite.binary.BinaryObjectBuilder) GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) GridQueryProperty(org.apache.ignite.internal.processors.query.GridQueryProperty) EntryProcessor(javax.cache.processor.EntryProcessor) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) BinaryObject(org.apache.ignite.binary.BinaryObject)

Example 12 with Column

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;
}
Also used : ArrayList(java.util.ArrayList) GridLuceneIndex(org.apache.ignite.internal.processors.query.h2.opt.GridLuceneIndex) GridLuceneIndex(org.apache.ignite.internal.processors.query.h2.opt.GridLuceneIndex) H2PkHashIndex(org.apache.ignite.internal.processors.query.h2.database.H2PkHashIndex) Index(org.h2.index.Index) IndexColumn(org.h2.table.IndexColumn) GridH2RowDescriptor(org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor) IgniteCheckedException(org.apache.ignite.IgniteCheckedException) Column(org.h2.table.Column) IndexColumn(org.h2.table.IndexColumn) IgniteException(org.apache.ignite.IgniteException) GridQueryIndexDescriptor(org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor)

Example 13 with Column

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);
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) GridBoundedConcurrentLinkedHashMap(org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap) IgniteBiTuple(org.apache.ignite.lang.IgniteBiTuple) GridQueryTypeDescriptor(org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor) GridQueryProperty(org.apache.ignite.internal.processors.query.GridQueryProperty) GridH2RowDescriptor(org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor) Column(org.h2.table.Column) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) BinaryObject(org.apache.ignite.binary.BinaryObject) BinaryObjectBuilder(org.apache.ignite.binary.BinaryObjectBuilder)

Example 14 with Column

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();
}
Also used : IgniteCheckedException(org.apache.ignite.IgniteCheckedException) Value(org.h2.value.Value) BinaryObject(org.apache.ignite.binary.BinaryObject) Date(java.util.Date)

Example 15 with Column

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());
}
Also used : GridH2RowDescriptor(org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor) Column(org.h2.table.Column) IndexColumn(org.h2.table.IndexColumn) ArrayList(java.util.ArrayList) IndexColumn(org.h2.table.IndexColumn)

Aggregations

Column (org.h2.table.Column)18 IndexColumn (org.h2.table.IndexColumn)11 ArrayList (java.util.ArrayList)8 GridH2RowDescriptor (org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor)7 LinkedHashMap (java.util.LinkedHashMap)6 Expression (org.h2.expression.Expression)6 ExpressionColumn (org.h2.expression.ExpressionColumn)6 IgniteSQLException (org.apache.ignite.internal.processors.query.IgniteSQLException)5 GridH2Table (org.apache.ignite.internal.processors.query.h2.opt.GridH2Table)5 GridSqlType.fromColumn (org.apache.ignite.internal.processors.query.h2.sql.GridSqlType.fromColumn)5 ValueExpression (org.h2.expression.ValueExpression)5 HashMap (java.util.HashMap)4 IgniteCheckedException (org.apache.ignite.IgniteCheckedException)4 IgniteException (org.apache.ignite.IgniteException)4 GridSqlType.fromExpression (org.apache.ignite.internal.processors.query.h2.sql.GridSqlType.fromExpression)4 AlterTableAddConstraint (org.h2.command.ddl.AlterTableAddConstraint)4 Table (org.h2.table.Table)4 Map (java.util.Map)3 BinaryObject (org.apache.ignite.binary.BinaryObject)3 SQLException (java.sql.SQLException)2