Skip to content

Commit bc61792

Browse files
authored
Do not cast SQL array to jsonb in ExtendedPostgresSqlDialect (#1439)
Also add `pg-arrays` test usecase
1 parent 02c9d3d commit bc61792

File tree

17 files changed

+545
-29
lines changed

17 files changed

+545
-29
lines changed

sqrl-planner/src/main/java/com/datasqrl/calcite/dialect/ExtendedPostgresSqlDialect.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.calcite.sql.SqlWriter;
3535
import org.apache.calcite.sql.dialect.PostgresqlSqlDialect;
3636
import org.apache.calcite.sql.parser.SqlParserPos;
37+
import org.apache.calcite.sql.type.ArraySqlType;
3738
import org.apache.calcite.sql.type.SqlTypeName;
3839
import org.apache.calcite.sql.validate.SqlConformance;
3940
import org.apache.flink.table.planner.plan.schema.RawRelDataType;
@@ -71,8 +72,14 @@ public SqlConformance getConformance() {
7172
@Override
7273
public SqlDataTypeSpec getCastSpec(RelDataType type) {
7374
String castSpec;
75+
7476
if (type.getComponentType() instanceof RelRecordType) {
7577
castSpec = "jsonb";
78+
79+
} else if (type instanceof ArraySqlType) {
80+
var componentSpec = getCastSpec(type.getComponentType());
81+
castSpec = componentSpec + " ARRAY";
82+
7683
} else if (type instanceof RawRelDataType rawRelDataType) {
7784
Class<?> originatingClass = rawRelDataType.getRawType().getOriginatingClass();
7885
if (originatingClass.equals(FlinkVectorType.class)) {
@@ -106,9 +113,6 @@ public SqlDataTypeSpec getCastSpec(RelDataType type) {
106113
case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
107114
castSpec = "TIMESTAMP WITH TIME ZONE";
108115
break;
109-
case ARRAY:
110-
castSpec = "jsonb";
111-
break;
112116
case BINARY:
113117
case VARBINARY:
114118
castSpec = "BYTEA";

sqrl-planner/src/main/java/com/datasqrl/function/builtinflink/ArrayContainsSqlTranslation.java

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
import com.datasqrl.function.translations.PostgresSqlTranslation;
2121
import com.datasqrl.function.translations.SqlTranslation;
2222
import com.google.auto.service.AutoService;
23-
import org.apache.calcite.sql.SqlBasicCall;
2423
import org.apache.calcite.sql.SqlCall;
25-
import org.apache.calcite.sql.SqlNode;
2624
import org.apache.calcite.sql.SqlWriter;
2725
import org.apache.calcite.sql.parser.SqlParserPos;
2826
import org.apache.flink.table.functions.BuiltInFunctionDefinitions;
@@ -36,24 +34,11 @@ public ArrayContainsSqlTranslation() {
3634

3735
@Override
3836
public void unparse(SqlCall call, SqlWriter writer, int leftPrec, int rightPrec) {
39-
var rawArray = call.getOperandList().get(0);
37+
var array = call.getOperandList().get(0);
4038
var value = call.getOperandList().get(1);
4139

42-
var array = unwrapCast(rawArray);
43-
4440
// Emit: value = ANY(array)
4541
PgSpecificOperatorTable.EqualsAny.createCall(SqlParserPos.ZERO, value, array)
4642
.unparse(writer, leftPrec, rightPrec);
4743
}
48-
49-
// FIXME: Remove unwrapCast method
50-
private SqlNode unwrapCast(SqlNode node) {
51-
if (node instanceof SqlBasicCall) {
52-
SqlBasicCall call = (SqlBasicCall) node;
53-
if (call.getOperator().getName().equalsIgnoreCase("CAST")) {
54-
return call.getOperandList().get(0);
55-
}
56-
}
57-
return node;
58-
}
5944
}

sqrl-testing/sqrl-integration-tests/src/test/java/com/datasqrl/FullUseCaseIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class FullUseCaseIT extends AbstractFullUseCaseTest {
6565
@Disabled("Intended for manual usage")
6666
@Test
6767
void specificUseCase() {
68-
var pkg = USE_CASES.resolve("repository").resolve("package.json");
68+
var pkg = USE_CASES.resolve("pg-arrays").resolve("package.json");
6969

7070
var param = new UseCaseParam(pkg);
7171
fullUseCaseTest(param);

sqrl-testing/sqrl-integration-tests/src/test/java/com/datasqrl/UseCaseCompileTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ public UseCaseFiles() {
5454
@ArgumentsSource(UseCaseFiles.class)
5555
@Disabled
5656
void runTestCaseByName(Path script, Path graphQlFile, Path packageFile) {
57-
assumeTrue(
58-
script.toString().endsWith("minimalFlink.sqrl"), "Not the test marked for execution.");
57+
assumeTrue(script.toString().endsWith("pg-arrays.sqrl"), "Not the test marked for execution.");
5958

6059
super.testUsecase(script, graphQlFile, packageFile);
6160
}

sqrl-testing/sqrl-integration-tests/src/test/resources/snapshots/com/datasqrl/DAGPlannerTest/functionParameterTest.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ INSERT INTO `default_catalog`.`default_database`.`CustomerByNothing_2`
351351
],
352352
"query" : {
353353
"type" : "SqlQuery",
354-
"sql" : "SELECT *\nFROM \"Customer_1\"\nWHERE (\"customerid\" = ANY ($1))",
354+
"sql" : "SELECT *\nFROM \"Customer_1\"\nWHERE (\"customerid\" = ANY (CAST($1 AS BIGINT ARRAY)))",
355355
"parameters" : [
356356
{
357357
"type" : "arg",

sqrl-testing/sqrl-integration-tests/src/test/resources/snapshots/com/datasqrl/UseCaseCompileTest/jwt-authorized--package.txt

Lines changed: 176 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,40 @@ SQL: CREATE VIEW AuthMyTableValues AS
3737
WHERE array_contains(cast(? as ARRAY<BIGINT>), t.val)
3838
ORDER BY t.val ASC;
3939

40+
=== AuthStringMyTableValues
41+
ID: default_catalog.default_database.AuthStringMyTableValues
42+
Type: query
43+
Stage: postgres
44+
Inputs: default_catalog.default_database.MyStringTable
45+
Annotations:
46+
- parameters: vals
47+
- base-table: MyStringTable
48+
Plan:
49+
LogicalSort(sort0=[$0], dir0=[ASC-nulls-first])
50+
LogicalProject(val=[$0])
51+
LogicalFilter(condition=[array_contains(CAST(?0):VARCHAR(2147483647) CHARACTER SET "UTF-16LE" ARRAY, CAST($0):VARCHAR(2147483647) CHARACTER SET "UTF-16LE" NOT NULL)])
52+
LogicalTableScan(table=[[default_catalog, default_database, MyStringTable]])
53+
SQL: CREATE VIEW AuthStringMyTableValues AS
54+
SELECT t.*
55+
FROM MyStringTable t
56+
WHERE array_contains(CAST(? AS ARRAY<STRING>), CAST(t.val AS STRING))
57+
ORDER BY t.val ASC;
58+
59+
=== MyStringTable
60+
ID: default_catalog.default_database.MyStringTable
61+
Type: state
62+
Stage: flink
63+
Annotations:
64+
- sort: [0 ASC-nulls-first]
65+
Primary Key: val
66+
Timestamp : -
67+
Schema:
68+
- val: CHAR(1) CHARACTER SET "UTF-16LE" NOT NULL
69+
Plan:
70+
LogicalProject(val=[$0])
71+
LogicalValues(tuples=[[{ 'a' }, { 'b' }, { 'c' }, { 'd' }]])
72+
SQL: CREATE VIEW MyStringTable AS SELECT val FROM (VALUES 'a', 'b', 'c', 'd') AS t(val) ORDER BY val;
73+
4074
=== MyTable
4175
ID: default_catalog.default_database.MyTable
4276
Type: state
@@ -68,11 +102,33 @@ FROM (VALUES ROW(1),
68102
ROW(8),
69103
ROW(9),
70104
ROW(10)) AS `t` (`val`);
105+
CREATE VIEW `MyStringTable`
106+
AS
107+
SELECT `val`
108+
FROM (VALUES ROW('a'),
109+
ROW('b'),
110+
ROW('c'),
111+
ROW('d')) AS `t` (`val`);
71112
CREATE VIEW `MyTableTest`
72113
AS
73114
SELECT *
74115
FROM `MyTable`;
75-
CREATE TABLE `MyTable_1` (
116+
CREATE VIEW `MyStringTableTest`
117+
AS
118+
SELECT *
119+
FROM `MyStringTable`;
120+
CREATE TABLE `MyStringTable_1` (
121+
`val` CHAR(1) CHARACTER SET `UTF-16LE` NOT NULL,
122+
PRIMARY KEY (`val`) NOT ENFORCED
123+
) WITH (
124+
'connector' = 'jdbc-sqrl',
125+
'driver' = 'org.postgresql.Driver',
126+
'password' = '${POSTGRES_PASSWORD}',
127+
'table-name' = 'MyStringTable',
128+
'url' = 'jdbc:postgresql://${POSTGRES_AUTHORITY}',
129+
'username' = '${POSTGRES_USERNAME}'
130+
);
131+
CREATE TABLE `MyTable_2` (
76132
`val` INTEGER NOT NULL,
77133
PRIMARY KEY (`val`) NOT ENFORCED
78134
) WITH (
@@ -84,24 +140,53 @@ CREATE TABLE `MyTable_1` (
84140
'username' = '${POSTGRES_USERNAME}'
85141
);
86142
EXECUTE STATEMENT SET BEGIN
87-
INSERT INTO `default_catalog`.`default_database`.`MyTable_1`
143+
INSERT INTO `default_catalog`.`default_database`.`MyStringTable_1`
88144
(SELECT *
89-
FROM `default_catalog`.`default_database`.`MyTable`)
145+
FROM `default_catalog`.`default_database`.`MyStringTable`)
90146
;
91-
END
147+
INSERT INTO `default_catalog`.`default_database`.`MyTable_2`
148+
(SELECT *
149+
FROM `default_catalog`.`default_database`.`MyTable`)
150+
;
151+
END
92152
>>>kafka.json
93153
{
94154
"topics" : [ ],
95155
"testRunnerTopics" : [ ]
96156
}
97157
>>>postgres-schema.sql
158+
CREATE TABLE IF NOT EXISTS "MyStringTable" ("val" TEXT NOT NULL , PRIMARY KEY ("val"));
98159
CREATE TABLE IF NOT EXISTS "MyTable" ("val" INTEGER NOT NULL , PRIMARY KEY ("val"))
99160
>>>postgres-views.sql
100161

101162
>>>vertx.json
102163
{
103164
"model" : {
104165
"queries" : [
166+
{
167+
"type" : "args",
168+
"parentType" : "Query",
169+
"fieldName" : "MyStringTable",
170+
"exec" : {
171+
"arguments" : [
172+
{
173+
"type" : "variable",
174+
"path" : "offset"
175+
},
176+
{
177+
"type" : "variable",
178+
"path" : "limit"
179+
}
180+
],
181+
"query" : {
182+
"type" : "SqlQuery",
183+
"sql" : "SELECT *\nFROM (SELECT \"val\"\n FROM \"MyStringTable\"\n ORDER BY \"val\" NULLS FIRST) AS \"t\"",
184+
"parameters" : [ ],
185+
"pagination" : "LIMIT_AND_OFFSET",
186+
"database" : "POSTGRES"
187+
}
188+
}
189+
},
105190
{
106191
"type" : "args",
107192
"parentType" : "Query",
@@ -176,7 +261,40 @@ CREATE TABLE IF NOT EXISTS "MyTable" ("val" INTEGER NOT NULL , PRIMARY KEY ("val
176261
],
177262
"query" : {
178263
"type" : "SqlQuery",
179-
"sql" : "SELECT *\nFROM (SELECT \"val\"\n FROM \"MyTable\"\n ORDER BY \"val\" NULLS FIRST) AS \"t\"\nWHERE (CAST(\"val\" AS BIGINT) = ANY ($1))\nORDER BY \"val\" NULLS FIRST",
264+
"sql" : "SELECT *\nFROM (SELECT \"val\"\n FROM \"MyTable\"\n ORDER BY \"val\" NULLS FIRST) AS \"t\"\nWHERE (CAST(\"val\" AS BIGINT) = ANY (CAST($1 AS BIGINT ARRAY)))\nORDER BY \"val\" NULLS FIRST",
265+
"parameters" : [
266+
{
267+
"type" : "metadata",
268+
"metadata" : {
269+
"metadataType" : "AUTH",
270+
"name" : "values",
271+
"isRequired" : true
272+
}
273+
}
274+
],
275+
"pagination" : "LIMIT_AND_OFFSET",
276+
"database" : "POSTGRES"
277+
}
278+
}
279+
},
280+
{
281+
"type" : "args",
282+
"parentType" : "Query",
283+
"fieldName" : "AuthStringMyTableValues",
284+
"exec" : {
285+
"arguments" : [
286+
{
287+
"type" : "variable",
288+
"path" : "offset"
289+
},
290+
{
291+
"type" : "variable",
292+
"path" : "limit"
293+
}
294+
],
295+
"query" : {
296+
"type" : "SqlQuery",
297+
"sql" : "SELECT *\nFROM (SELECT \"val\"\n FROM \"MyStringTable\"\n ORDER BY \"val\" NULLS FIRST) AS \"t\"\nWHERE (CAST(\"val\" AS TEXT) = ANY (CAST($1 AS TEXT ARRAY)))\nORDER BY \"val\" NULLS FIRST",
180298
"parameters" : [
181299
{
182300
"type" : "metadata",
@@ -196,6 +314,32 @@ CREATE TABLE IF NOT EXISTS "MyTable" ("val" INTEGER NOT NULL , PRIMARY KEY ("val
196314
"mutations" : [ ],
197315
"subscriptions" : [ ],
198316
"operations" : [
317+
{
318+
"function" : {
319+
"name" : "GetMyStringTable",
320+
"parameters" : {
321+
"type" : "object",
322+
"properties" : {
323+
"offset" : {
324+
"type" : "integer"
325+
},
326+
"limit" : {
327+
"type" : "integer"
328+
}
329+
},
330+
"required" : [ ]
331+
}
332+
},
333+
"format" : "JSON",
334+
"apiQuery" : {
335+
"query" : "query MyStringTable($limit: Int = 10, $offset: Int = 0) {\nMyStringTable(limit: $limit, offset: $offset) {\nval\n}\n\n}",
336+
"queryName" : "MyStringTable",
337+
"operationType" : "QUERY"
338+
},
339+
"mcpMethod" : "TOOL",
340+
"restMethod" : "GET",
341+
"uriTemplate" : "queries/MyStringTable{?offset,limit}"
342+
},
199343
{
200344
"function" : {
201345
"name" : "GetMyTable",
@@ -273,11 +417,37 @@ CREATE TABLE IF NOT EXISTS "MyTable" ("val" INTEGER NOT NULL , PRIMARY KEY ("val
273417
"mcpMethod" : "TOOL",
274418
"restMethod" : "GET",
275419
"uriTemplate" : "queries/AuthMyTableValues{?offset,limit}"
420+
},
421+
{
422+
"function" : {
423+
"name" : "GetAuthStringMyTableValues",
424+
"parameters" : {
425+
"type" : "object",
426+
"properties" : {
427+
"offset" : {
428+
"type" : "integer"
429+
},
430+
"limit" : {
431+
"type" : "integer"
432+
}
433+
},
434+
"required" : [ ]
435+
}
436+
},
437+
"format" : "JSON",
438+
"apiQuery" : {
439+
"query" : "query AuthStringMyTableValues($limit: Int = 10, $offset: Int = 0) {\nAuthStringMyTableValues(limit: $limit, offset: $offset) {\nval\n}\n\n}",
440+
"queryName" : "AuthStringMyTableValues",
441+
"operationType" : "QUERY"
442+
},
443+
"mcpMethod" : "TOOL",
444+
"restMethod" : "GET",
445+
"uriTemplate" : "queries/AuthStringMyTableValues{?offset,limit}"
276446
}
277447
],
278448
"schema" : {
279449
"type" : "string",
280-
"schema" : "\"An RFC-3339 compliant Full Date Scalar\"\nscalar Date\n\n\"A slightly refined version of RFC-3339 compliant DateTime Scalar\"\nscalar DateTime\n\n\"A JSON scalar\"\nscalar JSON\n\n\"24-hour clock time value string in the format `hh:mm:ss` or `hh:mm:ss.sss`.\"\nscalar LocalTime\n\n\"A 64-bit signed integer\"\nscalar Long\n\ntype MyTable {\n val: Int!\n}\n\ntype Query {\n MyTable(limit: Int = 10, offset: Int = 0): [MyTable!]\n AuthMyTable(limit: Int = 10, offset: Int = 0): [MyTable!]\n AuthMyTableValues(limit: Int = 10, offset: Int = 0): [MyTable!]\n}\n\nenum _McpMethodType {\n NONE\n TOOL\n RESOURCE\n}\n\nenum _RestMethodType {\n NONE\n GET\n POST\n}\n\ndirective @api(mcp: _McpMethodType, rest: _RestMethodType, uri: String) on QUERY | MUTATION | FIELD_DEFINITION\n"
450+
"schema" : "\"An RFC-3339 compliant Full Date Scalar\"\nscalar Date\n\n\"A slightly refined version of RFC-3339 compliant DateTime Scalar\"\nscalar DateTime\n\n\"A JSON scalar\"\nscalar JSON\n\n\"24-hour clock time value string in the format `hh:mm:ss` or `hh:mm:ss.sss`.\"\nscalar LocalTime\n\n\"A 64-bit signed integer\"\nscalar Long\n\ntype MyStringTable {\n val: String!\n}\n\ntype MyTable {\n val: Int!\n}\n\ntype Query {\n MyStringTable(limit: Int = 10, offset: Int = 0): [MyStringTable!]\n MyTable(limit: Int = 10, offset: Int = 0): [MyTable!]\n AuthMyTable(limit: Int = 10, offset: Int = 0): [MyTable!]\n AuthMyTableValues(limit: Int = 10, offset: Int = 0): [MyTable!]\n AuthStringMyTableValues(limit: Int = 10, offset: Int = 0): [MyStringTable!]\n}\n\nenum _McpMethodType {\n NONE\n TOOL\n RESOURCE\n}\n\nenum _RestMethodType {\n NONE\n GET\n POST\n}\n\ndirective @api(mcp: _McpMethodType, rest: _RestMethodType, uri: String) on QUERY | MUTATION | FIELD_DEFINITION\n"
281451
}
282452
}
283453
}

0 commit comments

Comments
 (0)