public ColumnFamily updateForKey( ByteBuffer key, ColumnNameBuilder builder, UpdateParameters params) throws InvalidRequestException { CFDefinition cfDef = cfm.getCfDef(); ColumnFamily cf = UnsortedColumns.factory.create(cfm); // Inserting the CQL row marker (see #4361) // We always need to insert a marker, because of the following situation: // CREATE TABLE t ( k int PRIMARY KEY, c text ); // INSERT INTO t(k, c) VALUES (1, 1) // DELETE c FROM t WHERE k = 1; // SELECT * FROM t; // The last query should return one row (but with c == null). Adding // the marker with the insert make sure the semantic is correct (while making sure a // 'DELETE FROM t WHERE k = 1' does remove the row entirely) // // We never insert markers for Super CF as this would confuse the thrift side. if (cfDef.isComposite && !cfDef.isCompact && !cfm.isSuper()) { ByteBuffer name = builder.copy().add(ByteBufferUtil.EMPTY_BYTE_BUFFER).build(); cf.addColumn(params.makeColumn(name, ByteBufferUtil.EMPTY_BYTE_BUFFER)); } List<Operation> updates = getOperations(); if (cfDef.isCompact) { if (builder.componentCount() == 0) throw new InvalidRequestException( String.format("Missing PRIMARY KEY part %s", cfDef.columns.values().iterator().next())); if (cfDef.value == null) { // compact + no compact value implies there is no column outside the PK. So no operation // could // have passed through validation assert updates.isEmpty(); setToEmptyOperation.execute(key, cf, builder.copy(), params); } else { // compact means we don't have a row marker, so don't accept to set only the PK. See // CASSANDRA-5648. if (updates.isEmpty()) throw new InvalidRequestException( String.format("Column %s is mandatory for this COMPACT STORAGE table", cfDef.value)); for (Operation update : updates) update.execute(key, cf, builder.copy(), params); } } else { for (Operation update : updates) update.execute(key, cf, builder.copy(), params); } return cf; }
public Collection<RowMutation> getMutations( List<ByteBuffer> variables, boolean local, ConsistencyLevel cl, long now) throws RequestExecutionException, RequestValidationException { // keys List<ByteBuffer> keys = UpdateStatement.buildKeyNames(cfDef, processedKeys, variables); // columns ColumnNameBuilder builder = cfDef.getColumnNameBuilder(); CFDefinition.Name firstEmpty = UpdateStatement.buildColumnNames(cfDef, processedKeys, builder, variables, false); boolean fullKey = builder.componentCount() == cfDef.columns.size(); boolean isRange = cfDef.isCompact ? !fullKey : (!fullKey || toRemove.isEmpty()); if (!toRemove.isEmpty() && isRange) throw new InvalidRequestException( String.format( "Missing mandatory PRIMARY KEY part %s since %s specified", firstEmpty, toRemove.iterator().next().left)); // Lists DISCARD operation incurs a read. Do that now. Set<ByteBuffer> toRead = null; for (Pair<CFDefinition.Name, Term> p : toRemove) { CFDefinition.Name name = p.left; Term value = p.right; if ((name.type instanceof ListType) && value != null) { if (toRead == null) toRead = new TreeSet<ByteBuffer>(UTF8Type.instance); toRead.add(name.name.key); } } Map<ByteBuffer, ColumnGroupMap> rows = toRead != null ? readRows(keys, builder, toRead, (CompositeType) cfDef.cfm.comparator, local, cl) : null; Collection<RowMutation> rowMutations = new ArrayList<RowMutation>(keys.size()); UpdateParameters params = new UpdateParameters(variables, getTimestamp(now), -1); for (ByteBuffer key : keys) rowMutations.add( mutationForKey( cfDef, key, builder, isRange, params, rows == null ? null : rows.get(key))); return rowMutations; }
public RowMutation mutationForKey( CFDefinition cfDef, ByteBuffer key, ColumnNameBuilder builder, boolean isRange, UpdateParameters params, ColumnGroupMap group) throws InvalidRequestException { QueryProcessor.validateKey(key); RowMutation rm = new RowMutation(cfDef.cfm.ksName, key); ColumnFamily cf = rm.addOrGet(columnFamily()); if (columns.isEmpty() && builder.componentCount() == 0) { // No columns, delete the row cf.delete(new DeletionInfo(params.timestamp, params.localDeletionTime)); } else { if (isRange) { ByteBuffer start = builder.copy().build(); ByteBuffer end = builder.buildAsEndOfRange(); QueryProcessor.validateColumnName(start); // If start is good, end is too cf.addAtom(params.makeRangeTombstone(start, end)); } else { // Delete specific columns if (cfDef.isCompact) { ByteBuffer columnName = builder.build(); QueryProcessor.validateColumnName(columnName); cf.addColumn(params.makeTombstone(columnName)); } else { Iterator<Pair<CFDefinition.Name, Term>> iter = toRemove.iterator(); while (iter.hasNext()) { Pair<CFDefinition.Name, Term> p = iter.next(); CFDefinition.Name column = p.left; if (column.type.isCollection()) { CollectionType validator = (CollectionType) column.type; Term keySelected = p.right; if (keySelected == null) { // Delete the whole collection ByteBuffer start = builder.copy().add(column.name.key).build(); QueryProcessor.validateColumnName(start); ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder; ByteBuffer end = b.add(column.name.key).buildAsEndOfRange(); cf.addAtom(params.makeRangeTombstone(start, end)); } else { builder.add(column.name.key); List<Term> args = Collections.singletonList(keySelected); Operation op; switch (validator.kind) { case LIST: op = ListOperation.DiscardKey(args); break; case SET: op = SetOperation.Discard(args); break; case MAP: op = MapOperation.DiscardKey(keySelected); break; default: throw new InvalidRequestException("Unknown collection type: " + validator.kind); } op.execute( cf, builder, validator, params, group == null ? null : group.getCollection(column.name.key)); } } else { ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder; ByteBuffer columnName = b.add(column.name.key).build(); QueryProcessor.validateColumnName(columnName); cf.addColumn(params.makeTombstone(columnName)); } } } } } return rm; }