@malloydata/malloy 0.0.394 → 0.0.395

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.
Files changed (50) hide show
  1. package/dist/api/foundation/config.d.ts +2 -3
  2. package/dist/api/foundation/config.js +23 -11
  3. package/dist/api/foundation/core.js +1 -1
  4. package/dist/api/foundation/runtime.js +21 -1
  5. package/dist/api/util.js +4 -0
  6. package/dist/connection/base_connection.js +6 -0
  7. package/dist/connection/validate_table_path.d.ts +10 -0
  8. package/dist/connection/validate_table_path.js +56 -0
  9. package/dist/dialect/databricks/databricks.d.ts +4 -4
  10. package/dist/dialect/databricks/databricks.js +17 -22
  11. package/dist/dialect/dialect.d.ts +100 -4
  12. package/dist/dialect/dialect.js +145 -1
  13. package/dist/dialect/duckdb/duckdb.d.ts +2 -3
  14. package/dist/dialect/duckdb/duckdb.js +12 -14
  15. package/dist/dialect/duckdb/table-path-parser.d.ts +2 -0
  16. package/dist/dialect/duckdb/table-path-parser.js +57 -0
  17. package/dist/dialect/index.d.ts +2 -0
  18. package/dist/dialect/index.js +4 -1
  19. package/dist/dialect/mysql/mysql.d.ts +4 -4
  20. package/dist/dialect/mysql/mysql.js +25 -20
  21. package/dist/dialect/pg_impl.d.ts +3 -1
  22. package/dist/dialect/pg_impl.js +6 -3
  23. package/dist/dialect/postgres/postgres.d.ts +1 -3
  24. package/dist/dialect/postgres/postgres.js +8 -16
  25. package/dist/dialect/snowflake/snowflake.d.ts +4 -4
  26. package/dist/dialect/snowflake/snowflake.js +11 -27
  27. package/dist/dialect/standardsql/standardsql.d.ts +6 -4
  28. package/dist/dialect/standardsql/standardsql.js +36 -15
  29. package/dist/dialect/table-path.d.ts +54 -0
  30. package/dist/dialect/table-path.js +144 -0
  31. package/dist/dialect/trino/trino.d.ts +0 -3
  32. package/dist/dialect/trino/trino.js +7 -20
  33. package/dist/index.d.ts +2 -2
  34. package/dist/index.js +4 -2
  35. package/dist/lang/ast/source-elements/table-source.d.ts +1 -7
  36. package/dist/lang/ast/source-elements/table-source.js +20 -19
  37. package/dist/lang/parse-log.d.ts +1 -0
  38. package/dist/lang/parse-malloy.js +37 -7
  39. package/dist/lang/parse-tree-walkers/find-external-references.d.ts +2 -15
  40. package/dist/lang/parse-tree-walkers/find-external-references.js +6 -23
  41. package/dist/lang/translate-response.d.ts +1 -1
  42. package/dist/model/filter_compilers.js +1 -1
  43. package/dist/model/query_model_impl.js +7 -7
  44. package/dist/model/query_query.js +37 -33
  45. package/dist/model/sql_compiled.d.ts +2 -4
  46. package/dist/model/sql_compiled.js +14 -15
  47. package/dist/test/test-models.js +2 -2
  48. package/dist/version.d.ts +1 -1
  49. package/dist/version.js +1 -1
  50. package/package.json +4 -4
@@ -22,24 +22,38 @@
22
22
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.TableFunctionSource = exports.TableMethodSource = exports.TableSource = void 0;
25
+ exports.TableMethodSource = exports.TableSource = void 0;
26
26
  const find_external_references_1 = require("../../parse-tree-walkers/find-external-references");
27
27
  const source_1 = require("./source");
28
28
  const error_factory_1 = require("../error-factory");
29
+ const dialect_1 = require("../../../dialect");
29
30
  class TableSource extends source_1.Source {
30
31
  getSourceDef() {
31
- var _a, _b, _c;
32
+ var _a, _b, _c, _d;
32
33
  const info = this.getTableInfo();
33
34
  if (info === undefined) {
34
35
  return error_factory_1.ErrorFactory.structDef;
35
36
  }
36
- const { tablePath, connectionName } = info;
37
+ const { tablePath: rawTablePath, connectionName } = info;
38
+ // Re-validate the table path. ImportsAndTablesStep validated and
39
+ // silently skipped invalid entries; we re-validate here so we can
40
+ // log a precise translator error at the AST element's location.
41
+ let tablePath = rawTablePath;
42
+ const dialectName = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.connectionDialectZone.get(connectionName);
43
+ if (dialectName !== undefined) {
44
+ const validation = (0, dialect_1.getDialect)(dialectName).sqlValidateTableName(rawTablePath);
45
+ if (!validation.ok) {
46
+ this.logError('invalid-table-path', validation.error);
47
+ return error_factory_1.ErrorFactory.structDef;
48
+ }
49
+ tablePath = validation.canonical;
50
+ }
37
51
  const key = (0, find_external_references_1.constructTableKey)(connectionName, tablePath);
38
- const tableDefEntry = (_a = this.translator()) === null || _a === void 0 ? void 0 : _a.root.schemaZone.getEntry(key);
52
+ const tableDefEntry = (_b = this.translator()) === null || _b === void 0 ? void 0 : _b.root.schemaZone.getEntry(key);
39
53
  let msg = `Schema read failure for table '${tablePath}' for connection '${connectionName}'`;
40
54
  if (tableDefEntry) {
41
55
  if (tableDefEntry.status === 'present') {
42
- (_b = this.document()) === null || _b === void 0 ? void 0 : _b.checkExperimentalDialect(this, tableDefEntry.value.dialect);
56
+ (_c = this.document()) === null || _c === void 0 ? void 0 : _c.checkExperimentalDialect(this, tableDefEntry.value.dialect);
43
57
  tableDefEntry.value.location = this.location;
44
58
  tableDefEntry.value.fields.forEach(field => {
45
59
  field.location = this.location;
@@ -58,7 +72,7 @@ class TableSource extends source_1.Source {
58
72
  }),
59
73
  location: this.location,
60
74
  };
61
- (_c = this.document()) === null || _c === void 0 ? void 0 : _c.rememberToAddModelAnnotations(ret);
75
+ (_d = this.document()) === null || _d === void 0 ? void 0 : _d.rememberToAddModelAnnotations(ret);
62
76
  return ret;
63
77
  }
64
78
  if (tableDefEntry.status === 'error') {
@@ -96,17 +110,4 @@ class TableMethodSource extends TableSource {
96
110
  }
97
111
  }
98
112
  exports.TableMethodSource = TableMethodSource;
99
- class TableFunctionSource extends TableSource {
100
- constructor(tableURI) {
101
- super();
102
- this.tableURI = tableURI;
103
- this.elementType = 'tableFunctionSource';
104
- }
105
- getTableInfo() {
106
- // This use of `deprecatedParseTableURI` is ok because it is for handling the
107
- // old, soon-to-be-deprecated table syntax.
108
- return (0, find_external_references_1.deprecatedParseTableURI)(this.tableURI);
109
- }
110
- }
111
- exports.TableFunctionSource = TableFunctionSource;
112
113
  //# sourceMappingURL=table-source.js.map
@@ -275,6 +275,7 @@ type MessageParameterTypes = {
275
275
  'parameter-name-conflict': string;
276
276
  'parameter-shadowing-field': string;
277
277
  'invalid-import-url': string;
278
+ 'invalid-table-path': string;
278
279
  'no-translator-for-import': string;
279
280
  'name-conflict-on-selective-import': string;
280
281
  'selective-import-not-found': string;
@@ -61,6 +61,7 @@ const ast = __importStar(require("./ast"));
61
61
  const malloy_to_ast_1 = require("./malloy-to-ast");
62
62
  const parse_log_1 = require("./parse-log");
63
63
  const find_external_references_1 = require("./parse-tree-walkers/find-external-references");
64
+ const dialect_1 = require("../dialect");
64
65
  const zone_1 = require("./zone");
65
66
  const document_symbol_walker_1 = require("./parse-tree-walkers/document-symbol-walker");
66
67
  const document_completion_walker_1 = require("./parse-tree-walkers/document-completion-walker");
@@ -140,12 +141,9 @@ class ImportsAndTablesStep {
140
141
  }
141
142
  if (!this.parseReferences) {
142
143
  this.parseReferences = (0, find_external_references_1.findReferences)(that, parseReq.parse.tokenStream, parseReq.parse.root);
143
- for (const ref in this.parseReferences.tables) {
144
- that.root.schemaZone.reference(ref, {
145
- url: that.sourceURL,
146
- range: this.parseReferences.tables[ref].firstReference,
147
- });
148
- }
144
+ // Register connection dialects and imports immediately. Table
145
+ // references are deferred until dialects are resolved, because
146
+ // validating a table path requires knowing its dialect's grammar.
149
147
  for (const connName in this.parseReferences.connectionDialects) {
150
148
  that.root.connectionDialectZone.reference(connName, {
151
149
  url: that.sourceURL,
@@ -180,17 +178,49 @@ class ImportsAndTablesStep {
180
178
  return { timingInfo: parseReq.timingInfo };
181
179
  }
182
180
  let allMissing = {};
181
+ // Validate each table reference against its dialect's grammar (if
182
+ // the dialect is resolved) and register the canonical entry. Bad
183
+ // paths are silently dropped — the AST step re-validates and logs
184
+ // an error at the precise source range. Entries whose dialect
185
+ // isn't resolved yet are preserved unchanged and re-processed on a
186
+ // later step.
187
+ {
188
+ const refs = this.parseReferences.tables;
189
+ const canonical = {};
190
+ for (const rawKey in refs) {
191
+ const info = refs[rawKey];
192
+ let { tablePath } = info;
193
+ const dialectName = that.root.connectionDialectZone.get(info.connectionName);
194
+ if (dialectName !== undefined) {
195
+ const result = (0, dialect_1.getDialect)(dialectName).sqlValidateTableName(tablePath);
196
+ if (!result.ok)
197
+ continue;
198
+ tablePath = result.canonical;
199
+ }
200
+ const key = `${info.connectionName}:${tablePath}`;
201
+ canonical[key] = { ...info, tablePath };
202
+ that.root.schemaZone.reference(key, {
203
+ url: that.sourceURL,
204
+ range: info.firstReference,
205
+ });
206
+ }
207
+ this.parseReferences.tables = canonical;
208
+ }
183
209
  const missingTables = that.root.schemaZone.getUndefined();
184
210
  if (missingTables) {
185
211
  const tables = {};
186
212
  for (const key of missingTables) {
187
213
  const info = this.parseReferences.tables[key];
214
+ if (info === undefined)
215
+ continue;
188
216
  tables[key] = {
189
217
  connectionName: info.connectionName,
190
218
  tablePath: info.tablePath,
191
219
  };
192
220
  }
193
- allMissing = { tables };
221
+ if (Object.keys(tables).length > 0) {
222
+ allMissing = { tables };
223
+ }
194
224
  }
195
225
  const missingDialects = that.root.connectionDialectZone.getUndefined();
196
226
  if (missingDialects) {
@@ -4,27 +4,14 @@ import type { DocumentRange } from '../../model/malloy_types';
4
4
  import type { MalloyTranslation } from '../parse-malloy';
5
5
  type NeedImports = Record<string, DocumentRange>;
6
6
  type NeedTables = Record<string, {
7
- connectionName: string | undefined;
7
+ connectionName: string;
8
8
  tablePath: string;
9
9
  firstReference: DocumentRange;
10
10
  }>;
11
11
  type NeedConnectionDialects = Record<string, {
12
12
  firstReference: DocumentRange;
13
13
  }>;
14
- export declare function constructTableKey(connectionName: string | undefined, tablePath: string): string;
15
- /**
16
- * This function parses an old-style `tableURI` into a connection name and
17
- * table path. The name includes `deprecated` because it should only be used
18
- * in the (deprecated) old-style `table('conn:tab')` syntax. Any use of this
19
- * anywhere else is bad.
20
- * @param tableURI The sting that is passed into the `table('conn:tab')` syntax.
21
- * @returns A connection name and table path.
22
- * @deprecated
23
- */
24
- export declare function deprecatedParseTableURI(tableURI: string): {
25
- connectionName?: string;
26
- tablePath: string;
27
- };
14
+ export declare function constructTableKey(connectionName: string, tablePath: string): string;
28
15
  export interface FindReferencesData {
29
16
  tables: NeedTables;
30
17
  urls: NeedImports;
@@ -23,7 +23,6 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.constructTableKey = constructTableKey;
26
- exports.deprecatedParseTableURI = deprecatedParseTableURI;
27
26
  exports.findReferences = findReferences;
28
27
  const ParseTreeWalker_1 = require("antlr4ts/tree/ParseTreeWalker");
29
28
  const parse_utils_1 = require("../parse-utils");
@@ -70,6 +69,11 @@ class FindExternalReferences {
70
69
  const tablePath = getPlainString(pcx.tablePath());
71
70
  const reference = this.trans.rangeFromContext(pcx);
72
71
  this.registerTableReference(connId, tablePath, reference);
72
+ // Register a need for the connection's dialect so the validator in
73
+ // ImportsAndTablesStep can run against it.
74
+ if (!this.needConnectionDialects[connId]) {
75
+ this.needConnectionDialects[connId] = { firstReference: reference };
76
+ }
73
77
  }
74
78
  enterVirtualSource(pcx) {
75
79
  const connId = (0, parse_utils_1.getId)(pcx.connectionId());
@@ -87,28 +91,7 @@ class FindExternalReferences {
87
91
  }
88
92
  }
89
93
  function constructTableKey(connectionName, tablePath) {
90
- return connectionName === undefined
91
- ? tablePath
92
- : `${connectionName}:${tablePath}`;
93
- }
94
- /**
95
- * This function parses an old-style `tableURI` into a connection name and
96
- * table path. The name includes `deprecated` because it should only be used
97
- * in the (deprecated) old-style `table('conn:tab')` syntax. Any use of this
98
- * anywhere else is bad.
99
- * @param tableURI The sting that is passed into the `table('conn:tab')` syntax.
100
- * @returns A connection name and table path.
101
- * @deprecated
102
- */
103
- function deprecatedParseTableURI(tableURI) {
104
- const parts = tableURI.match(/^([^:]*):(.*)$/);
105
- if (parts) {
106
- const [, firstPart, secondPart] = parts;
107
- return { connectionName: firstPart, tablePath: secondPart };
108
- }
109
- else {
110
- return { tablePath: tableURI };
111
- }
94
+ return `${connectionName}:${tablePath}`;
112
95
  }
113
96
  function findReferences(trans, tokens, parseTree) {
114
97
  const finder = new FindExternalReferences(trans, tokens);
@@ -22,7 +22,7 @@ export interface ProblemResponse {
22
22
  export type FatalResponse = FinalResponse & ProblemResponse;
23
23
  export interface NeedSchemaData {
24
24
  tables: Record<string, {
25
- connectionName: string | undefined;
25
+ connectionName: string;
26
26
  tablePath: string;
27
27
  }>;
28
28
  }
@@ -129,7 +129,7 @@ exports.FilterCompilers = {
129
129
  // For some databases checking NULL combined with a boolean check
130
130
  // is faster than a COALESCE, for now, just detect if the expression
131
131
  // is just a column reference, and if so, don't use COALECSE.
132
- const quoteChar = d.sqlMaybeQuoteIdentifier('select')[0];
132
+ const quoteChar = d.sqlQuoteIdentifier('select')[0];
133
133
  const isColumn = x.match(`^[()${quoteChar}\\w.]+$`);
134
134
  if (isColumn) {
135
135
  if (bc.operator === 'true') {
@@ -107,12 +107,12 @@ class QueryModelImpl {
107
107
  const fieldNames = [];
108
108
  for (const f of ret.outputStruct.fields) {
109
109
  if ((0, malloy_types_1.isAtomic)(f)) {
110
- const quoted = q.parent.dialect.sqlMaybeQuoteIdentifier(f.name);
110
+ const quoted = q.parent.dialect.sqlQuoteIdentifier(f.name);
111
111
  fieldNames.push(quoted);
112
112
  }
113
113
  }
114
114
  // const fieldNames = getAtomicFields(ret.outputStruct).map(fieldDef =>
115
- // q.parent.dialect.sqlMaybeQuoteIdentifier(fieldDef.name)
115
+ // q.parent.dialect.sqlQuoteIdentifier(fieldDef.name)
116
116
  // );
117
117
  ret.lastStageName = stageWriter.addStage(q.parent.dialect.sqlFinalStage(ret.lastStageName, fieldNames));
118
118
  }
@@ -217,11 +217,11 @@ class QueryModelImpl {
217
217
  },
218
218
  ],
219
219
  };
220
- const fieldNameColumn = d.sqlMaybeQuoteIdentifier('fieldName');
221
- const fieldPathColumn = d.sqlMaybeQuoteIdentifier('fieldPath');
222
- const fieldValueColumn = d.sqlMaybeQuoteIdentifier('fieldValue');
223
- const fieldTypeColumn = d.sqlMaybeQuoteIdentifier('fieldType');
224
- const weightColumn = d.sqlMaybeQuoteIdentifier('weight');
220
+ const fieldNameColumn = d.sqlQuoteIdentifier('fieldName');
221
+ const fieldPathColumn = d.sqlQuoteIdentifier('fieldPath');
222
+ const fieldValueColumn = d.sqlQuoteIdentifier('fieldValue');
223
+ const fieldTypeColumn = d.sqlQuoteIdentifier('fieldType');
224
+ const weightColumn = d.sqlQuoteIdentifier('weight');
225
225
  // if we've compiled the SQL before use it otherwise
226
226
  let sqlPDT = this.exploreSearchSQLMap.get(explore);
227
227
  if (sqlPDT === undefined) {
@@ -517,14 +517,17 @@ class QueryQuery extends query_node_1.QueryField {
517
517
  var _a, _b, _c, _d;
518
518
  switch (qs.structDef.type) {
519
519
  case 'table':
520
- return this.parent.dialect.quoteTablePath(qs.structDef.tablePath);
520
+ // tablePath is canonical SQL — translator pre-validated.
521
+ return qs.structDef.tablePath;
521
522
  case 'virtual': {
522
523
  const virtualMap = (_a = qs.prepareResultOptions) === null || _a === void 0 ? void 0 : _a.virtualMap;
523
524
  const tablePath = (_b = virtualMap === null || virtualMap === void 0 ? void 0 : virtualMap.get(qs.structDef.connection)) === null || _b === void 0 ? void 0 : _b.get(qs.structDef.name);
524
525
  if (!tablePath) {
525
526
  throw new Error(`No virtual map entry for '${qs.structDef.name}' on connection '${qs.structDef.connection}'`);
526
527
  }
527
- return this.parent.dialect.quoteTablePath(tablePath);
528
+ // virtualMap entries are application-supplied — assumed already
529
+ // canonical SQL.
530
+ return tablePath;
528
531
  }
529
532
  case 'composite':
530
533
  // TODO: throw an error here; not simple because we call into this
@@ -533,7 +536,7 @@ class QueryQuery extends query_node_1.QueryField {
533
536
  case 'finalize':
534
537
  return qs.structDef.name;
535
538
  case 'sql_select':
536
- return `(${(0, sql_compiled_1.getCompiledSQL)(qs.structDef, (_c = qs.prepareResultOptions) !== null && _c !== void 0 ? _c : {}, path => this.parent.dialect.quoteTablePath(path), (query, opts) => {
539
+ return `(${(0, sql_compiled_1.getCompiledSQL)(qs.structDef, (_c = qs.prepareResultOptions) !== null && _c !== void 0 ? _c : {}, (query, opts) => {
537
540
  // Compile query to isolated SQL (not into parent's stageWriter)
538
541
  const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
539
542
  return ret.sql;
@@ -551,8 +554,9 @@ class QueryQuery extends query_node_1.QueryField {
551
554
  const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, fullRet.sql);
552
555
  const entry = buildManifest.entries[buildId];
553
556
  if (entry) {
554
- // Found in manifest - use persisted table
555
- return this.parent.dialect.quoteTablePath(entry.tableName);
557
+ // Found in manifest - use persisted table.
558
+ // entry.tableName comes from the manifest, assumed canonical.
559
+ return entry.tableName;
556
560
  }
557
561
  if (buildManifest.strict) {
558
562
  const base = `Persist source '${qs.structDef.sourceID}' not found in manifest (buildId: ${buildId})`;
@@ -631,7 +635,7 @@ class QueryQuery extends query_node_1.QueryField {
631
635
  }
632
636
  if (ji.makeUniqueKey) {
633
637
  const passKeys = this.generateSQLPassthroughKeys(qs);
634
- structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlMaybeQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
638
+ structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
635
639
  }
636
640
  let onCondition = '';
637
641
  if (qs.parent === undefined) {
@@ -764,7 +768,7 @@ class QueryQuery extends query_node_1.QueryField {
764
768
  if ((0, malloy_types_1.isBaseTable)(qs.structDef)) {
765
769
  if (ji.makeUniqueKey) {
766
770
  const passKeys = this.generateSQLPassthroughKeys(qs);
767
- structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlMaybeQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
771
+ structSQL = `(SELECT ${qs.dialect.sqlGenerateUUID()} as ${qs.dialect.sqlQuoteIdentifier('__distinct_key')}, x.* ${passKeys} FROM ${structSQL} as x)`;
768
772
  }
769
773
  s += `FROM ${structSQL} as ${ji.alias}\n`;
770
774
  }
@@ -846,7 +850,7 @@ class QueryQuery extends query_node_1.QueryField {
846
850
  o.push(`${fi.fieldUsage.resultIndex} ${f.dir || 'ASC'}`);
847
851
  }
848
852
  else if (this.parent.dialect.orderByClause === 'output_name') {
849
- o.push(`${this.parent.dialect.sqlMaybeQuoteIdentifier(f.field)} ${f.dir || 'ASC'}`);
853
+ o.push(`${this.parent.dialect.sqlQuoteIdentifier(f.field)} ${f.dir || 'ASC'}`);
850
854
  }
851
855
  else if (this.parent.dialect.orderByClause === 'expression') {
852
856
  const fieldExpr = fi.getSQL();
@@ -863,7 +867,7 @@ class QueryQuery extends query_node_1.QueryField {
863
867
  }
864
868
  else if (this.parent.dialect.orderByClause === 'output_name') {
865
869
  const orderingField = resultStruct.getFieldByNumber(f.field);
866
- o.push(`${this.parent.dialect.sqlMaybeQuoteIdentifier(orderingField.name)} ${f.dir || 'ASC'}`);
870
+ o.push(`${this.parent.dialect.sqlQuoteIdentifier(orderingField.name)} ${f.dir || 'ASC'}`);
867
871
  }
868
872
  else if (this.parent.dialect.orderByClause === 'expression') {
869
873
  const orderingField = resultStruct.getFieldByNumber(f.field);
@@ -887,7 +891,7 @@ class QueryQuery extends query_node_1.QueryField {
887
891
  const fields = [];
888
892
  for (const [name, field] of this.rootResult.allFields) {
889
893
  const fi = field;
890
- const sqlName = this.parent.dialect.sqlMaybeQuoteIdentifier(name);
894
+ const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
891
895
  if (fi.fieldUsage.type === 'result') {
892
896
  fields.push(` ${fi.generateExpression()} as ${sqlName}`);
893
897
  }
@@ -937,7 +941,7 @@ class QueryQuery extends query_node_1.QueryField {
937
941
  .map(o => `${o.pipelineSQL} as ${o.sqlFieldName}`)
938
942
  .join(',\n');
939
943
  const outputFields = outputPipelinedSQL.map(f => f.sqlFieldName);
940
- const allFields = Array.from(this.rootResult.allFields.keys()).map(f => this.parent.dialect.sqlMaybeQuoteIdentifier(f));
944
+ const allFields = Array.from(this.rootResult.allFields.keys()).map(f => this.parent.dialect.sqlQuoteIdentifier(f));
941
945
  const fields = allFields.filter(f => outputFields.indexOf(f) === -1);
942
946
  retSQL = `SELECT ${fields.length > 0 ? fields.join(', ') + ',' : ''} ${pipelinesSQL} FROM ${lastStageName}`;
943
947
  }
@@ -956,7 +960,7 @@ class QueryQuery extends query_node_1.QueryField {
956
960
  }
957
961
  const orderedFields = [...scalarFields, ...otherFields];
958
962
  for (const [name, fi] of orderedFields) {
959
- const outputName = this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${resultSet.groupSet}`);
963
+ const outputName = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}`);
960
964
  if (fi instanceof field_instance_1.FieldInstanceField) {
961
965
  if (fi.fieldUsage.type === 'result') {
962
966
  const exp = fi.getSQL();
@@ -975,7 +979,7 @@ class QueryQuery extends query_node_1.QueryField {
975
979
  });
976
980
  output.sql.push(outputFieldName);
977
981
  if (fi.f.fieldDef.type === 'number') {
978
- const outputNameString = this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${resultSet.groupSet}_string`);
982
+ const outputNameString = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}_string`);
979
983
  const outputFieldNameString = `__lateral_join_bag.${outputNameString}`;
980
984
  output.sql.push(outputFieldNameString);
981
985
  output.dimensionIndexes.push(output.fieldIndex++);
@@ -1086,7 +1090,7 @@ class QueryQuery extends query_node_1.QueryField {
1086
1090
  let r = result;
1087
1091
  while (r) {
1088
1092
  for (const name of r.fieldNames(fi => (0, query_node_1.isScalarField)(fi.f))) {
1089
- dimensions.push(this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${r.groupSet}`));
1093
+ dimensions.push(this.parent.dialect.sqlQuoteIdentifier(`${name}__${r.groupSet}`));
1090
1094
  }
1091
1095
  r = r.parent;
1092
1096
  }
@@ -1120,7 +1124,7 @@ class QueryQuery extends query_node_1.QueryField {
1120
1124
  orderingField = result.getFieldByNumber(ordering.field);
1121
1125
  }
1122
1126
  obSQL.push(' ' +
1123
- this.parent.dialect.sqlMaybeQuoteIdentifier(`${orderingField.name}__${result.groupSet}`) +
1127
+ this.parent.dialect.sqlQuoteIdentifier(`${orderingField.name}__${result.groupSet}`) +
1124
1128
  ` ${ordering.dir || 'ASC'}`);
1125
1129
  }
1126
1130
  // partition for a row number is the parent if it exists.
@@ -1225,7 +1229,7 @@ class QueryQuery extends query_node_1.QueryField {
1225
1229
  generateDepthNFields(depth, resultSet, output, stageWriter) {
1226
1230
  const groupsToMap = [];
1227
1231
  for (const [name, fi] of resultSet.allFields) {
1228
- const sqlFieldName = this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${resultSet.groupSet}`);
1232
+ const sqlFieldName = this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultSet.groupSet}`);
1229
1233
  if (fi instanceof field_instance_1.FieldInstanceField) {
1230
1234
  if (fi.fieldUsage.type === 'result') {
1231
1235
  if ((0, query_node_1.isScalarField)(fi.f)) {
@@ -1329,15 +1333,15 @@ class QueryQuery extends query_node_1.QueryField {
1329
1333
  const outputPipelinedSQL = [];
1330
1334
  const dimensionIndexes = [];
1331
1335
  for (const [name, fi] of this.rootResult.allFields) {
1332
- const sqlName = this.parent.dialect.sqlMaybeQuoteIdentifier(name);
1336
+ const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
1333
1337
  if (fi instanceof field_instance_1.FieldInstanceField) {
1334
1338
  if (fi.fieldUsage.type === 'result') {
1335
1339
  if ((0, query_node_1.isScalarField)(fi.f)) {
1336
- fieldsSQL.push(this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${this.rootResult.groupSet}`) + ` as ${sqlName}`);
1340
+ fieldsSQL.push(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`) + ` as ${sqlName}`);
1337
1341
  dimensionIndexes.push(fieldIndex++);
1338
1342
  }
1339
1343
  else if ((0, query_node_1.isBasicCalculation)(fi.f)) {
1340
- fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
1344
+ fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
1341
1345
  fieldIndex++;
1342
1346
  }
1343
1347
  }
@@ -1348,7 +1352,7 @@ class QueryQuery extends query_node_1.QueryField {
1348
1352
  fieldIndex++;
1349
1353
  }
1350
1354
  else if (fi.firstSegment.type === 'project') {
1351
- fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
1355
+ fieldsSQL.push(this.parent.dialect.sqlAnyValueLastTurtle(this.parent.dialect.sqlQuoteIdentifier(`${name}__${this.rootResult.groupSet}`), this.rootResult.groupSet, sqlName));
1352
1356
  fieldIndex++;
1353
1357
  }
1354
1358
  }
@@ -1375,7 +1379,7 @@ class QueryQuery extends query_node_1.QueryField {
1375
1379
  buildDialectFieldList(resultStruct) {
1376
1380
  const dialectFieldList = [];
1377
1381
  for (const [name, field] of resultStruct.allFields) {
1378
- const sqlName = this.parent.dialect.sqlMaybeQuoteIdentifier(name);
1382
+ const sqlName = this.parent.dialect.sqlQuoteIdentifier(name);
1379
1383
  //
1380
1384
  if (resultStruct.firstSegment.type === 'reduce' &&
1381
1385
  field instanceof field_instance_1.FieldInstanceResult) {
@@ -1390,7 +1394,7 @@ class QueryQuery extends query_node_1.QueryField {
1390
1394
  };
1391
1395
  dialectFieldList.push({
1392
1396
  typeDef: multiLineNest,
1393
- sqlExpression: this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
1397
+ sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
1394
1398
  rawName: name,
1395
1399
  sqlOutputName: sqlName,
1396
1400
  });
@@ -1404,7 +1408,7 @@ class QueryQuery extends query_node_1.QueryField {
1404
1408
  };
1405
1409
  dialectFieldList.push({
1406
1410
  typeDef: oneLineNest,
1407
- sqlExpression: this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
1411
+ sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
1408
1412
  rawName: name,
1409
1413
  sqlOutputName: sqlName,
1410
1414
  });
@@ -1415,7 +1419,7 @@ class QueryQuery extends query_node_1.QueryField {
1415
1419
  field.fieldUsage.type === 'result') {
1416
1420
  pushDialectField(dialectFieldList, {
1417
1421
  fieldDef: field.f.fieldDef,
1418
- sqlExpression: this.parent.dialect.sqlMaybeQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
1422
+ sqlExpression: this.parent.dialect.sqlQuoteIdentifier(`${name}__${resultStruct.groupSet}`),
1419
1423
  rawName: name,
1420
1424
  sqlOutputName: sqlName,
1421
1425
  });
@@ -1449,10 +1453,10 @@ class QueryQuery extends query_node_1.QueryField {
1449
1453
  else {
1450
1454
  orderingField = resultStruct.getFieldByNumber(ordering.field);
1451
1455
  }
1452
- const structField = this.parent.dialect.sqlMaybeQuoteIdentifier(orderingField.name);
1456
+ const structField = this.parent.dialect.sqlQuoteIdentifier(orderingField.name);
1453
1457
  if (resultStruct.firstSegment.type === 'reduce') {
1454
1458
  compiledOrderBy.push({
1455
- field: this.parent.dialect.sqlMaybeQuoteIdentifier(`${orderingField.name}__${resultStruct.groupSet}`),
1459
+ field: this.parent.dialect.sqlQuoteIdentifier(`${orderingField.name}__${resultStruct.groupSet}`),
1456
1460
  structField,
1457
1461
  dir: ordering.dir || 'asc',
1458
1462
  });
@@ -1636,12 +1640,12 @@ class QueryQueryIndexStage extends QueryQuery {
1636
1640
  generateSQL(stageWriter) {
1637
1641
  let measureSQL = 'COUNT(*)';
1638
1642
  const dialect = this.parent.dialect;
1639
- const fieldNameColumn = dialect.sqlMaybeQuoteIdentifier('fieldName');
1640
- const fieldPathColumn = dialect.sqlMaybeQuoteIdentifier('fieldPath');
1641
- const fieldValueColumn = dialect.sqlMaybeQuoteIdentifier('fieldValue');
1642
- const fieldTypeColumn = dialect.sqlMaybeQuoteIdentifier('fieldType');
1643
- const fieldRangeColumn = dialect.sqlMaybeQuoteIdentifier('fieldRange');
1644
- const weightColumn = dialect.sqlMaybeQuoteIdentifier('weight');
1643
+ const fieldNameColumn = dialect.sqlQuoteIdentifier('fieldName');
1644
+ const fieldPathColumn = dialect.sqlQuoteIdentifier('fieldPath');
1645
+ const fieldValueColumn = dialect.sqlQuoteIdentifier('fieldValue');
1646
+ const fieldTypeColumn = dialect.sqlQuoteIdentifier('fieldType');
1647
+ const fieldRangeColumn = dialect.sqlQuoteIdentifier('fieldRange');
1648
+ const weightColumn = dialect.sqlQuoteIdentifier('weight');
1645
1649
  const measureName = this.firstSegment.weightMeasure;
1646
1650
  if (measureName) {
1647
1651
  measureSQL = this.rootResult.getField(measureName).generateExpression();
@@ -1819,7 +1823,7 @@ class QueryQueryRaw extends QueryQuery {
1819
1823
  if (this.parent.structDef.type !== 'sql_select') {
1820
1824
  throw new Error('Invalid struct for QueryQueryRaw, currently only supports SQL');
1821
1825
  }
1822
- return stageWriter.addStage((0, sql_compiled_1.getCompiledSQL)(this.parent.structDef, (_a = this.parent.prepareResultOptions) !== null && _a !== void 0 ? _a : {}, path => this.parent.dialect.quoteTablePath(path), (query, opts) => {
1826
+ return stageWriter.addStage((0, sql_compiled_1.getCompiledSQL)(this.parent.structDef, (_a = this.parent.prepareResultOptions) !== null && _a !== void 0 ? _a : {}, (query, opts) => {
1823
1827
  // Compile query to isolated SQL (not into parent's stageWriter)
1824
1828
  const ret = this.compileQueryToStages(query, opts !== null && opts !== void 0 ? opts : {}, undefined, false);
1825
1829
  return ret.sql;
@@ -13,17 +13,15 @@ export type CompileQueryCallback = (query: Query, opts?: PrepareResultOptions) =
13
13
  *
14
14
  * @param src The SQLSourceDef to compile
15
15
  * @param opts PrepareResultOptions with buildManifest and connectionDigests
16
- * @param quoteTablePath Dialect function to safely quote a table path
17
16
  * @param compileQuery Callback to compile a Query to SQL
18
17
  */
19
- export declare function getCompiledSQL(src: SQLSourceDef, opts: PrepareResultOptions, quoteTablePath: (path: string) => string, compileQuery: CompileQueryCallback): string;
18
+ export declare function getCompiledSQL(src: SQLSourceDef, opts: PrepareResultOptions, compileQuery: CompileQueryCallback): string;
20
19
  /**
21
20
  * Get the SQL for a PersistableSourceDef.
22
21
  *
23
22
  * @param source The persistable source to compile
24
- * @param quoteTablePath Dialect function to quote table paths
25
23
  * @param compileQuery Callback to compile a Query to SQL
26
24
  * @param opts Optional - if provided with manifest, nested sources may be substituted.
27
25
  * Omit for "full SQL" (e.g., when computing BuildID).
28
26
  */
29
- export declare function getSourceSQL(source: PersistableSourceDef, quoteTablePath: (path: string) => string, compileQuery: CompileQueryCallback, opts?: PrepareResultOptions): string;
27
+ export declare function getSourceSQL(source: PersistableSourceDef, compileQuery: CompileQueryCallback, opts?: PrepareResultOptions): string;
@@ -16,10 +16,9 @@ const source_def_utils_1 = require("./source_def_utils");
16
16
  *
17
17
  * @param src The SQLSourceDef to compile
18
18
  * @param opts PrepareResultOptions with buildManifest and connectionDigests
19
- * @param quoteTablePath Dialect function to safely quote a table path
20
19
  * @param compileQuery Callback to compile a Query to SQL
21
20
  */
22
- function getCompiledSQL(src, opts, quoteTablePath, compileQuery) {
21
+ function getCompiledSQL(src, opts, compileQuery) {
23
22
  // If no segments, just return the pre-computed selectStr
24
23
  if (!src.selectSegments || src.selectSegments.length === 0) {
25
24
  return src.selectStr;
@@ -27,42 +26,43 @@ function getCompiledSQL(src, opts, quoteTablePath, compileQuery) {
27
26
  // Expand each segment
28
27
  const parts = [];
29
28
  for (const segment of src.selectSegments) {
30
- parts.push(expandSegment(segment, opts, quoteTablePath, compileQuery));
29
+ parts.push(expandSegment(segment, opts, compileQuery));
31
30
  }
32
31
  return parts.join('');
33
32
  }
34
33
  /**
35
34
  * Expand a single SQLPhraseSegment to SQL.
36
35
  */
37
- function expandSegment(segment, opts, quoteTablePath, compileQuery) {
36
+ function expandSegment(segment, opts, compileQuery) {
38
37
  // Plain SQL string
39
38
  if ((0, malloy_types_1.isSegmentSQL)(segment)) {
40
39
  return segment.sql;
41
40
  }
42
41
  // PersistableSourceDef (sql_select or query_source)
43
42
  if ((0, malloy_types_1.isSegmentSource)(segment)) {
44
- return expandPersistableSource(segment, opts, quoteTablePath, compileQuery);
43
+ return expandPersistableSource(segment, opts, compileQuery);
45
44
  }
46
45
  // Query segment
47
- return expandQuery(segment, opts, quoteTablePath, compileQuery);
46
+ return expandQuery(segment, opts, compileQuery);
48
47
  }
49
48
  /**
50
49
  * Expand a PersistableSourceDef, checking manifest for pre-built table.
51
50
  * Always returns a subquery form: (SELECT * FROM table) or (inline SQL)
52
51
  */
53
- function expandPersistableSource(source, opts, quoteTablePath, compileQuery) {
52
+ function expandPersistableSource(source, opts, compileQuery) {
54
53
  const { buildManifest, connectionDigests } = opts;
55
54
  // Try manifest lookup if we have the required info (only for persistent sources)
56
55
  if (buildManifest && connectionDigests && source.persistent) {
57
56
  const connDigest = (0, malloy_types_1.safeRecordGet)(connectionDigests, source.connection);
58
57
  if (connDigest) {
59
58
  // Get the SQL for this source to compute BuildID (no opts = full SQL)
60
- const sql = getSourceSQL(source, quoteTablePath, compileQuery);
59
+ const sql = getSourceSQL(source, compileQuery);
61
60
  const buildId = (0, source_def_utils_1.mkBuildID)(connDigest, sql);
62
61
  const entry = buildManifest.entries[buildId];
63
62
  if (entry) {
64
- // Found in manifest - substitute with subquery from persisted table
65
- return `(SELECT * FROM ${quoteTablePath(entry.tableName)})`;
63
+ // Found in manifest - substitute with subquery from persisted table.
64
+ // entry.tableName is canonical SQL, supplied by the manifest builder.
65
+ return `(SELECT * FROM ${entry.tableName})`;
66
66
  }
67
67
  // Not in manifest
68
68
  if (buildManifest.strict) {
@@ -74,13 +74,13 @@ function expandPersistableSource(source, opts, quoteTablePath, compileQuery) {
74
74
  }
75
75
  }
76
76
  // No manifest or not found - expand inline as subquery
77
- const sql = getSourceSQL(source, quoteTablePath, compileQuery, opts);
77
+ const sql = getSourceSQL(source, compileQuery, opts);
78
78
  return `(${sql})`;
79
79
  }
80
80
  /**
81
81
  * Expand a Query segment.
82
82
  */
83
- function expandQuery(query, opts, _quoteTablePath, compileQuery) {
83
+ function expandQuery(query, opts, compileQuery) {
84
84
  // Set isPartialQuery so CTEs aren't used (they can't be nested in subqueries)
85
85
  const sql = compileQuery(query, { ...opts, isPartialQuery: true });
86
86
  return `(${sql})`;
@@ -89,15 +89,14 @@ function expandQuery(query, opts, _quoteTablePath, compileQuery) {
89
89
  * Get the SQL for a PersistableSourceDef.
90
90
  *
91
91
  * @param source The persistable source to compile
92
- * @param quoteTablePath Dialect function to quote table paths
93
92
  * @param compileQuery Callback to compile a Query to SQL
94
93
  * @param opts Optional - if provided with manifest, nested sources may be substituted.
95
94
  * Omit for "full SQL" (e.g., when computing BuildID).
96
95
  */
97
- function getSourceSQL(source, quoteTablePath, compileQuery, opts) {
96
+ function getSourceSQL(source, compileQuery, opts) {
98
97
  if (source.type === 'sql_select') {
99
98
  // Recursive call for nested sql_select
100
- return getCompiledSQL(source, opts !== null && opts !== void 0 ? opts : {}, quoteTablePath, compileQuery);
99
+ return getCompiledSQL(source, opts !== null && opts !== void 0 ? opts : {}, compileQuery);
101
100
  }
102
101
  // query_source - compile the inner query
103
102
  return compileQuery(source.query, opts);