Search in sources :

Example 21 with IgniteSQLException

use of org.apache.ignite.internal.processors.query.IgniteSQLException in project ignite by apache.

the class IgniteH2Indexing method streamBatchedUpdateQuery.

/**
 * {@inheritDoc}
 */
@SuppressWarnings("ForLoopReplaceableByForEach")
@Override
public List<Long> streamBatchedUpdateQuery(String schemaName, String qry, List<Object[]> params, SqlClientContext cliCtx) throws IgniteCheckedException {
    if (cliCtx == null || !cliCtx.isStream()) {
        U.warn(log, "Connection is not in streaming mode.");
        return zeroBatchedStreamedUpdateResult(params.size());
    }
    final Connection conn = connectionForSchema(schemaName);
    final PreparedStatement stmt = prepareStatementAndCaches(conn, qry);
    if (GridSqlQueryParser.checkMultipleStatements(stmt))
        throw new IgniteSQLException("Multiple statements queries are not supported for streaming mode.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
    checkStatementStreamable(stmt);
    Prepared p = GridSqlQueryParser.prepared(stmt);
    UpdatePlan plan = dmlProc.getPlanForStatement(schemaName, conn, p, null, true, null);
    IgniteDataStreamer<?, ?> streamer = cliCtx.streamerForCache(plan.cacheContext().name());
    assert streamer != null;
    List<Long> res = new ArrayList<>(params.size());
    for (int i = 0; i < params.size(); i++) res.add(dmlProc.streamUpdateQuery(schemaName, streamer, stmt, params.get(i)));
    return res;
}
Also used : Connection(java.sql.Connection) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) Prepared(org.h2.command.Prepared) AtomicLong(java.util.concurrent.atomic.AtomicLong) ArrayList(java.util.ArrayList) PreparedStatement(java.sql.PreparedStatement) UpdatePlan(org.apache.ignite.internal.processors.query.h2.dml.UpdatePlan)

Example 22 with IgniteSQLException

use of org.apache.ignite.internal.processors.query.IgniteSQLException 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);
}
Also used : GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) HashMap(java.util.HashMap) 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) BinaryObject(org.apache.ignite.binary.BinaryObject) 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) T3(org.apache.ignite.internal.util.typedef.T3)

Example 23 with IgniteSQLException

use of org.apache.ignite.internal.processors.query.IgniteSQLException 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);
}
Also used : GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) HashMap(java.util.HashMap) 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 24 with IgniteSQLException

use of org.apache.ignite.internal.processors.query.IgniteSQLException in project ignite by apache.

the class UpdatePlanBuilder method verifyUpdateColumns.

/**
 * Check that UPDATE statement affects no key columns.
 *
 * @param statement Statement.
 */
private static void verifyUpdateColumns(GridSqlStatement statement) {
    if (statement == null || !(statement instanceof GridSqlUpdate))
        return;
    GridSqlUpdate update = (GridSqlUpdate) statement;
    GridSqlElement updTarget = update.target();
    Set<GridSqlTable> tbls = new HashSet<>();
    DmlAstUtils.collectAllGridTablesInTarget(updTarget, tbls);
    if (tbls.size() != 1)
        throw new IgniteSQLException("Failed to determine target table for UPDATE", IgniteQueryErrorCode.TABLE_NOT_FOUND);
    GridSqlTable tbl = tbls.iterator().next();
    GridH2Table gridTbl = tbl.dataTable();
    if (updateAffectsKeyColumns(gridTbl, update.set().keySet()))
        throw new IgniteSQLException("SQL UPDATE can't modify key or its fields directly", IgniteQueryErrorCode.KEY_UPDATE);
}
Also used : GridSqlTable(org.apache.ignite.internal.processors.query.h2.sql.GridSqlTable) GridH2Table(org.apache.ignite.internal.processors.query.h2.opt.GridH2Table) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) GridSqlElement(org.apache.ignite.internal.processors.query.h2.sql.GridSqlElement) GridSqlUpdate(org.apache.ignite.internal.processors.query.h2.sql.GridSqlUpdate) HashSet(java.util.HashSet)

Example 25 with IgniteSQLException

use of org.apache.ignite.internal.processors.query.IgniteSQLException 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 {
    GridCacheContext cctx = plan.cacheContext();
    DmlBatchSender sender = new DmlBatchSender(cctx, pageSize, 1);
    for (List<?> row : cursor) {
        T3<Object, Object, Object> row0 = plan.processRowForUpdate(row);
        Object key = row0.get1();
        Object oldVal = row0.get2();
        Object newVal = row0.get3();
        sender.add(key, new ModifyingEntryProcessor(oldVal, new EntryValueUpdater(newVal)), 0);
    }
    sender.flush();
    SQLException resEx = sender.error();
    if (resEx != null) {
        if (!F.isEmpty(sender.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=" + sender.failedKeys() + ']';
            SQLException dupEx = createJdbcSqlException(msg, IgniteQueryErrorCode.CONCURRENT_UPDATE);
            dupEx.setNextException(resEx);
            resEx = dupEx;
        }
        throw new IgniteSQLException(resEx);
    }
    return new UpdateResult(sender.updateCount(), sender.failedKeys().toArray());
}
Also used : GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) SQLException(java.sql.SQLException) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) DmlBatchSender(org.apache.ignite.internal.processors.query.h2.dml.DmlBatchSender)

Aggregations

IgniteSQLException (org.apache.ignite.internal.processors.query.IgniteSQLException)57 SQLException (java.sql.SQLException)20 ArrayList (java.util.ArrayList)19 IgniteCheckedException (org.apache.ignite.IgniteCheckedException)17 List (java.util.List)16 Column (org.h2.table.Column)13 IgniteException (org.apache.ignite.IgniteException)11 PreparedStatement (java.sql.PreparedStatement)9 GridQueryProperty (org.apache.ignite.internal.processors.query.GridQueryProperty)9 GridH2Table (org.apache.ignite.internal.processors.query.h2.opt.GridH2Table)9 Connection (java.sql.Connection)8 IgniteSystemProperties.getString (org.apache.ignite.IgniteSystemProperties.getString)8 LinkedHashMap (java.util.LinkedHashMap)7 SqlFieldsQuery (org.apache.ignite.cache.query.SqlFieldsQuery)7 GridCacheContext (org.apache.ignite.internal.processors.cache.GridCacheContext)7 QueryCursorImpl (org.apache.ignite.internal.processors.cache.QueryCursorImpl)7 GridH2RowDescriptor (org.apache.ignite.internal.processors.query.h2.opt.GridH2RowDescriptor)7 UUID (java.util.UUID)6 GridQueryTypeDescriptor (org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor)6 GridSqlColumn (org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn)6