dcapwell commented on code in PR #1962:
URL: https://github.com/apache/cassandra/pull/1962#discussion_r1039878746


##########
src/java/org/apache/cassandra/cql3/transactions/SelectReferenceSource.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.transactions;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.selection.Selection;
+import org.apache.cassandra.cql3.statements.SelectStatement;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+
+import static 
org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
+
+public class SelectReferenceSource implements RowDataReference.ReferenceSource
+{
+    public static final String COLUMN_NOT_IN_SELECT_MESSAGE = "%s refererences 
a column not included in the select";
+    private final SelectStatement statement;
+    private final Set<ColumnMetadata> selectedColumns;
+    private final TableMetadata metadata;
+
+    public SelectReferenceSource(SelectStatement statement)
+    {
+        this.statement = statement;
+        this.metadata = statement.table;
+        Selection selection = statement.getSelection();
+        selectedColumns = new HashSet<>(selection.getColumns());
+    }
+
+    @Override
+    public boolean isPointSelect()
+    {
+        return 
statement.getRestrictions().hasAllPKColumnsRestrictedByEqualities()
+               || statement.getLimit(QueryOptions.DEFAULT) == 1;

Review Comment:
   yeah, this is an issue; the following test fails
   
   ```
   @Test
       public void test() throws Exception
       {
           test(cluster -> {
              String cql = "BEGIN TRANSACTION\n" +
                           "LET row1 = (SELECT * FROM "+currentTable+" WHERE 
k=0 LIMIT ?);\n" +
                           "SELECT row1.v;\n" +
                           "COMMIT TRANSACTION";
   // I put rand value for return; I just wanted to hit this statement
               assertRowEqualsWithPreemptedRetry(cluster, new Object[] { 1 }, 
cql, 1);
           });
       }
   ```
   
   ```
   java.lang.IndexOutOfBoundsException: Index: 0
   
        at java.util.Collections$EmptyList.get(Collections.java:4456)
        at 
org.apache.cassandra.cql3.Constants$Marker.bindAndGet(Constants.java:425)
        at 
org.apache.cassandra.cql3.statements.SelectStatement.getLimit(SelectStatement.java:840)
        at 
org.apache.cassandra.cql3.statements.SelectStatement.getLimit(SelectStatement.java:819)
        at 
org.apache.cassandra.cql3.statements.TransactionStatement$Parsed.checkAtMostOneRowSpecified(TransactionStatement.java:434)
        at 
org.apache.cassandra.cql3.statements.TransactionStatement$Parsed.prepare(TransactionStatement.java:380)
        at 
org.apache.cassandra.cql3.QueryProcessor.getStatement(QueryProcessor.java:861)
   ```



##########
src/java/org/apache/cassandra/cql3/transactions/ReferenceOperation.java:
##########
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.transactions;
+
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.FieldIdentifier;
+import org.apache.cassandra.cql3.Lists;
+import org.apache.cassandra.cql3.Maps;
+import org.apache.cassandra.cql3.Operation;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UserTypes;
+import org.apache.cassandra.cql3.VariableSpecifications;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.db.marshal.MapType;
+import org.apache.cassandra.db.marshal.SetType;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.db.rows.CellPath;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+import org.apache.cassandra.service.accord.txn.TxnReferenceOperation;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+import static 
org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
+import static org.apache.cassandra.db.marshal.CollectionType.Kind.MAP;
+import static 
org.apache.cassandra.schema.TableMetadata.UNDEFINED_COLUMN_NAME_MESSAGE;
+
+public class ReferenceOperation
+{
+    private final ColumnMetadata receiver;
+    private final TxnReferenceOperation.Kind kind;
+    private final FieldIdentifier field;
+    private final Term key;
+    private final ReferenceValue value;
+
+    public ReferenceOperation(ColumnMetadata receiver, 
TxnReferenceOperation.Kind kind, Term key, FieldIdentifier field, 
ReferenceValue value)
+    {
+        this.receiver = receiver;
+        this.kind = kind;
+        this.key = key;
+        this.field = field;
+        this.value = value;
+    }
+
+    /**
+     * Creates a {@link ReferenceOperation} from the given {@link  Operation} 
for the purpose of defering execution
+     * within a transaction. When the language sees an Operation using a 
reference one is created already, but for cases
+     * that needs to defer execution (such as when {@link 
Operation#requiresRead()} is true), this method can be used.
+     */
+    public static ReferenceOperation create(Operation operation)
+    {
+        TxnReferenceOperation.Kind kind = 
TxnReferenceOperation.Kind.from(operation);
+        ColumnMetadata receiver = operation.column;
+        ReferenceValue value = new ReferenceValue.Constant(operation.term());
+
+        Term key = extractKeyOrIndex(operation);
+        FieldIdentifier field = extractField(operation);
+        return new ReferenceOperation(receiver, kind, key, field, value);
+    }
+
+    public boolean requiresRead()
+    {
+        // TODO: Find a better way than delegating to the operation?
+        return kind.toOperation(receiver, null, null, null).requiresRead();
+    }
+
+    public TxnReferenceOperation bindAndGet(QueryOptions options)
+    {
+        return new TxnReferenceOperation(kind,
+                                         receiver,
+                                         key != null ? key.bindAndGet(options) 
: null,
+                                         field != null ? field.bytes : null,
+                                         value.bindAndGet(options));
+    }
+
+    public static class Raw
+    {
+        private final Operation.RawUpdate rawUpdate;
+        public final ColumnIdentifier column;
+        private final ReferenceValue.Raw value;
+
+        public Raw(Operation.RawUpdate rawUpdate, ColumnIdentifier column, 
ReferenceValue.Raw value)
+        {
+            this.rawUpdate = rawUpdate;
+            this.column = column;
+            this.value = value;
+        }
+
+        public ReferenceOperation prepare(TableMetadata metadata, 
VariableSpecifications bindVariables)
+        {
+            ColumnMetadata receiver = metadata.getColumn(column);
+            checkTrue(receiver != null, UNDEFINED_COLUMN_NAME_MESSAGE, 
column.toCQLString(), metadata);
+            AbstractType<?> type = receiver.type;
+
+            Operation operation = rawUpdate.prepare(metadata, receiver, true);
+            TxnReferenceOperation.Kind kind = 
TxnReferenceOperation.Kind.from(operation);
+
+            Term key = extractKeyOrIndex(operation);
+
+            if (type.isCollection())
+            {
+                CollectionType<?> collectionType = (CollectionType<?>) type;
+
+                // The value for a map subtraction is actually a set (see 
Operation.Substraction)
+                if (kind == TxnReferenceOperation.Kind.SetDiscarder)
+                    if (collectionType.kind == MAP)
+                        receiver = 
receiver.withNewType(SetType.getInstance(((MapType<?, ?>) type).getKeysType(), 
true));
+
+                if (kind == TxnReferenceOperation.Kind.SetterByIndex || kind 
== TxnReferenceOperation.Kind.SetterByKey)
+                    receiver = 
receiver.withNewType(collectionType.valueComparator());
+            }
+
+            FieldIdentifier field = extractField(operation);
+
+            if (type.isUDT())
+            {
+                if (kind == TxnReferenceOperation.Kind.SetterByField)
+                {
+                    @SuppressWarnings("ConstantConditions") UserType userType 
= (UserType) type;
+                    CellPath fieldPath = userType.cellPathForField(field);
+                    int i = ByteBufferUtil.getUnsignedShort(fieldPath.get(0), 
0);
+                    receiver = receiver.withNewType(userType.fieldType(i));
+                }
+            }
+
+            return new ReferenceOperation(receiver, kind, key, field, 
value.prepare(receiver, bindVariables));
+        }
+    }

Review Comment:
   this is similar but different from `create` and wondering why... we prepare 
to get the Operation, then extract what we need from the Operation... why are 
these 2 methods so different?



##########
src/java/org/apache/cassandra/cql3/transactions/SelectReferenceSource.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.transactions;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.selection.Selection;
+import org.apache.cassandra.cql3.statements.SelectStatement;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+
+import static 
org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
+
+public class SelectReferenceSource implements RowDataReference.ReferenceSource
+{
+    public static final String COLUMN_NOT_IN_SELECT_MESSAGE = "%s refererences 
a column not included in the select";
+    private final SelectStatement statement;
+    private final Set<ColumnMetadata> selectedColumns;
+    private final TableMetadata metadata;
+
+    public SelectReferenceSource(SelectStatement statement)
+    {
+        this.statement = statement;
+        this.metadata = statement.table;
+        Selection selection = statement.getSelection();
+        selectedColumns = new HashSet<>(selection.getColumns());
+    }
+
+    @Override
+    public boolean isPointSelect()
+    {
+        return 
statement.getRestrictions().hasAllPKColumnsRestrictedByEqualities()
+               || statement.getLimit(QueryOptions.DEFAULT) == 1;

Review Comment:
   since this doesn't include the real QueryOptions doesn't this mean `LIMIT ?` 
will fail?



##########
src/java/org/apache/cassandra/cql3/transactions/SelectReferenceSource.java:
##########
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.transactions;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.selection.Selection;
+import org.apache.cassandra.cql3.statements.SelectStatement;
+import org.apache.cassandra.schema.ColumnMetadata;
+import org.apache.cassandra.schema.TableMetadata;
+
+import static 
org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
+
+public class SelectReferenceSource implements RowDataReference.ReferenceSource
+{
+    public static final String COLUMN_NOT_IN_SELECT_MESSAGE = "%s refererences 
a column not included in the select";
+    private final SelectStatement statement;
+    private final Set<ColumnMetadata> selectedColumns;
+    private final TableMetadata metadata;
+
+    public SelectReferenceSource(SelectStatement statement)
+    {
+        this.statement = statement;
+        this.metadata = statement.table;
+        Selection selection = statement.getSelection();
+        selectedColumns = new HashSet<>(selection.getColumns());
+    }
+
+    @Override
+    public boolean isPointSelect()
+    {
+        return 
statement.getRestrictions().hasAllPKColumnsRestrictedByEqualities()
+               || statement.getLimit(QueryOptions.DEFAULT) == 1;

Review Comment:
   `org.apache.cassandra.cql3.statements.TransactionStatement#execute` and 
`org.apache.cassandra.cql3.statements.TransactionStatement#executeLocally` both 
have access; we just can't check this in `prepare` =(



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to