From e083c8be27fb5840c57a85d2c401c4725281639d Mon Sep 17 00:00:00 2001 From: Alan Cai Date: Wed, 13 Dec 2023 12:33:26 -0800 Subject: [PATCH] Fix errors from partiql-lang#6 and #33 --- src/environment.adoc | 20 ++++++++--------- src/from.adoc | 46 +++++++++++++++++++-------------------- src/groupby.adoc | 6 ++--- src/orderby.adoc | 4 ++-- src/paths.adoc | 8 +++---- src/pivot.adoc | 2 +- src/predsFunctions.adoc | 4 ---- src/select.adoc | 42 ++++++++++++++++++++--------------- src/subqueryCoercion.adoc | 2 +- src/where.adoc | 2 +- 10 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/environment.adoc b/src/environment.adoc index 4087747..225ffad 100644 --- a/src/environment.adoc +++ b/src/environment.adoc @@ -16,7 +16,7 @@ sfw_query = [ "WITH", query, "AS", variable ], [ "WHERE", expr_query ], [ "GROUP", "BY", expr_query, [ "AS", variable ], { "," expr_query, [ "AS", variable ] }, - "GROUP", "AS", variable + "GROUP", "AS", variable], [ "HAVING", expr_query ], [ [ "OUTER" ], ( "UNION"|"INTERSECT"|"EXCEPT" ), [ "ALL" ] sfw_query ], [ "ORDER", "BY", expr_query, [ "ASC" | "DESC" ], [ order_spec ], @@ -58,15 +58,15 @@ names and the variables of the enclosing queries. A PartiQL query is either an _SFW query_ (i.e. `SELECT-FROM-WHERE`..., (lines 3-16) the grammar of <<#figure:query:bnf>>) or an _expression query_ (also called _simple expression_ in the rest, -<<#figure:query:bnf> lines 17-30) such as a path expression ( -<<#figure:query:bnf> lines 25-30) or a function invocation. Unlike SQL +<<#figure:query:bnf>> lines 17-30) such as a path expression ( +<<#figure:query:bnf>> lines 25-30) or a function invocation. Unlike SQL expressions, which are restricted to outputting scalar and null values, PartiQL expressions output arbitrary PartiQL values, and are fully composable within larger SFW queries and expressions. Indeed, PartiQL allows the top-level query to also be an expression query, not just a SFW query as in SQL. -An PartiQL (sub)query is evaluated within an environment, which provides +A PartiQL (sub)query is evaluated within an environment, which provides variable bindings (as defined next). [[sec:environments-and-bindings]] @@ -213,9 +213,9 @@ stem:[p = <<>>] `FROM mydb.r AS x, mydb.s AS y` + stem:[B_"FROM"^"out" = B_"WHERE"^"in" = ] + stem:[< <] + -stem:[ <>] + -stem:[ <>] + -stem:[ <>] + +stem:[ <>,] + +stem:[ <>,] + +stem:[ <>,] + stem:[ <>] + stem:[> >] @@ -232,7 +232,7 @@ stem:["Result" = < < <<{"foo":3, "bar":1}>> > >] [discrete] ==== SFW query clauses as operators that input/output binding tuples -Similar to SQL semantics, the clauses of an PartiQL SFW query are +Similar to SQL semantics, the clauses of a PartiQL SFW query are evaluated in the following order: `WITH`, `FROM`, `LET`, `WHERE`, `GROUP BY`, `HAVING`, `LETTING` (which is special to PartiQL), `ORDER BY`, `LIMIT`/`OFFSET`, and `SELECT` (or `SELECT VALUE` or `PIVOT`, @@ -344,13 +344,11 @@ Since this is an SQL query and PartiQL is backwards compatible to SQL, it is easy to tell that the `x` in `x.c` resolves to the variable defined by the inner query’s `FROM` clause. -// TODO s/thinner/the inner/ - Technically, this scoping rule is captured by the following handling of binding tuples. The inner `FROM` clause is evaluated with a variables environment stem:[p = <>]; its `x` is the one defined by the outer `FROM`. Then the inner `FROM` clause outputs a binding -stem:[b = <>]; this `x` is defined by thinner `FROM`. Then the +stem:[b = <>]; this `x` is defined by the inner `FROM`. Then the `x.c` is evaluated in the concatenation stem:[p||b] and because `x` appears in both stem:[p] and stem:[b], the concatenation keeps only the `x` of its right argument. Essentially by putting stem:[b] as the diff --git a/src/from.adoc b/src/from.adoc index 46ee963..dce3499 100644 --- a/src/from.adoc +++ b/src/from.adoc @@ -11,7 +11,7 @@ single item (<> and <>). The term "`semantics of the item stem:[f]`" is synonymous to the term "`semantics of a clause with the single item stem:[f]`". In either case, we refer to the specification of the collection of binding -tuples stem:[B^{out}_{\from}] that results from the evaluation of +tuples stem:[B_"FROM"^"out"] that results from the evaluation of "`stem:[f]`". 2. Then the semantics specify how multiple items combine, according to @@ -69,7 +69,7 @@ FROM someOrderedTable AS x AT y outputs the bag of binding tuples: stem:[B_"FROM"^"out" =] stem:[< <] + -stem:[" " << x: {'a':0, 'b':0}, y:0 >> ] + +stem:[" " << x: {'a':0, 'b':0}, y:0 >>, ] + stem:[" " << x: {'a':1, 'b':1}, y:1 >> ] + stem:[ > > ] ==== @@ -281,14 +281,14 @@ The clause: [source%unbreakable, partiql] ---- -FROM UNPIVOT justATuple AS price AT symbol +FROM UNPIVOT justATuple AS price AT sym ---- outputs: stem:[B_"FROM"^"out" =] stem:[< <] + -stem:[ << price: 840.05, symbol: 'amzn' >> ] + -stem:[ << price: 31.06, symbol: 'tdc' >> ] + +stem:[ << price: 840.05, sym: 'amzn' >>, ] + +stem:[ << price: 31.06, sym: 'tdc' >> ] + stem:[ > > ] ==== @@ -471,9 +471,9 @@ keyword, and presumably, one would put the sensible equality condition clause outputs the bag of binding tuples: stem:[B_"FROM"^"out" = < <] + -stem:[ << c: {"'id'": 5, "'name'": "'Joe'"}, o: {"'custId'": 7, "'productId'": 101} >> ] + -stem:[ << c: {"'id'": 5, "'name'": "'Joe'"}, o: {"'custId'": 7, "'productId'": 523} >> ] + -stem:[ << c: {"'id'": 7, "'name'": "'Mary'"}, o: {"'custId'": 7, "'productId'": 101} >> ] + +stem:[ << c: {"'id'": 5, "'name'": "'Joe'"}, o: {"'custId'": 7, "'productId'": 101} >>, ] + +stem:[ << c: {"'id'": 5, "'name'": "'Joe'"}, o: {"'custId'": 7, "'productId'": 523} >>, ] + +stem:[ << c: {"'id'": 7, "'name'": "'Mary'"}, o: {"'custId'": 7, "'productId'": 101} >>, ] + stem:[ << c: {"'id'": 7, "'name'": "'Mary'"}, o: {"'custId'": 7, "'productId'": 523} >> ] + stem:[> >] ==== @@ -497,8 +497,8 @@ Consider the database: stem:[ p_0 = << ] + stem:[ "sensors": \[ ] + -stem:[ {"'readings'": [{"'v'": 1.3}, {"'v'": 2}]}, ] + -stem:[ {"'readings'": [{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}]} ] + +stem:[ {"'readings'": [{"'v'": 1.3}, {"'v'": 2}\]}, ] + +stem:[ {"'readings'": [{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}\]} ] + stem:[ \] ] + stem:[ >> ] @@ -511,11 +511,11 @@ FROM sensors AS s, s.readings AS r ---- stem:[B_"FROM"^"out" = < <] + -stem:[ s: {"'readings'": \[{"'v'": 1.3}, {"'v'": 2}\]}, r: {v:1.3} ] + -stem:[ s: {"'readings'": \[{"'v'": 1.3}, {"'v'": 2}\]}, r: {v:2} ] + -stem:[ s: {"'readings'": \[{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}\]}, r: {"'v'":0.7} ] + -stem:[ s: {"'readings'": \[{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}\]}, r: {"'v'":0.8} ] + -stem:[ s: {"'readings'": \[{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}\]}, r: {"'v'":0.9} ] + +stem:[ << s: {"'readings'": \[{"'v'": 1.3}, {"'v'": 2}\]}, r: {"'v'":1.3} >> ] + +stem:[ << s: {"'readings'": \[{"'v'": 1.3}, {"'v'": 2}\]}, r: {"'v'":2} >> ] + +stem:[ << s: {"'readings'": \[{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}\]}, r: {"'v'":0.7} >> ] + +stem:[ << s: {"'readings'": \[{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}\]}, r: {"'v'":0.8} >> ] + +stem:[ << s: {"'readings'": \[{"'v'": 0.7}, {"'v'": 0.8}, {"'v'": 0.9}\]}, r: {"'v'":0.9} >> ] + stem:[> >] ==== @@ -574,7 +574,7 @@ Consider the database: stem:[ p_0 = << ] + stem:[ "sensors": \[ ] + -stem:[ {"'readings'": \[{"'v'":1.3}, {"'v'":2}\]} ] + +stem:[ {"'readings'": \[{"'v'":1.3}, {"'v'":2}\]}, ] + stem:[ {"'readings'": \[{"'v'":0.7}, {"'v'":0.8}, {"'v'":0.9}\]}, ] + stem:[ {"'readings'": \[\]} ] + stem:[ \] ] + @@ -591,13 +591,13 @@ FROM sensors AS s LEFT CROSS JOIN s.readings AS r ---- stem:[B_"FROM"^"out" = < <] + -stem:[ s: {"'readings'": \[{"'v'":1.3}, {"'v'":2}\]}, r: {"'v'":1.3} ] + -stem:[ s: {"'readings'": \[{"'v'":1.3}, {"'v'":2}\]}, r: {"'v'":2} ] + -stem:[ s: {"'readings'": \[{"'v'":0.7}, {"'v'":0.8}, {"'v'":0.9}\]}, r: {"'v'":0.7} ] + -stem:[ s: {"'readings'": \[{"'v'":0.7}, {"'v'":0.8}, {"'v'":0.9}\]}, r: {"'v'":0.8} ] + -stem:[ s: {"'readings'": \[{"'v'":0.7}, {"'v'":0.8}, {"'v'":0.9}\]}, r: {"'v'":0.9} ] + -stem:[ s: {"'readings'": \[\]}, r: "NULL" ] + -stem:[ >> ] +stem:[ << s: {"'readings'": \[{"'v'":1.3}, {"'v'":2}\]}, r: {"'v'":1.3} >>, ] + +stem:[ << s: {"'readings'": \[{"'v'":1.3}, {"'v'":2}\]}, r: {"'v'":2} >>, ] + +stem:[ << s: {"'readings'": \[{"'v'":0.7}, {"'v'":0.8}, {"'v'":0.9}\]}, r: {"'v'":0.7} >>, ] + +stem:[ << s: {"'readings'": \[{"'v'":0.7}, {"'v'":0.8}, {"'v'":0.9}\]}, r: {"'v'":0.8} >>, ] + +stem:[ << s: {"'readings'": \[{"'v'":0.7}, {"'v'":0.8}, {"'v'":0.9}\]}, r: {"'v'":0.9} >>, ] + +stem:[ << s: {"'readings'": \[\]}, r: "NULL" >> ] + +stem:[ > > ] ==== diff --git a/src/groupby.adoc b/src/groupby.adoc index 056d6b7..b6e155c 100644 --- a/src/groupby.adoc +++ b/src/groupby.adoc @@ -125,7 +125,7 @@ GROUP BY l.sensor AS sensor GROUP AS g Notice, the output binding tuple provides the partitioned input binding tuples in the group variable stem:[g], which can be explicitly utilized in subsequent `HAVING`, `ORDER BY`, and `SELECT` -clauses. Thus, an PartiQL query can perform complex computations on +clauses. Thus, a PartiQL query can perform complex computations on the groups, leading to results of any type (e.g. collections nested within collections). The explicit presence of groups in PartiQL, while more general than SQL, also leads to simpler semantics than those of @@ -565,8 +565,8 @@ written in an SQL compatible way as [source%unbreakable, partiql] ---- SELECT l.sensor AS sensor, - AVG(l.co) AS avg, - COUNT(*) AS count + AVG(l.co) AS "avg", + COUNT(*) AS "count" FROM logs AS l GROUP BY l.sensor ---- diff --git a/src/orderby.adoc b/src/orderby.adoc index 850da83..74b9885 100644 --- a/src/orderby.adoc +++ b/src/orderby.adoc @@ -18,7 +18,7 @@ PartiQL there are no binding tuples (or any tuples at all for that matter) after a `SELECT VALUE` clause. <<#sec:order-by-and-setops>> elaborates on this aspect of PartiQL. -. Unlike SQL, the input of an PartiQL query may also have order, +. Unlike SQL, the input of a PartiQL query may also have order, because it is an array. The user may want to preserve the order of the input into the output. In this case, the `AT` structure in the `FROM` clause (recall, <<#sec:single-item-from>>) can capture the input order @@ -118,7 +118,7 @@ expressions can refer directly to the attributes of those tuples. The complete scoping rules are as follows. When all of the following conditions are satisfied: -. an PartiQL path expression ordering expression stem:[as] appears in +. a PartiQL path expression ordering expression stem:[as] appears in the `ORDER BY` of a `UNION ... ORDER BY` query, where stem:[a] is an identifier and stem:[s] is the potentially empty suffix of the path. diff --git a/src/paths.adoc b/src/paths.adoc index dc6682a..91ef34b 100644 --- a/src/paths.adoc +++ b/src/paths.adoc @@ -180,7 +180,7 @@ appropriate features on how result tuples are constructed (see preserve (when needed) the distinction between absent attribute and null-valued attribute. -For example, the expression ` 'not a tuple'.a ` and the expression +For example, the expression `` 'not a tuple'.a `` and the expression `{'a':1, 'b':2}.noSuchAttribute` evaluate to `MISSING`. The above semantics apply regardless of whether the tuple navigation @@ -202,9 +202,9 @@ the query processor can prove that the path expression is guaranteed to _always_ produce `MISSING`. The extent of error detection is implementation-specific. -For example, in the presence of schema validation, an PartiQL query +For example, in the presence of schema validation, a PartiQL query processor can throw a compile-time error when given the path expression -`{a:1, b:2}.c`. In a more important and common case, an PartiQL implementation can +`{a:1, b:2}.c`. In a more important and common case, a PartiQL implementation can utilize the input data schema to prove that a path expression _always_ returns `MISSING` and thus throw a compile-time error. For example, assume that `sometable` is an SQL table whose schema does not include an attribute `c`. Then, an @@ -216,7 +216,7 @@ the query: SELECT t.a, t.c FROM sometable AS t ---- -Apparently, such an PartiQL implementation is fully compatible with the +Apparently, such a PartiQL implementation is fully compatible with the behavior of an SQL processor. Generally, if a rigid schema is explicitly present, a tuple path navigation error can be caught during compilation time; this is the case in SQL itself, where referring to a non-existent diff --git a/src/pivot.adoc b/src/pivot.adoc index ab06b2f..ae6625f 100644 --- a/src/pivot.adoc +++ b/src/pivot.adoc @@ -32,7 +32,7 @@ collection of tuples. [source%unbreakable, partiql] ---- PIVOT x.v AT x.a -FROM << {'a': 'first', 'v': 'john'}, {'a': 'last', 'v': 'doe'} >> as x +FROM << {'a': 'first', 'v': 'john'}, {'a': 'last', 'v': 'doe'} >> AS x ---- The result is diff --git a/src/predsFunctions.adoc b/src/predsFunctions.adoc index 53a5836..1cfd7db 100644 --- a/src/predsFunctions.adoc +++ b/src/predsFunctions.adoc @@ -150,10 +150,6 @@ The following are false: The following are also false. [source%unbreakable, partiql] ---- -{'a':1, 'b':2} = {'a':1} ----- -[source%unbreakable, partiql] ----- {'a':1, 'b':2} = {'a':1, 'b':null} ---- [source%unbreakable, partiql] diff --git a/src/select.adoc b/src/select.adoc index b0d7e79..22e4c36 100644 --- a/src/select.adoc +++ b/src/select.adoc @@ -294,7 +294,7 @@ The query [source%unbreakable, partiql] ---- SELECT VALUE {'a':v.a, 'b':v.b} -FROM [{'a':1, 'b':1}, {'a':2}] +FROM [{'a':1, 'b':1}, {'a':2}] AS v ---- results into @@ -322,7 +322,7 @@ The query [source%unbreakable, partiql] ---- SELECT VALUE [v.a, v.b] -FROM [{'a':1, 'b':1}, {'a':2}] +FROM [{'a':1, 'b':1}, {'a':2}] AS v ---- results into @@ -355,7 +355,7 @@ The query [source%unbreakable, partiql] ---- SELECT VALUE v.b -FROM [{'a':1, 'b':1}, {'a':2}] +FROM [{'a':1, 'b':1}, {'a':2}] AS v ---- results into @@ -378,7 +378,7 @@ The query [source%unbreakable, partiql] ---- SELECT VALUE <> -FROM [{'a':1, 'b':1}, {'a':2}] +FROM [{'a':1, 'b':1}, {'a':2}] AS v ---- results into @@ -425,7 +425,7 @@ The query: [source%unbreakable, partiql] ---- -PIVOT t.price AT t.symbol +PIVOT t.price AT t."symbol" FROM [{'symbol':'tdc', 'price': 31.52}, {'symbol': 'amzn', 'price': 840.05}] AS t ---- @@ -477,39 +477,43 @@ since `25` is not a legitimate attribute name. The SQL syntax: [source%unbreakable, partiql] +[subs="+normal"] ---- -SELECT e1 AS a1, ..., en AS an +SELECT e~1~ AS a~1~, ..., e~n~ AS a~n~ ---- is syntactic sugar for: [source%unbreakable, partiql] +[subs="+normal"] ---- -SELECT VALUE {'a1':e1, ...., 'an':en} +SELECT VALUE {'a~1~':e~1~, ..., 'a~n~':e~n~} ---- whereas if the attribute name stem:[a_i] is written as an identifier (e.g., `a` or `"a"`) it is replaced by a single-quoted form -stem:[a_1'] (e.g., `'a'`). +stem:['a_1'] (e.g., `'a'`). -When the expression stem:[e_i] is of the form stem:[e_i`.n] (i.e. a +When the expression stem:[e_i] is of the form stem:[e_i.n] (i.e. a path that navigates into tuple attribute stem:[n]), PartiQL follows SQL in allowing the attribute name to be optional. In this case, [source%unbreakable, partiql] +[subs="+normal"] ---- -SELECT ...ei.n... +SELECT ... e~i~.n... ---- is equivalent to [source%unbreakable, partiql] +[subs="+normal"] ---- -SELECT ...ei.n AS n... +SELECT ... e~i~.n AS n... ---- In the case that the expression stem:[e_i] is not of the form -stem:[e_i`.n] the clause: +stem:[e_i.n] the clause: [source%unbreakable, partiql] ---- @@ -600,19 +604,21 @@ stem:[{"'_1'":v_1}] (resp. stem:[{"'_2'":v_3}]. [source%unbreakable, partiql] +[subs="+normal"] ---- -SELECT v1.*, e2 AS a, v3.* +SELECT v~1~.\*, e~2~ AS a, v~3~.* ---- is equivalent to [source%unbreakable, partiql] +[subs="+normal"] ---- SELECT VALUE TUPLEUNION( - CASE WHEN v1 IS TUPLE THEN v1 ELSE {'_1': v1} END, - {'a':e2 }, - CASE WHEN v3 IS TUPLE THEN v3 ELSE {'_2': v3} END + CASE WHEN v~1~ IS TUPLE THEN v~1~ ELSE {'_1': v~1~} END, + {'a':e~2~ }, + CASE WHEN v~3~ IS TUPLE THEN v~3~ ELSE {'_2': v~3~} END ) ---- @@ -725,10 +731,10 @@ The result is [source%unbreakable, partiql] ---- -[ +<< {'co':0.7, 'co2':0.5}, {'co':0.4, 'co2':1.3} -] +>> ---- Intuitively, the `UNPIVOT` turns every instance of the tuple `t` into diff --git a/src/subqueryCoercion.adoc b/src/subqueryCoercion.adoc index 925f39d..7fb76e1 100644 --- a/src/subqueryCoercion.adoc +++ b/src/subqueryCoercion.adoc @@ -11,7 +11,7 @@ following cases replicate SQL’s coercing behavior and analyze in which cases the result of a subquery coerces into scalar and in which cases they coerce into arrays. -An PartiQL extension with respect to SQL is that, in the permissive +A PartiQL extension with respect to SQL is that, in the permissive mode, subqueries that fail to coerce to the required type (scalar or tuple) still run, as opposed to failing. They simply omit from the results the data that correspond to the coercion failures. diff --git a/src/where.adoc b/src/where.adoc index 5c5dfd5..ff7aaca 100644 --- a/src/where.adoc +++ b/src/where.adoc @@ -28,7 +28,7 @@ The result of [source%unbreakable, partiql] ---- -SELECT VALUES v.a +SELECT VALUE v.a FROM [{'a':1, 'b':true}, {'a':2, 'b':null}, {'a':3}] v WHERE v.b ----