...and one more option...

5.) Introduce tuple assignments, removing all ambiguity around row vs.
column operations.

BEGIN TRANSACTION
  LET row1 = * FROM ks.tbl WHERE k=0 AND c=0; <-- * selects all columns
  LET row2 = (v) FROM ks.tbl WHERE k=1 AND c=0;
  SELECT row1.v, row2.v
  IF row1 IS NULL AND row2.v = 3 THEN
    INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1);
  END IF
COMMIT TRANSACTION



On Thu, Aug 11, 2022 at 12:55 PM Caleb Rackliffe <calebrackli...@gmail.com>
wrote:

> via Benedict, here is a 4th option:
>
> 4.) Similar to #2, but don't rely on the key element being NULL.
>
> If the read returns no result, x effectively becomes NULL. Otherwise, it
> remains true/NOT NULL.
>
> BEGIN TRANSACTION
>   LET x = true FROM ks.tbl WHERE k=0 AND c=0;
>   LET row2_v = v FROM ks.tbl WHERE k=1 AND c=0;
>   SELECT x, row2_v
>   IF x IS NULL AND row2_v = 3 THEN
>     INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1);
>   END IF
> COMMIT TRANSACTION
>
> On Thu, Aug 11, 2022 at 12:12 PM Caleb Rackliffe <calebrackli...@gmail.com>
> wrote:
>
>> Hello again everyone!
>>
>> I've been working on a prototype
>> <https://issues.apache.org/jira/browse/CASSANDRA-17719> in
>> CASSANDRA-17719 for a grammar that roughly corresponds to what we've agreed
>> on in this thread. One thing that isn't immediately obvious to me is how
>> the LET syntax handles cases where we want to check for the plain existence
>> of a row in IF. For example, in this hybrid of the originally proposed
>> syntax and something more like what we've agreed on (and the RETURNING just
>> to distinguish between that and SELECT), this could be pretty
>> straightforward:
>>
>> BEGIN TRANSACTION
>>   SELECT v FROM ks.tbl WHERE k=0 AND c=0 AS row1;
>>   SELECT v FROM ks.tbl WHERE k=1 AND c=0 AS row2;
>>   RETURNING row1.v, row2.v
>>   IF row1 NOT EXISTS AND row2.v = 3 THEN
>>     INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1);
>>   END IF
>> COMMIT TRANSACTION
>>
>> The NOT EXISTS operator has row1 to work with. One the other hand, w/ the
>> LET syntax and no naming of reads, it's not clear what the best solution
>> would be. Here are a few possibilities:
>>
>> 1.) Provide a few built-in functions that operate on a whole result row.
>> If we assume a SQL style IS NULL and IS NOT NULL (see my last post here)
>> for operations on particular columns, this probably eliminates the need for
>> EXISTS/NOT EXISTS as well.
>>
>> BEGIN TRANSACTION
>>   LET row1_missing = notExists() FROM ks.tbl WHERE k=0 AND c=0;
>>   LET row2_v = v FROM ks.tbl WHERE k=1 AND c=0;
>>   SELECT row1_missing, row2_v
>>   IF row1_missing AND row2_v = 3 THEN
>>     INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1);
>>   END IF
>> COMMIT TRANSACTION
>>
>> 2.) Assign and check the first primary key element to determine whether
>> the row exists.
>>
>> BEGIN TRANSACTION
>>   LET row1_k = k FROM ks.tbl WHERE k=0 AND c=0;
>>   LET row2_v = v FROM ks.tbl WHERE k=1 AND c=0;
>>   SELECT row1_k, row2_v
>>   IF row1_k IS NULL AND row2_v = 3 THEN
>>     INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1);
>>   END IF
>> COMMIT TRANSACTION
>>
>> 3.) Reconsider the LET concept toward something that allows us to
>> explicitly name our reads again.
>>
>> BEGIN TRANSACTION
>>   WITH (SELECT v FROM ks.tbl WHERE k=0 AND c=0) AS row1;
>>   WITH (SELECT v FROM ks.tbl WHERE k=1 AND c=0) AS row2;
>>   SELECT row1.v, row2.v
>>   IF row1 NOT EXISTS AND row2.v = 3 THEN
>>     INSERT INTO ks.tbl (k, c, v) VALUES (0, 0, 1);
>>   END IF
>> COMMIT TRANSACTION
>>
>> I don't have a strong affinity for any of these, although #1 seems the
>> most awkward.
>>
>> Does anyone have any other alternatives? Preference for one of the above
>> options?
>>
>> Thanks!
>>
>> On Fri, Jul 22, 2022 at 11:21 AM Caleb Rackliffe <
>> calebrackli...@gmail.com> wrote:
>>
>>> Avi brought up an interesting point around NULLness checking in
>>> CASSANDRA-17762 <https://issues.apache.org/jira/browse/CASSANDRA-17762>
>>> ...
>>>
>>> In SQL, any comparison with NULL is NULL, which is interpreted as FALSE
>>>> in a condition. To test for NULLness, you use IS NULL or IS NOT NULL. But
>>>> LWT uses IF col = NULL as a NULLness test. This is likely to confuse people
>>>> coming from SQL and hamper attempts to extend the dialect.
>>>
>>>
>>> We can leave that Jira open to address what to do in the legacy LWT
>>> case, but I'd support a SQL-congruent syntax here (IS NULL or IS NOT
>>> NULL), where we have something closer to a blank slate.
>>>
>>> Thoughts?
>>>
>>> On Thu, Jun 30, 2022 at 6:25 PM Abe Ratnofsky <a...@aber.io> wrote:
>>>
>>>> The new syntax looks great, and I’m really excited to see this coming
>>>> together.
>>>>
>>>> One piece of feedback on the proposed syntax is around the use of “=“
>>>> as a declaration in addition to its current use as an equality operator in
>>>> a WHERE clause and an assignment operator in an UPDATE:
>>>>
>>>> BEGIN TRANSACTION
>>>>   LET car_miles = miles_driven, car_is_running = is_running FROM cars
>>>> WHERE model=’pinto’
>>>>   LET user_miles = miles_driven FROM users WHERE name=’blake’
>>>>   SELECT something else from some other table
>>>>   IF NOT car_is_running THEN ABORT
>>>>   UPDATE users SET miles_driven = user_miles + 30 WHERE name='blake';
>>>>   UPDATE cars SET miles_driven = car_miles + 30 WHERE model='pinto';
>>>> COMMIT TRANSACTION
>>>>
>>>> This is supported in languages like PL/pgSQL, but in a normal SQL query
>>>> kind of local declaration is often expressed as an alias (SELECT col AS
>>>> new_col), subquery alias (SELECT col) t, or common table expression (WITH t
>>>> AS (SELECT col)).
>>>>
>>>> Here’s an example of an alternative to the proposed syntax that I’d
>>>> find more readable:
>>>>
>>>> BEGIN TRANSACTION
>>>>   WITH car_miles, car_is_running AS (SELECT miles_driven, is_running
>>>> FROM cars WHERE model=’pinto’),
>>>>   user_miles AS (SELECT miles_driven FROM users WHERE name=’blake’)
>>>>   IF NOT car_is_running THEN ABORT
>>>>   UPDATE users SET miles_driven = user_miles + 30 WHERE name='blake';
>>>>   UPDATE cars SET miles_driven = car_miles + 30 WHERE model='pinto';
>>>> COMMIT TRANSACTION
>>>>
>>>> There’s also the option of naming the transaction like a subquery, and
>>>> supporting LET via AS (this one I’m less sure about but wanted to propose
>>>> anyway):
>>>>
>>>> BEGIN TRANSACTION t1
>>>>   SELECT miles_driven AS t1.car_miles, is_running AS t1.car_is_running
>>>> FROM cars WHERE model=’pinto’;
>>>>   SELECT miles_driven AS t1.user_miles FROM users WHERE name=’blake’;
>>>>   IF NOT car_is_running THEN ABORT
>>>>   UPDATE users SET miles_driven = user_miles + 30 WHERE name='blake';
>>>>   UPDATE cars SET miles_driven = car_miles + 30 WHERE model='pinto';
>>>> COMMIT TRANSACTION
>>>>
>>>> This also has the benefit of resolving ambiguity in case of naming
>>>> conflicts with existing (or future) column names.
>>>>
>>>> --
>>>> Abe
>>>>
>>>

Reply via email to