@malloydata/malloy 0.0.394 → 0.0.396
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/foundation/compile.d.ts +7 -6
- package/dist/api/foundation/compile.js +22 -6
- package/dist/api/foundation/config.d.ts +2 -3
- package/dist/api/foundation/config.js +23 -11
- package/dist/api/foundation/core.js +1 -1
- package/dist/api/foundation/runtime.d.ts +85 -5
- package/dist/api/foundation/runtime.js +204 -14
- package/dist/api/foundation/types.d.ts +2 -0
- package/dist/api/util.js +4 -0
- package/dist/connection/base_connection.js +6 -0
- package/dist/connection/validate_table_path.d.ts +10 -0
- package/dist/connection/validate_table_path.js +56 -0
- package/dist/dialect/databricks/databricks.d.ts +4 -4
- package/dist/dialect/databricks/databricks.js +17 -22
- package/dist/dialect/dialect.d.ts +100 -4
- package/dist/dialect/dialect.js +145 -1
- package/dist/dialect/duckdb/duckdb.d.ts +2 -3
- package/dist/dialect/duckdb/duckdb.js +12 -14
- package/dist/dialect/duckdb/table-path-parser.d.ts +2 -0
- package/dist/dialect/duckdb/table-path-parser.js +57 -0
- package/dist/dialect/index.d.ts +2 -0
- package/dist/dialect/index.js +4 -1
- package/dist/dialect/mysql/mysql.d.ts +4 -4
- package/dist/dialect/mysql/mysql.js +25 -20
- package/dist/dialect/pg_impl.d.ts +3 -1
- package/dist/dialect/pg_impl.js +6 -3
- package/dist/dialect/postgres/postgres.d.ts +1 -3
- package/dist/dialect/postgres/postgres.js +8 -16
- package/dist/dialect/snowflake/snowflake.d.ts +4 -4
- package/dist/dialect/snowflake/snowflake.js +11 -27
- package/dist/dialect/standardsql/standardsql.d.ts +6 -4
- package/dist/dialect/standardsql/standardsql.js +36 -15
- package/dist/dialect/table-path.d.ts +54 -0
- package/dist/dialect/table-path.js +144 -0
- package/dist/dialect/trino/trino.d.ts +0 -3
- package/dist/dialect/trino/trino.js +7 -20
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -2
- package/dist/lang/ast/expressions/expr-func.js +30 -11
- package/dist/lang/ast/expressions/expr-given.js +1 -0
- package/dist/lang/ast/field-space/reference-field.js +1 -1
- package/dist/lang/ast/source-elements/sql-source.js +4 -0
- package/dist/lang/ast/source-elements/table-source.d.ts +1 -7
- package/dist/lang/ast/source-elements/table-source.js +24 -19
- package/dist/lang/ast/statements/define-given.d.ts +1 -0
- package/dist/lang/ast/statements/define-given.js +7 -0
- package/dist/lang/ast/statements/import-statement.js +4 -0
- package/dist/lang/ast/types/annotation-elements.d.ts +1 -0
- package/dist/lang/ast/types/annotation-elements.js +10 -3
- package/dist/lang/ast/types/malloy-element.d.ts +1 -0
- package/dist/lang/ast/types/malloy-element.js +4 -0
- package/dist/lang/malloy-to-ast.d.ts +2 -1
- package/dist/lang/malloy-to-ast.js +11 -1
- package/dist/lang/parse-log.d.ts +2 -0
- package/dist/lang/parse-log.js +4 -0
- package/dist/lang/parse-malloy.d.ts +4 -1
- package/dist/lang/parse-malloy.js +63 -11
- package/dist/lang/parse-tree-walkers/find-external-references.d.ts +2 -15
- package/dist/lang/parse-tree-walkers/find-external-references.js +6 -23
- package/dist/lang/test/test-translator.d.ts +19 -5
- package/dist/lang/test/test-translator.js +15 -12
- package/dist/lang/translate-response.d.ts +1 -1
- package/dist/lang/zone.d.ts +2 -0
- package/dist/lang/zone.js +10 -0
- package/dist/model/constant_expression_compiler.js +14 -5
- package/dist/model/expression_compiler.js +19 -17
- package/dist/model/field_instance.js +7 -3
- package/dist/model/filter_compilers.js +1 -1
- package/dist/model/given_binding.js +26 -21
- package/dist/model/index.d.ts +1 -0
- package/dist/model/index.js +3 -1
- package/dist/model/malloy_compile_error.d.ts +13 -0
- package/dist/model/malloy_compile_error.js +23 -0
- package/dist/model/malloy_types.d.ts +2 -0
- package/dist/model/query_model_impl.js +9 -8
- package/dist/model/query_node.d.ts +5 -5
- package/dist/model/query_node.js +21 -16
- package/dist/model/query_query.js +60 -44
- package/dist/model/sql_compiled.d.ts +2 -4
- package/dist/model/sql_compiled.js +20 -18
- package/dist/test/test-models.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Contributors to the Malloy project
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.validateDuckDBTablePath = validateDuckDBTablePath;
|
|
8
|
+
const table_path_1 = require("../table-path");
|
|
9
|
+
const DUCKDB_FILE_PATH_RE = /^[A-Za-z0-9._\-/:?*]+$/;
|
|
10
|
+
const DUCKDB_SINGLE_QUOTED_RE = /^'(?:[^']|'')*'$/;
|
|
11
|
+
function validateDuckDBTablePath(input) {
|
|
12
|
+
if (input.length === 0) {
|
|
13
|
+
return { ok: false, error: 'DuckDB table path is empty' };
|
|
14
|
+
}
|
|
15
|
+
// Branch 1: explicit single-quoted literal.
|
|
16
|
+
if (input[0] === "'") {
|
|
17
|
+
if (DUCKDB_SINGLE_QUOTED_RE.test(input)) {
|
|
18
|
+
const body = input.slice(1, -1).replace(/''/g, "'");
|
|
19
|
+
if (body.includes(';') || body.includes('--')) {
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
error: `Invalid DuckDB table path: ${JSON.stringify(input)} — ` +
|
|
23
|
+
'forbidden character `;` or `--` in single-quoted body.',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return { ok: true, canonical: input };
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
ok: false,
|
|
30
|
+
error: `Invalid DuckDB table path: ${JSON.stringify(input)} — ` +
|
|
31
|
+
'unterminated or trailing-junk single-quoted literal.',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Branch 2: identifier path (same grammar as ANSI dialects).
|
|
35
|
+
const id = (0, table_path_1.validateDottedTablePath)(input, {
|
|
36
|
+
quoteChar: '"',
|
|
37
|
+
escapeStyle: 'doubled',
|
|
38
|
+
bareIdentRegex: /^[A-Za-z_][A-Za-z0-9_]*/,
|
|
39
|
+
dialectName: 'DuckDB',
|
|
40
|
+
});
|
|
41
|
+
if (id.ok)
|
|
42
|
+
return id;
|
|
43
|
+
// Branch 3: file-path convenience.
|
|
44
|
+
if (DUCKDB_FILE_PATH_RE.test(input)) {
|
|
45
|
+
return { ok: true, canonical: `'${input}'` };
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
error: `Invalid DuckDB table path: ${JSON.stringify(input)} — expected an ` +
|
|
50
|
+
'identifier path, a quoted identifier path, a single-quoted ' +
|
|
51
|
+
"literal ('foo.csv'), or a file-path-shaped string of letters, " +
|
|
52
|
+
'digits, and `._-/:?*`. For table-valued function calls (e.g. ' +
|
|
53
|
+
"read_parquet('foo.parquet')) or other table expressions, use a " +
|
|
54
|
+
'SQL block instead: connection.sql("""SELECT * FROM …""").',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=table-path-parser.js.map
|
package/dist/dialect/index.d.ts
CHANGED
|
@@ -14,3 +14,5 @@ export { getMalloyStandardFunctions } from './functions';
|
|
|
14
14
|
export type { MalloyStandardFunctionImplementations } from './functions';
|
|
15
15
|
export type { TinyToken } from './tiny_parser';
|
|
16
16
|
export { TinyParser } from './tiny_parser';
|
|
17
|
+
export type { DecodeDottedTablePathResult, DottedTablePathOptions, TablePathEscapeStyle, TablePathSegment, ValidateTablePathResult, } from './table-path';
|
|
18
|
+
export { decodeDottedTablePath, validateDottedTablePath } from './table-path';
|
package/dist/dialect/index.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.TinyParser = exports.getMalloyStandardFunctions = exports.registerDialect = exports.getDialect = exports.DatabricksDialect = exports.MySQLDialect = exports.TrinoDialect = exports.SnowflakeDialect = exports.DuckDBDialect = exports.PostgresDialect = exports.StandardSQLDialect = exports.qtz = exports.Dialect = exports.sql = exports.literal = exports.variadicParam = exports.param = exports.spread = exports.maxScalar = exports.minAggregate = exports.minScalar = exports.overload = exports.makeParam = exports.anyExprType = exports.arg = void 0;
|
|
25
|
+
exports.validateDottedTablePath = exports.decodeDottedTablePath = exports.TinyParser = exports.getMalloyStandardFunctions = exports.registerDialect = exports.getDialect = exports.DatabricksDialect = exports.MySQLDialect = exports.TrinoDialect = exports.SnowflakeDialect = exports.DuckDBDialect = exports.PostgresDialect = exports.StandardSQLDialect = exports.qtz = exports.Dialect = exports.sql = exports.literal = exports.variadicParam = exports.param = exports.spread = exports.maxScalar = exports.minAggregate = exports.minScalar = exports.overload = exports.makeParam = exports.anyExprType = exports.arg = void 0;
|
|
26
26
|
var util_1 = require("./functions/util");
|
|
27
27
|
Object.defineProperty(exports, "arg", { enumerable: true, get: function () { return util_1.arg; } });
|
|
28
28
|
Object.defineProperty(exports, "anyExprType", { enumerable: true, get: function () { return util_1.anyExprType; } });
|
|
@@ -60,4 +60,7 @@ var functions_1 = require("./functions");
|
|
|
60
60
|
Object.defineProperty(exports, "getMalloyStandardFunctions", { enumerable: true, get: function () { return functions_1.getMalloyStandardFunctions; } });
|
|
61
61
|
var tiny_parser_1 = require("./tiny_parser");
|
|
62
62
|
Object.defineProperty(exports, "TinyParser", { enumerable: true, get: function () { return tiny_parser_1.TinyParser; } });
|
|
63
|
+
var table_path_1 = require("./table-path");
|
|
64
|
+
Object.defineProperty(exports, "decodeDottedTablePath", { enumerable: true, get: function () { return table_path_1.decodeDottedTablePath; } });
|
|
65
|
+
Object.defineProperty(exports, "validateDottedTablePath", { enumerable: true, get: function () { return table_path_1.validateDottedTablePath; } });
|
|
63
66
|
//# sourceMappingURL=index.js.map
|
|
@@ -4,6 +4,9 @@ import { Dialect } from '../dialect';
|
|
|
4
4
|
import type { DialectFunctionOverloadDef } from '../functions';
|
|
5
5
|
export declare class MySQLDialect extends Dialect {
|
|
6
6
|
name: string;
|
|
7
|
+
stringLiteralStyle: "backslash";
|
|
8
|
+
identifierEscapeStyle: "doubled";
|
|
9
|
+
identifierQuoteChar: string;
|
|
7
10
|
defaultNumberType: string;
|
|
8
11
|
defaultDecimalType: string;
|
|
9
12
|
udfPrefix: string;
|
|
@@ -32,9 +35,9 @@ export declare class MySQLDialect extends Dialect {
|
|
|
32
35
|
booleanType: BooleanTypeSupport;
|
|
33
36
|
orderByClause: OrderByClauseType;
|
|
34
37
|
maxIdentifierLength: number;
|
|
38
|
+
tablePathBareIdentRegex: RegExp;
|
|
35
39
|
malloyTypeToSQLType(malloyType: AtomicTypeDef): string;
|
|
36
40
|
sqlTypeToMalloyType(sqlType: string): BasicAtomicTypeDef;
|
|
37
|
-
quoteTablePath(tablePath: string): string;
|
|
38
41
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
39
42
|
sqlAnyValue(_groupSet: number, fieldName: string): string;
|
|
40
43
|
private mapFields;
|
|
@@ -54,7 +57,6 @@ export declare class MySQLDialect extends Dialect {
|
|
|
54
57
|
sqlCreateFunction(id: string, funcText: string): string;
|
|
55
58
|
sqlCreateFunctionCombineLastStage(lastStageName: string): string;
|
|
56
59
|
sqlSelectAliasAsStruct(_alias: string, _fieldList: DialectFieldList): string;
|
|
57
|
-
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
58
60
|
sqlCreateTableAsSelect(_tableName: string, _sql: string): string;
|
|
59
61
|
sqlNowExpr(): string;
|
|
60
62
|
sqlConvertToCivilTime(expr: string, timezone: string, _typeDef: AtomicTypeDef): {
|
|
@@ -73,8 +75,6 @@ export declare class MySQLDialect extends Dialect {
|
|
|
73
75
|
sqlMeasureTimeExpr(df: MeasureTimeExpr): string;
|
|
74
76
|
sqlAggDistinct(_key: string, _values: string[], _func: (valNames: string[]) => string): string;
|
|
75
77
|
sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
|
|
76
|
-
sqlLiteralString(literal: string): string;
|
|
77
|
-
sqlLiteralRegexp(literal: string): string;
|
|
78
78
|
getDialectFunctionOverrides(): {
|
|
79
79
|
[name: string]: DialectFunctionOverloadDef[];
|
|
80
80
|
};
|
|
@@ -94,6 +94,9 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
94
94
|
constructor() {
|
|
95
95
|
super(...arguments);
|
|
96
96
|
this.name = 'mysql';
|
|
97
|
+
this.stringLiteralStyle = dialect_1.EscapeStyle.Backslash;
|
|
98
|
+
this.identifierEscapeStyle = dialect_1.EscapeStyle.Doubled;
|
|
99
|
+
this.identifierQuoteChar = '`';
|
|
97
100
|
this.defaultNumberType = 'DOUBLE PRECISION';
|
|
98
101
|
this.defaultDecimalType = 'DECIMAL';
|
|
99
102
|
this.udfPrefix = 'ms_temp.__udf';
|
|
@@ -121,6 +124,11 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
121
124
|
this.booleanType = 'simulated';
|
|
122
125
|
this.orderByClause = 'ordinal';
|
|
123
126
|
this.maxIdentifierLength = 64;
|
|
127
|
+
// MySQL bare identifiers allow `$` and may start with a digit, but
|
|
128
|
+
// cannot be entirely digits (or they lex as number literals). The
|
|
129
|
+
// regex requires at least one non-digit char somewhere in the run.
|
|
130
|
+
// Verified against the live engine.
|
|
131
|
+
this.tablePathBareIdentRegex = /^[A-Za-z0-9_$]*[A-Za-z_$][A-Za-z0-9_$]*/;
|
|
124
132
|
}
|
|
125
133
|
malloyTypeToSQLType(malloyType) {
|
|
126
134
|
switch (malloyType.type) {
|
|
@@ -154,12 +162,6 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
154
162
|
rawType: baseSqlType,
|
|
155
163
|
});
|
|
156
164
|
}
|
|
157
|
-
quoteTablePath(tablePath) {
|
|
158
|
-
return tablePath
|
|
159
|
-
.split('.')
|
|
160
|
-
.map(part => `\`${part}\``)
|
|
161
|
-
.join('.');
|
|
162
|
-
}
|
|
163
165
|
sqlGroupSetTable(groupSetCount) {
|
|
164
166
|
return `CROSS JOIN (select number - 1 as group_set from JSON_TABLE(cast(concat("[1", repeat(",1", ${groupSetCount}), "]") as JSON),"$[*]" COLUMNS(number FOR ORDINALITY)) group_set) as group_set`;
|
|
165
167
|
}
|
|
@@ -167,7 +169,11 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
167
169
|
return `MAX(${fieldName})`;
|
|
168
170
|
}
|
|
169
171
|
mapFields(fieldList) {
|
|
170
|
-
|
|
172
|
+
// JSON_OBJECT key is a string value. Routing rawName through
|
|
173
|
+
// sqlLiteralString also keeps the SQL valid under ANSI_QUOTES mode.
|
|
174
|
+
return fieldList
|
|
175
|
+
.map(f => `${this.sqlLiteralString(f.rawName)}, ${f.sqlExpression}`)
|
|
176
|
+
.join(', ');
|
|
171
177
|
}
|
|
172
178
|
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
173
179
|
const separator = ',';
|
|
@@ -218,7 +224,12 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
218
224
|
((_a = f.typeDef.rawType) === null || _a === void 0 ? void 0 : _a.match(/json/))) {
|
|
219
225
|
fType = f.typeDef.rawType.toUpperCase();
|
|
220
226
|
}
|
|
221
|
-
|
|
227
|
+
// JSON_TABLE PATH argument is a string literal containing a
|
|
228
|
+
// JSONPath. Render rawName through sqlLiteralString so a single
|
|
229
|
+
// quote in the user-controlled field name cannot close the SQL
|
|
230
|
+
// string literal.
|
|
231
|
+
const jsonPathLit = this.sqlLiteralString('$.' + f.rawName);
|
|
232
|
+
fields.push(`${this.sqlQuoteIdentifier(f.sqlOutputName)} ${fType} PATH ${jsonPathLit}`);
|
|
222
233
|
}
|
|
223
234
|
return fields.join(',\n');
|
|
224
235
|
}
|
|
@@ -266,7 +277,11 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
266
277
|
}
|
|
267
278
|
sqlFieldReference(parentAlias, parentType, childName, childType) {
|
|
268
279
|
if (parentType === 'array[scalar]' || parentType === 'record') {
|
|
269
|
-
|
|
280
|
+
// childName comes from user-controlled record field names; render
|
|
281
|
+
// the JSON path through sqlLiteralString so a single quote in the
|
|
282
|
+
// name cannot close the SQL string literal.
|
|
283
|
+
const jsonPathLit = this.sqlLiteralString('$.' + childName);
|
|
284
|
+
let ret = `JSON_UNQUOTE(JSON_EXTRACT(${parentAlias},${jsonPathLit}))`;
|
|
270
285
|
if (parentType === 'array[scalar]') {
|
|
271
286
|
ret = `JSON_UNQUOTE(${parentAlias}.\`value\`)`;
|
|
272
287
|
}
|
|
@@ -280,7 +295,7 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
280
295
|
return `CAST(${ret} as JSON)`;
|
|
281
296
|
}
|
|
282
297
|
}
|
|
283
|
-
const child = this.
|
|
298
|
+
const child = this.sqlQuoteIdentifier(childName);
|
|
284
299
|
return `${parentAlias}.${child}`;
|
|
285
300
|
}
|
|
286
301
|
sqlCreateFunction(id, funcText) {
|
|
@@ -297,9 +312,6 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
297
312
|
// .map(name => `'${name.replace(/`/g, '')}', \`${alias}\`.${name}`)
|
|
298
313
|
// .join(',')})`;
|
|
299
314
|
}
|
|
300
|
-
sqlMaybeQuoteIdentifier(identifier) {
|
|
301
|
-
return '`' + identifier.replace(/`/g, '``') + '`';
|
|
302
|
-
}
|
|
303
315
|
// TODO: Check what this is.
|
|
304
316
|
sqlCreateTableAsSelect(_tableName, _sql) {
|
|
305
317
|
throw new Error('Not implemented Yet');
|
|
@@ -441,13 +453,6 @@ class MySQLDialect extends dialect_1.Dialect {
|
|
|
441
453
|
}
|
|
442
454
|
return tableSQL;
|
|
443
455
|
}
|
|
444
|
-
sqlLiteralString(literal) {
|
|
445
|
-
const noVirgule = literal.replace(/\\/g, '\\\\');
|
|
446
|
-
return "'" + noVirgule.replace(/'/g, "\\'") + "'";
|
|
447
|
-
}
|
|
448
|
-
sqlLiteralRegexp(literal) {
|
|
449
|
-
return "'" + literal.replace(/'/g, "''") + "'";
|
|
450
|
-
}
|
|
451
456
|
getDialectFunctionOverrides() {
|
|
452
457
|
return (0, functions_1.expandOverrideMap)(function_overrides_1.MYSQL_MALLOY_STANDARD_OVERLOADS);
|
|
453
458
|
}
|
|
@@ -9,6 +9,9 @@ export declare const timeExtractMap: Record<string, string>;
|
|
|
9
9
|
export declare abstract class PostgresBase extends Dialect {
|
|
10
10
|
hasTimestamptz: boolean;
|
|
11
11
|
supportsBigIntPrecision: boolean;
|
|
12
|
+
stringLiteralStyle: "doubled";
|
|
13
|
+
identifierEscapeStyle: "doubled";
|
|
14
|
+
identifierQuoteChar: string;
|
|
12
15
|
sqlNowExpr(): string;
|
|
13
16
|
sqlTimeExtractExpr(qi: QueryInfo, from: TimeExtractExpr): string;
|
|
14
17
|
sqlCast(qi: QueryInfo, cast: TypecastExpr): string;
|
|
@@ -18,7 +21,6 @@ export declare abstract class PostgresBase extends Dialect {
|
|
|
18
21
|
sqlTimestamptzLiteral(_qi: QueryInfo, literal: string, timezone: string): string;
|
|
19
22
|
sqlLiteralRecord(_lit: RecordLiteralNode): string;
|
|
20
23
|
sqlLiteralArray(lit: ArrayLiteralNode): string;
|
|
21
|
-
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
22
24
|
sqlConvertToCivilTime(expr: string, timezone: string, typeDef: AtomicTypeDef): {
|
|
23
25
|
sql: string;
|
|
24
26
|
typeDef: AtomicTypeDef;
|
package/dist/dialect/pg_impl.js
CHANGED
|
@@ -23,6 +23,12 @@ class PostgresBase extends dialect_1.Dialect {
|
|
|
23
23
|
this.hasTimestamptz = true;
|
|
24
24
|
// Postgres-family dialects use JSON serialization which loses bigint precision
|
|
25
25
|
this.supportsBigIntPrecision = false;
|
|
26
|
+
// All current Postgres-family dialects (Postgres, DuckDB, Trino, Presto)
|
|
27
|
+
// use ANSI doubled-quote literal escaping and ANSI double-quote identifiers.
|
|
28
|
+
// Subclasses may override.
|
|
29
|
+
this.stringLiteralStyle = dialect_1.EscapeStyle.Doubled;
|
|
30
|
+
this.identifierEscapeStyle = dialect_1.EscapeStyle.Doubled;
|
|
31
|
+
this.identifierQuoteChar = '"';
|
|
26
32
|
}
|
|
27
33
|
sqlNowExpr() {
|
|
28
34
|
return 'LOCALTIMESTAMP';
|
|
@@ -96,9 +102,6 @@ class PostgresBase extends dialect_1.Dialect {
|
|
|
96
102
|
const array = lit.kids.values.map(val => val.sql);
|
|
97
103
|
return 'ARRAY[' + array.join(',') + ']';
|
|
98
104
|
}
|
|
99
|
-
sqlMaybeQuoteIdentifier(identifier) {
|
|
100
|
-
return '"' + identifier.replace(/"/g, '""') + '"';
|
|
101
|
-
}
|
|
102
105
|
sqlConvertToCivilTime(expr, timezone, typeDef) {
|
|
103
106
|
// PostgreSQL/DuckDB: AT TIME ZONE is polymorphic
|
|
104
107
|
// For timestamptz (TIMESTAMPTZ): AT TIME ZONE converts to plain TIMESTAMP (civil in timezone)
|
|
@@ -27,7 +27,7 @@ export declare class PostgresDialect extends PostgresBase {
|
|
|
27
27
|
compoundObjectInSchema: boolean;
|
|
28
28
|
likeEscape: boolean;
|
|
29
29
|
maxIdentifierLength: number;
|
|
30
|
-
|
|
30
|
+
tablePathBareIdentRegex: RegExp;
|
|
31
31
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
32
32
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
33
33
|
mapFields(fieldList: DialectFieldList): string;
|
|
@@ -52,8 +52,6 @@ export declare class PostgresDialect extends PostgresBase {
|
|
|
52
52
|
sqlAggDistinct(key: string, values: string[], func: (valNames: string[]) => string): string;
|
|
53
53
|
sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
|
|
54
54
|
sqlOrderBy(orderTerms: string[]): string;
|
|
55
|
-
sqlLiteralString(literal: string): string;
|
|
56
|
-
sqlLiteralRegexp(literal: string): string;
|
|
57
55
|
getDialectFunctionOverrides(): {
|
|
58
56
|
[name: string]: DialectFunctionOverloadDef[];
|
|
59
57
|
};
|
|
@@ -99,12 +99,9 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
99
99
|
this.compoundObjectInSchema = false;
|
|
100
100
|
this.likeEscape = false;
|
|
101
101
|
this.maxIdentifierLength = 63;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
.split('.')
|
|
106
|
-
.map(part => `"${part}"`)
|
|
107
|
-
.join('.');
|
|
102
|
+
// Postgres bare-identifier continuation allows `$` (verified against
|
|
103
|
+
// the live engine: `postgres.table('foo$bar')` resolves successfully).
|
|
104
|
+
this.tablePathBareIdentRegex = /^[A-Za-z_][A-Za-z0-9_$]*/;
|
|
108
105
|
}
|
|
109
106
|
sqlGroupSetTable(groupSetCount) {
|
|
110
107
|
return `CROSS JOIN GENERATE_SERIES(0,${groupSetCount},1) as group_set`;
|
|
@@ -164,7 +161,8 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
164
161
|
return `(${parentAlias}->>'__row_id')`;
|
|
165
162
|
}
|
|
166
163
|
if (parentType !== 'table') {
|
|
167
|
-
|
|
164
|
+
const nameLit = this.sqlLiteralString(childName);
|
|
165
|
+
let ret = `JSONB_EXTRACT_PATH_TEXT(${parentAlias},${nameLit})`;
|
|
168
166
|
switch (childType) {
|
|
169
167
|
case 'string':
|
|
170
168
|
break;
|
|
@@ -176,13 +174,13 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
176
174
|
case 'record':
|
|
177
175
|
case 'array[record]':
|
|
178
176
|
case 'sql native':
|
|
179
|
-
ret = `JSONB_EXTRACT_PATH(${parentAlias}
|
|
177
|
+
ret = `JSONB_EXTRACT_PATH(${parentAlias},${nameLit})`;
|
|
180
178
|
break;
|
|
181
179
|
}
|
|
182
180
|
return ret;
|
|
183
181
|
}
|
|
184
182
|
else {
|
|
185
|
-
const child = this.
|
|
183
|
+
const child = this.sqlQuoteIdentifier(childName);
|
|
186
184
|
return `${parentAlias}.${child}`;
|
|
187
185
|
}
|
|
188
186
|
}
|
|
@@ -307,12 +305,6 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
307
305
|
sqlOrderBy(orderTerms) {
|
|
308
306
|
return `ORDER BY ${orderTerms.map(t => `${t} NULLS LAST`).join(',')}`;
|
|
309
307
|
}
|
|
310
|
-
sqlLiteralString(literal) {
|
|
311
|
-
return "'" + literal.replace(/'/g, "''") + "'";
|
|
312
|
-
}
|
|
313
|
-
sqlLiteralRegexp(literal) {
|
|
314
|
-
return "'" + literal.replace(/'/g, "''") + "'";
|
|
315
|
-
}
|
|
316
308
|
getDialectFunctionOverrides() {
|
|
317
309
|
return (0, functions_1.expandOverrideMap)(function_overrides_1.POSTGRES_MALLOY_STANDARD_OVERLOADS);
|
|
318
310
|
}
|
|
@@ -372,7 +364,7 @@ class PostgresDialect extends pg_impl_1.PostgresBase {
|
|
|
372
364
|
sqlLiteralRecord(lit) {
|
|
373
365
|
const props = [];
|
|
374
366
|
for (const [kName, kVal] of Object.entries(lit.kids)) {
|
|
375
|
-
props.push(
|
|
367
|
+
props.push(`${this.sqlLiteralString(kName)},${kVal.sql}`);
|
|
376
368
|
}
|
|
377
369
|
return `JSONB_BUILD_OBJECT(${props.join(', ')})`;
|
|
378
370
|
}
|
|
@@ -6,6 +6,9 @@ export declare class SnowflakeDialect extends Dialect {
|
|
|
6
6
|
name: string;
|
|
7
7
|
experimental: boolean;
|
|
8
8
|
hasTimestamptz: boolean;
|
|
9
|
+
stringLiteralStyle: "backslash";
|
|
10
|
+
identifierEscapeStyle: "doubled";
|
|
11
|
+
identifierQuoteChar: string;
|
|
9
12
|
defaultNumberType: string;
|
|
10
13
|
defaultDecimalType: string;
|
|
11
14
|
udfPrefix: string;
|
|
@@ -26,8 +29,8 @@ export declare class SnowflakeDialect extends Dialect {
|
|
|
26
29
|
supportsQualify: boolean;
|
|
27
30
|
supportsPipelinesInViews: boolean;
|
|
28
31
|
supportsComplexFilteredSources: boolean;
|
|
32
|
+
tablePathBareIdentRegex: RegExp;
|
|
29
33
|
integerTypeMappings: IntegerTypeMapping[];
|
|
30
|
-
quoteTablePath(tablePath: string): string;
|
|
31
34
|
sqlGroupSetTable(groupSetCount: number): string;
|
|
32
35
|
sqlAnyValue(groupSet: number, fieldName: string): string;
|
|
33
36
|
mapFields(fieldList: DialectFieldList): string;
|
|
@@ -45,7 +48,6 @@ export declare class SnowflakeDialect extends Dialect {
|
|
|
45
48
|
sqlCreateFunction(_id: string, _funcText: string): string;
|
|
46
49
|
sqlCreateFunctionCombineLastStage(_lastStageName: string): string;
|
|
47
50
|
sqlSelectAliasAsStruct(alias: string): string;
|
|
48
|
-
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
49
51
|
sqlCreateTableAsSelect(tableName: string, sql: string): string;
|
|
50
52
|
sqlConvertToCivilTime(expr: string, timezone: string, typeDef: AtomicTypeDef): {
|
|
51
53
|
sql: string;
|
|
@@ -65,8 +67,6 @@ export declare class SnowflakeDialect extends Dialect {
|
|
|
65
67
|
sqlRegexpMatch(compare: RegexMatchExpr): string;
|
|
66
68
|
sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
|
|
67
69
|
sqlOrderBy(orderTerms: string[]): string;
|
|
68
|
-
sqlLiteralString(literal: string): string;
|
|
69
|
-
sqlLiteralRegexp(literal: string): string;
|
|
70
70
|
getDialectFunctionOverrides(): {
|
|
71
71
|
[name: string]: DialectFunctionOverloadDef[];
|
|
72
72
|
};
|
|
@@ -78,6 +78,9 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
78
78
|
this.name = 'snowflake';
|
|
79
79
|
this.experimental = false;
|
|
80
80
|
this.hasTimestamptz = true;
|
|
81
|
+
this.stringLiteralStyle = dialect_1.EscapeStyle.Backslash;
|
|
82
|
+
this.identifierEscapeStyle = dialect_1.EscapeStyle.Doubled;
|
|
83
|
+
this.identifierQuoteChar = '"';
|
|
81
84
|
this.defaultNumberType = 'NUMBER';
|
|
82
85
|
this.defaultDecimalType = 'NUMBER';
|
|
83
86
|
this.udfPrefix = '__udf';
|
|
@@ -98,21 +101,14 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
98
101
|
this.supportsQualify = false;
|
|
99
102
|
this.supportsPipelinesInViews = false;
|
|
100
103
|
this.supportsComplexFilteredSources = false;
|
|
104
|
+
// Snowflake bare-identifier continuation allows `$` (verified against
|
|
105
|
+
// the live engine).
|
|
106
|
+
this.tablePathBareIdentRegex = /^[A-Za-z_][A-Za-z0-9_$]*/;
|
|
101
107
|
// Snowflake uses NUMBER(38,0) for all integers - can exceed JS Number precision
|
|
102
108
|
this.integerTypeMappings = [
|
|
103
109
|
{ min: dialect_1.MIN_DECIMAL38, max: dialect_1.MAX_DECIMAL38, numberType: 'bigint' },
|
|
104
110
|
];
|
|
105
111
|
}
|
|
106
|
-
quoteTablePath(tablePath) {
|
|
107
|
-
// Quote with double quotes if contains dangerous characters
|
|
108
|
-
if (tablePath.match(/[;-]/)) {
|
|
109
|
-
return tablePath
|
|
110
|
-
.split('.')
|
|
111
|
-
.map(part => `"${part}"`)
|
|
112
|
-
.join('.');
|
|
113
|
-
}
|
|
114
|
-
return tablePath;
|
|
115
|
-
}
|
|
116
112
|
sqlGroupSetTable(groupSetCount) {
|
|
117
113
|
return `CROSS JOIN (SELECT index as group_set FROM TABLE(FLATTEN(ARRAY_GENERATE_RANGE(0, ${groupSetCount + 1}))))`;
|
|
118
114
|
}
|
|
@@ -126,7 +122,7 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
126
122
|
}
|
|
127
123
|
mapFieldsForObjectConstruct(fieldList) {
|
|
128
124
|
return fieldList
|
|
129
|
-
.map(f =>
|
|
125
|
+
.map(f => `${this.sqlLiteralString(f.rawName)}, (${f.sqlExpression})`)
|
|
130
126
|
.join(', ');
|
|
131
127
|
}
|
|
132
128
|
sqlAggregateTurtle(groupSet, fieldList, orderBy) {
|
|
@@ -152,7 +148,7 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
152
148
|
return `COALESCE(ARRAY_AGG(CASE WHEN group_set=${groupSet} THEN OBJECT_CONSTRUCT_KEEP_NULL(${fields}) END)[0], OBJECT_CONSTRUCT_KEEP_NULL(${nullValues}))`;
|
|
153
149
|
}
|
|
154
150
|
sqlUnnestAlias(source, alias, _fieldList, _needDistinctKey, isArray, _isInNestedPipeline) {
|
|
155
|
-
const as = this.
|
|
151
|
+
const as = this.sqlQuoteIdentifier(alias);
|
|
156
152
|
if (isArray) {
|
|
157
153
|
return `LEFT JOIN lateral flatten(input => ${source}) as ${as}`;
|
|
158
154
|
}
|
|
@@ -202,7 +198,7 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
202
198
|
return 'UUID_STRING()';
|
|
203
199
|
}
|
|
204
200
|
sqlFieldReference(parentAlias, parentType, childName, childType) {
|
|
205
|
-
const sqlName = this.
|
|
201
|
+
const sqlName = this.sqlQuoteIdentifier(childName);
|
|
206
202
|
if (childName === '__row_id') {
|
|
207
203
|
return `"${parentAlias}".INDEX::varchar`;
|
|
208
204
|
}
|
|
@@ -250,9 +246,6 @@ class SnowflakeDialect extends dialect_1.Dialect {
|
|
|
250
246
|
sqlSelectAliasAsStruct(alias) {
|
|
251
247
|
return `OBJECT_CONSTRUCT_KEEP_NULL(${alias}.*)`;
|
|
252
248
|
}
|
|
253
|
-
sqlMaybeQuoteIdentifier(identifier) {
|
|
254
|
-
return '"' + identifier.replace(/"/g, '""') + '"';
|
|
255
|
-
}
|
|
256
249
|
sqlCreateTableAsSelect(tableName, sql) {
|
|
257
250
|
return `
|
|
258
251
|
CREATE TEMP TABLE IF NOT EXISTS \`${tableName}\`
|
|
@@ -425,14 +418,6 @@ ${(0, utils_1.indent)(sql)}
|
|
|
425
418
|
sqlOrderBy(orderTerms) {
|
|
426
419
|
return `ORDER BY ${orderTerms.map(t => `${t} NULLS LAST`).join(',')}`;
|
|
427
420
|
}
|
|
428
|
-
sqlLiteralString(literal) {
|
|
429
|
-
const noVirgule = literal.replace(/\\/g, '\\\\');
|
|
430
|
-
return "'" + noVirgule.replace(/'/g, "\\'") + "'";
|
|
431
|
-
}
|
|
432
|
-
sqlLiteralRegexp(literal) {
|
|
433
|
-
const noVirgule = literal.replace(/\\/g, '\\\\');
|
|
434
|
-
return "'" + noVirgule.replace(/'/g, "\\'") + "'";
|
|
435
|
-
}
|
|
436
421
|
getDialectFunctionOverrides() {
|
|
437
422
|
return (0, functions_1.expandOverrideMap)(function_overrides_1.SNOWFLAKE_MALLOY_STANDARD_OVERLOADS);
|
|
438
423
|
}
|
|
@@ -457,7 +442,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
457
442
|
var _a;
|
|
458
443
|
if ((0, malloy_types_1.isAtomic)(f)) {
|
|
459
444
|
const name = (_a = f.as) !== null && _a !== void 0 ? _a : f.name;
|
|
460
|
-
const oneSchema = `${this.
|
|
445
|
+
const oneSchema = `${this.sqlQuoteIdentifier(name)} ${this.malloyTypeToSQLType(f)}`;
|
|
461
446
|
ret.push(oneSchema);
|
|
462
447
|
}
|
|
463
448
|
return ret;
|
|
@@ -521,9 +506,8 @@ ${(0, utils_1.indent)(sql)}
|
|
|
521
506
|
const rowVals = [];
|
|
522
507
|
for (const f of lit.typeDef.fields) {
|
|
523
508
|
const name = (_a = f.as) !== null && _a !== void 0 ? _a : f.name;
|
|
524
|
-
const propName = `'${name}'`;
|
|
525
509
|
const propVal = (_c = (_b = (0, malloy_types_1.safeRecordGet)(lit.kids, name)) === null || _b === void 0 ? void 0 : _b.sql) !== null && _c !== void 0 ? _c : 'internal-error-record-literal';
|
|
526
|
-
rowVals.push(`${
|
|
510
|
+
rowVals.push(`${this.sqlLiteralString(name)},${propVal}`);
|
|
527
511
|
}
|
|
528
512
|
return `OBJECT_CONSTRUCT_KEEP_NULL(${rowVals.join(',')})`;
|
|
529
513
|
}
|
|
@@ -4,6 +4,9 @@ import type { CompiledOrderBy, DialectFieldList, IntegerTypeMapping, OrderByRequ
|
|
|
4
4
|
import { Dialect, type LateralJoinExpression } from '../dialect';
|
|
5
5
|
export declare class StandardSQLDialect extends Dialect {
|
|
6
6
|
name: string;
|
|
7
|
+
stringLiteralStyle: "backslash";
|
|
8
|
+
identifierEscapeStyle: "backslash";
|
|
9
|
+
identifierQuoteChar: string;
|
|
7
10
|
experimental: boolean;
|
|
8
11
|
defaultNumberType: string;
|
|
9
12
|
defaultDecimalType: string;
|
|
@@ -29,7 +32,9 @@ export declare class StandardSQLDialect extends Dialect {
|
|
|
29
32
|
supportsHyperLogLog: boolean;
|
|
30
33
|
likeEscape: boolean;
|
|
31
34
|
integerTypeMappings: IntegerTypeMapping[];
|
|
32
|
-
|
|
35
|
+
private bqRejectBacktick;
|
|
36
|
+
sqlQuoteIdentifier(identifier: string): string;
|
|
37
|
+
tablePathBareIdentRegex: RegExp;
|
|
33
38
|
needsCivilTimeComputation(typeDef: AtomicTypeDef, truncateTo: TimestampUnit | undefined, offsetUnit: TimestampUnit | undefined, qi: QueryInfo): {
|
|
34
39
|
needed: boolean;
|
|
35
40
|
tz: string | undefined;
|
|
@@ -50,7 +55,6 @@ export declare class StandardSQLDialect extends Dialect {
|
|
|
50
55
|
sqlCreateTableAsSelect(tableName: string, sql: string): string;
|
|
51
56
|
sqlCreateFunctionCombineLastStage(lastStageName: string): string;
|
|
52
57
|
sqlSelectAliasAsStruct(alias: string): string;
|
|
53
|
-
sqlMaybeQuoteIdentifier(identifier: string): string;
|
|
54
58
|
sqlNowExpr(): string;
|
|
55
59
|
sqlTimeExtractExpr(qi: QueryInfo, te: TimeExtractExpr): string;
|
|
56
60
|
sqlConvertToCivilTime(expr: string, timezone: string, _typeDef: AtomicTypeDef): {
|
|
@@ -68,8 +72,6 @@ export declare class StandardSQLDialect extends Dialect {
|
|
|
68
72
|
sqlTimestamptzLiteral(_qi: QueryInfo, _literal: string, _timezone: string): string;
|
|
69
73
|
sqlMeasureTimeExpr(measure: MeasureTimeExpr): string;
|
|
70
74
|
sqlSampleTable(tableSQL: string, sample: Sampling | undefined): string;
|
|
71
|
-
sqlLiteralString(literal: string): string;
|
|
72
|
-
sqlLiteralRegexp(literal: string): string;
|
|
73
75
|
getDialectFunctionOverrides(): {
|
|
74
76
|
[name: string]: DialectFunctionOverloadDef[];
|
|
75
77
|
};
|
|
@@ -76,6 +76,9 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
76
76
|
constructor() {
|
|
77
77
|
super(...arguments);
|
|
78
78
|
this.name = 'standardsql';
|
|
79
|
+
this.stringLiteralStyle = dialect_1.EscapeStyle.Backslash;
|
|
80
|
+
this.identifierEscapeStyle = dialect_1.EscapeStyle.Backslash;
|
|
81
|
+
this.identifierQuoteChar = '`';
|
|
79
82
|
this.experimental = false;
|
|
80
83
|
this.defaultNumberType = 'FLOAT64';
|
|
81
84
|
this.defaultDecimalType = 'NUMERIC';
|
|
@@ -101,13 +104,42 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
101
104
|
this.integerTypeMappings = [
|
|
102
105
|
{ min: dialect_1.MIN_INT64, max: dialect_1.MAX_INT64, numberType: 'bigint' },
|
|
103
106
|
];
|
|
107
|
+
// BigQuery bare-identifier continuation allows dashes (verified
|
|
108
|
+
// against the live engine: `proj-foo.dataset.table` resolves to a
|
|
109
|
+
// table reference, both bare and inside per-segment backticks). The
|
|
110
|
+
// base `sqlValidateTableName` handles every shape we accept —
|
|
111
|
+
// bare-dotted, whole-backticked, and per-segment-backticked — because
|
|
112
|
+
// its grammar is `Segment ('.' Segment)*` and a segment is either
|
|
113
|
+
// bare or quoted with this dialect's `identifierQuoteChar` /
|
|
114
|
+
// `identifierEscapeStyle` (`` ` `` / Backslash). The whole-path form
|
|
115
|
+
// (`` `proj.dataset.table` ``) is accepted naturally as a single
|
|
116
|
+
// quoted segment.
|
|
117
|
+
//
|
|
118
|
+
// `*` is intentionally NOT in this regex. BigQuery's parser only
|
|
119
|
+
// accepts `*` inside backticks (wildcard tables must be quoted, e.g.
|
|
120
|
+
// `` `dataset.events_*` ``). Bare wildcards would fail at the engine,
|
|
121
|
+
// so we reject them up front and require the user to type the
|
|
122
|
+
// backticks they'd need anyway.
|
|
123
|
+
this.tablePathBareIdentRegex = /^[A-Za-z_][A-Za-z0-9_-]*/;
|
|
104
124
|
}
|
|
105
125
|
sqlLateralJoinBag(expressions) {
|
|
106
126
|
const fields = expressions.map(e => `${e.sql} as ${e.name}`);
|
|
107
127
|
return `LEFT JOIN UNNEST([STRUCT(${fields.join(',\n')})]) as __lateral_join_bag\n`;
|
|
108
128
|
}
|
|
109
|
-
|
|
110
|
-
|
|
129
|
+
// BigQuery's parser accepts `\`` as a backtick escape inside quoted
|
|
130
|
+
// identifiers, but BigQuery's schema layer rejects field/table names
|
|
131
|
+
// containing a literal backtick. Refuse here so the error names the
|
|
132
|
+
// dialect; the rest of the escape (backslash-doubling) is handled by
|
|
133
|
+
// the base via identifierEscapeStyle.
|
|
134
|
+
// Reference: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical
|
|
135
|
+
bqRejectBacktick(name, kind) {
|
|
136
|
+
if (name.includes('`')) {
|
|
137
|
+
throw new Error(`BigQuery ${kind} cannot contain a backtick: ${JSON.stringify(name)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
sqlQuoteIdentifier(identifier) {
|
|
141
|
+
this.bqRejectBacktick(identifier, 'identifier');
|
|
142
|
+
return super.sqlQuoteIdentifier(identifier);
|
|
111
143
|
}
|
|
112
144
|
needsCivilTimeComputation(typeDef, truncateTo, offsetUnit, qi) {
|
|
113
145
|
// In addition to using "civil" space for units where a query time zone is
|
|
@@ -193,7 +225,7 @@ class StandardSQLDialect extends dialect_1.Dialect {
|
|
|
193
225
|
return 'GENERATE_UUID()';
|
|
194
226
|
}
|
|
195
227
|
sqlFieldReference(parentAlias, _parentType, childName, _childType) {
|
|
196
|
-
const child = this.
|
|
228
|
+
const child = this.sqlQuoteIdentifier(childName);
|
|
197
229
|
return `${parentAlias}.${child}`;
|
|
198
230
|
}
|
|
199
231
|
sqlUnnestPipelineHead(isSingleton, sourceSQLExpression) {
|
|
@@ -223,9 +255,6 @@ ${(0, utils_1.indent)(sql)}
|
|
|
223
255
|
sqlSelectAliasAsStruct(alias) {
|
|
224
256
|
return `(SELECT AS STRUCT ${alias}.*)`;
|
|
225
257
|
}
|
|
226
|
-
sqlMaybeQuoteIdentifier(identifier) {
|
|
227
|
-
return '`' + identifier + '`';
|
|
228
|
-
}
|
|
229
258
|
sqlNowExpr() {
|
|
230
259
|
return 'CURRENT_TIMESTAMP()';
|
|
231
260
|
}
|
|
@@ -358,14 +387,6 @@ ${(0, utils_1.indent)(sql)}
|
|
|
358
387
|
}
|
|
359
388
|
return tableSQL;
|
|
360
389
|
}
|
|
361
|
-
sqlLiteralString(literal) {
|
|
362
|
-
const noVirgule = literal.replace(/\\/g, '\\\\');
|
|
363
|
-
return "'" + noVirgule.replace(/'/g, "\\'") + "'";
|
|
364
|
-
}
|
|
365
|
-
sqlLiteralRegexp(literal) {
|
|
366
|
-
const noVirgule = literal.replace(/\\/g, '\\\\');
|
|
367
|
-
return "'" + noVirgule.replace(/'/g, "\\'") + "'";
|
|
368
|
-
}
|
|
369
390
|
getDialectFunctionOverrides() {
|
|
370
391
|
return (0, functions_1.expandOverrideMap)(function_overrides_1.STANDARDSQL_MALLOY_STANDARD_OVERLOADS);
|
|
371
392
|
}
|
|
@@ -432,7 +453,7 @@ ${(0, utils_1.indent)(sql)}
|
|
|
432
453
|
const ents = [];
|
|
433
454
|
for (const [name, val] of Object.entries(lit.kids)) {
|
|
434
455
|
const expr = val.sql || 'internal-error-literal-record';
|
|
435
|
-
ents.push(`${expr} AS ${this.
|
|
456
|
+
ents.push(`${expr} AS ${this.sqlQuoteIdentifier(name)}`);
|
|
436
457
|
}
|
|
437
458
|
return `STRUCT(${ents.join(',')})`;
|
|
438
459
|
}
|