@sap/cds-compiler 3.3.2 → 3.4.2

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 (76) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/bin/cdsc.js +3 -1
  3. package/doc/CHANGELOG_BETA.md +17 -0
  4. package/lib/api/main.js +147 -18
  5. package/lib/api/validate.js +8 -3
  6. package/lib/base/dictionaries.js +6 -6
  7. package/lib/base/keywords.js +104 -0
  8. package/lib/base/message-registry.js +137 -68
  9. package/lib/base/messages.js +59 -48
  10. package/lib/base/model.js +1 -0
  11. package/lib/checks/actionsFunctions.js +1 -1
  12. package/lib/checks/cdsPersistence.js +1 -1
  13. package/lib/checks/checkForTypes.js +13 -8
  14. package/lib/checks/defaultValues.js +3 -1
  15. package/lib/checks/elements.js +1 -1
  16. package/lib/checks/parameters.js +4 -2
  17. package/lib/checks/queryNoDbArtifacts.js +1 -1
  18. package/lib/checks/sql-snippets.js +12 -10
  19. package/lib/checks/validator.js +14 -4
  20. package/lib/compiler/assert-consistency.js +8 -7
  21. package/lib/compiler/checks.js +30 -20
  22. package/lib/compiler/define.js +89 -25
  23. package/lib/compiler/extend.js +33 -28
  24. package/lib/compiler/finalize-parse-cdl.js +14 -9
  25. package/lib/compiler/populate.js +30 -8
  26. package/lib/compiler/propagator.js +23 -28
  27. package/lib/compiler/resolve.js +11 -5
  28. package/lib/compiler/shared.js +66 -48
  29. package/lib/compiler/tweak-assocs.js +2 -3
  30. package/lib/compiler/utils.js +11 -0
  31. package/lib/edm/annotations/genericTranslation.js +7 -4
  32. package/lib/edm/csn2edm.js +1 -1
  33. package/lib/gen/language.checksum +1 -1
  34. package/lib/gen/language.interp +1 -1
  35. package/lib/gen/languageParser.js +3565 -3544
  36. package/lib/json/csnVersion.js +13 -13
  37. package/lib/json/from-csn.js +140 -158
  38. package/lib/json/to-csn.js +23 -5
  39. package/lib/language/.eslintrc.json +4 -0
  40. package/lib/language/antlrParser.js +7 -10
  41. package/lib/language/docCommentParser.js +1 -2
  42. package/lib/language/errorStrategy.js +54 -27
  43. package/lib/language/genericAntlrParser.js +115 -84
  44. package/lib/language/language.g4 +29 -25
  45. package/lib/language/multiLineStringParser.js +75 -63
  46. package/lib/main.js +1 -0
  47. package/lib/model/csnRefs.js +4 -3
  48. package/lib/model/csnUtils.js +39 -7
  49. package/lib/model/sortViews.js +7 -3
  50. package/lib/modelCompare/compare.js +49 -15
  51. package/lib/modelCompare/filter.js +83 -0
  52. package/lib/optionProcessor.js +5 -1
  53. package/lib/render/manageConstraints.js +9 -5
  54. package/lib/render/toCdl.js +120 -62
  55. package/lib/render/toHdbcds.js +1 -1
  56. package/lib/render/toSql.js +6 -2
  57. package/lib/render/utils/common.js +7 -0
  58. package/lib/sql-identifier.js +7 -0
  59. package/lib/transform/db/assertUnique.js +27 -38
  60. package/lib/transform/db/expansion.js +11 -4
  61. package/lib/transform/db/temporal.js +3 -1
  62. package/lib/transform/db/transformExists.js +7 -1
  63. package/lib/transform/db/views.js +42 -13
  64. package/lib/transform/draft/db.js +2 -2
  65. package/lib/transform/forOdataNew.js +7 -3
  66. package/lib/transform/forRelationalDB.js +12 -6
  67. package/lib/transform/localized.js +1 -1
  68. package/lib/transform/odata/typesExposure.js +2 -1
  69. package/lib/transform/parseExpr.js +245 -0
  70. package/lib/transform/transformUtilsNew.js +23 -14
  71. package/lib/transform/translateAssocsToJoins.js +12 -12
  72. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  73. package/lib/utils/term.js +5 -5
  74. package/package.json +2 -2
  75. package/share/messages/message-explanations.json +1 -1
  76. package/share/messages/{syntax-expected-integer.md → syntax-expecting-integer.md} +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@
7
7
  Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
 
10
+ ## Version 3.4.2 - 2022-11-11
11
+
12
+ ### Fixed
13
+
14
+ - Don't propagate `@cds.external` (The CDS Importer adds `@cds.external` for all
15
+ imported definitions beginning with cds-dk@6.3.0, see CAP release log).
16
+ - for.odata: Ignore all `@cds.external` definitions.
17
+ - to.sql: For sql dialect `h2`, don't turn a Decimal with length 0 into a Decfloat.
18
+ - Extending a projection with an aspect could result in incorrect auto-redirection.
19
+ - Annotations of aspects were not properly propagated to projections under some order-specific circumstances.
20
+
21
+ ## Version 3.4.0 - 2022-10-26
22
+
23
+ ### Added
24
+
25
+ - to.sql: Add support for sql dialect `h2`, which renders SQL for H2 2.x.
26
+ - Projections can now be extended by annotation-only aspects, e.g. `extend P with MyAspect;`.
27
+
28
+ ### Fixed
29
+
30
+ - Properly report an error for bare `$self` references,
31
+ except in the `on` condition of unmanaged associations.
32
+ - Do not dump with references to CDS variables like `$now` in `expand`/`inline`.
33
+ - Properly report an error when trying to `cast` a column to an association.
34
+ - to.cdl: Identifiers that are always keywords in special functions are now escaped.
35
+ - to.edm(x):
36
+ + Nested annotation was not applied if outer annotation has value zero.
37
+ + Fix `AppliesTo=ComplexType, TypeDefinition` term definition directive.
38
+ - to.sql/hdi/hdbcds:
39
+ + Properly report an error for `exists` with `$self.managed-association`
40
+ + For sql dialect `hana`, add an implicit alias when using `:param` in the select list
41
+ + Handle `$self` and magic variables during expansion of nested projections
42
+
10
43
  ## Version 3.3.2 - 2022-09-30
11
44
 
12
45
  ### Fixed
package/bin/cdsc.js CHANGED
@@ -153,7 +153,9 @@ function cdsc_main() {
153
153
  cmdLine.args.files = [ cmdLine.args.file ];
154
154
  }
155
155
  else if (cmdLine.command === 'parseOnly') {
156
+ // Remap command and command-specific options.
156
157
  cmdLine.command = 'toCsn';
158
+ cmdLine.options.toCsn = cmdLine.options.parseOnly;
157
159
  cmdLine.options.parseOnly = true;
158
160
  cmdLine.args.files = [ cmdLine.args.file ];
159
161
  }
@@ -521,7 +523,7 @@ function executeCommandLine(command, options, args) {
521
523
  log(); // newline
522
524
  });
523
525
  if (options.showMessageId && hasAtLeastOneExplanation)
524
- log(`${colorTerm.help('help')}: Messages marked with '…' have an explanation text. Use \`cdsc explain <message-id>\` for a more detailed error description.`);
526
+ log(`${colorTerm.asHelp('help')}: Messages marked with '…' have an explanation text. Use \`cdsc explain <message-id>\` for a more detailed error description.`);
525
527
  }
526
528
  return model;
527
529
  }
@@ -8,6 +8,23 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
  **Don't use `beta` fixes, changes and features in productive mode.**
10
10
 
11
+ ## Version 3.4.0 - 2022-MM-DD
12
+
13
+ ### Added `aspectWithoutElements`
14
+
15
+ - Aspects can now be defined without elements, e.g. `aspect A;`. This allows the definition of annotation-only aspects.
16
+ Views can be extended by such an aspect. For example:
17
+ ```cds
18
+ entity V as projection on SomeEntity;
19
+ @anno aspect A;
20
+ extend V with A;
21
+ ```
22
+
23
+ ### Added `sqlMigration`
24
+
25
+ - to.sql.migration: Offer something similar to to.hdi.migration, but for general SQL. Don't offer a complete out-of-the-box schema evolution, instead only
26
+ allow lossless, easy to revert actions like adding a column or extending a string length.
27
+
11
28
  ## Version 3.3.0 - 2022-09-29
12
29
 
13
30
  ### Removed `nestedProjections`
package/lib/api/main.js CHANGED
@@ -12,6 +12,7 @@ const forOdataNew = lazyload('../transform/forOdataNew.js');
12
12
  const toSql = lazyload('../render/toSql');
13
13
  const toCdl = require('../render/toCdl');
14
14
  const modelCompare = lazyload('../modelCompare/compare');
15
+ const diffFilter = lazyload('../modelCompare/filter');
15
16
  const sortViews = lazyload('../model/sortViews');
16
17
  const csnUtils = lazyload('../model/csnUtils');
17
18
  const timetrace = lazyload('../utils/timetrace');
@@ -33,7 +34,7 @@ const { cloneCsnNonDict } = require('../model/csnUtils');
33
34
  const { toHdbcdsSource } = require('../render/toHdbcds');
34
35
  const { ModelError } = require('../base/error');
35
36
  const { forEach, forEachKey } = require('../utils/objectUtils');
36
- const { checkRemovedDeprecatedFlags } = require('../base/model');
37
+ const { checkRemovedDeprecatedFlags, isBetaEnabled } = require('../base/model');
37
38
  const { csn2edm, csn2edmAll } = require('../edm/csn2edm');
38
39
 
39
40
  const relevantGeneralOptions = [ /* for future generic options */ ];
@@ -92,13 +93,17 @@ function checkPreTransformedCsn(csn, options, relevantOptionNames, warnAboutMism
92
93
  const { error, warning, throwWithAnyError } = messages.makeMessageFunction(csn, options, module);
93
94
 
94
95
  for (const name of relevantOptionNames ) {
95
- if (options[name] !== csn.meta.options[name])
96
- error('wrong-pretransformed-csn', null, {}, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
96
+ if (options[name] !== csn.meta.options[name]) {
97
+ error('wrong-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
98
+ 'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
99
+ }
97
100
  }
98
101
 
99
102
  for (const name of warnAboutMismatch ) {
100
- if (options[name] !== csn.meta.options[name])
101
- warning('options-mismatch-pretransformed-csn', null, {}, `Expected pre-processed CSN to have option "${ name }" set to "${ options[name] }". Found: "${ csn.meta.options[name] }"`);
103
+ if (options[name] !== csn.meta.options[name]) {
104
+ warning('options-mismatch-pretransformed-csn', null, { prop: name, value: options[name], othervalue: csn.meta.options[name] },
105
+ 'Expected pre-processed CSN to have option $(PROP) set to $(VALUE). Found: $(OTHERVALUE)');
106
+ }
102
107
  }
103
108
 
104
109
  throwWithAnyError();
@@ -361,6 +366,119 @@ function remapName(key, csn, filter = () => true) {
361
366
  return key;
362
367
  }
363
368
 
369
+ /**
370
+ * Return all changes in artifacts between two given models.
371
+ * Note: Only supports changes in artifacts compiled/rendered as db-CSN/SQL.
372
+ *
373
+ * @param {CSN.Model} csn A clean input CSN representing the desired "after-image"
374
+ * @param {HdiOptions} options Options
375
+ * @param {CSN.Model} beforeImage A db-transformed CSN representing the "before-image", or null in case no such image
376
+ * is known, i.e. for the very first migration step
377
+ * @returns {object} An object with three properties:
378
+ * - afterImage: A db-transformed CSN representing the "after-image"
379
+ * - drops: An array of SQL statements to drop views/tables
380
+ * - createsAndAlters: An array of SQL statements to ALTER/CREATE tables/views
381
+ */
382
+ function sqlMigration(csn, options, beforeImage) {
383
+ const internalOptions = prepareOptions.to.sql(options);
384
+ const { error, throwWithError } = messages.makeMessageFunction(csn, options, 'to.sql.migration');
385
+
386
+ if (!isBetaEnabled(internalOptions, 'sqlMigration'))
387
+ throw new Error('Function `to.sql.migration` requires beta-flag `sqlMigration`');
388
+
389
+ // Prepare after-image.
390
+ const afterImage = forSql(csn, options);
391
+ // Compare both images.
392
+ const diff = modelCompare.compareModels(beforeImage || afterImage, afterImage, internalOptions);
393
+ const diffFilterObj = diffFilter[options.sqlDialect];
394
+
395
+ if (diffFilterObj) {
396
+ diff.extensions.forEach(ex => diffFilterObj.extension(ex, error));
397
+ diff.migrations.forEach(migration => diffFilterObj.migration(migration, error));
398
+ Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
399
+ }
400
+
401
+ const drops = {
402
+ creates: {},
403
+ final: Object.entries(diff.deletions).reduce((previous, [ name, artifact ]) => {
404
+ previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ artifact['@cds.persistence.name'] };`;
405
+ return previous;
406
+ }, {}),
407
+ };
408
+
409
+ const cleanup = [];
410
+ // Delete artifacts that are already present in csn
411
+ if (beforeImage?.definitions) {
412
+ Object.keys(beforeImage.definitions).forEach((artifactName) => {
413
+ const beforeArtifact = beforeImage.definitions[artifactName];
414
+ const diffArtifact = diff.definitions[artifactName];
415
+ // TODO: exists, abstract? isPersistedOnDb?
416
+ if (diffArtifact && diffArtifact['@cds.persistence.name'] && !diffArtifact['@cds.persistence.skip'] &&
417
+ (diffArtifact.query || diffArtifact.projection) &&
418
+ (diffArtifact[modelCompare.isChanged] === true || // we know it changed because we compared two views
419
+ diffArtifact[modelCompare.isChanged] === undefined)) { // if it was removed in the after, then we don't have the flag
420
+ drops.creates[artifactName] = `DROP VIEW ${ diffArtifact['@cds.persistence.name'] };`;
421
+ } // TODO: What happens with a changed kind -> entity becomes a view?
422
+ else if (diffArtifact &&
423
+ diffArtifact['@cds.persistence.skip'] !== true &&
424
+ diffArtifact.kind === beforeArtifact.kind && // detect action -> entity
425
+ csnUtils.isPersistedAsView(diffArtifact) === csnUtils.isPersistedAsView(beforeArtifact) // detect view -> entity
426
+ ) { // don't render again, but need info for primary key extension
427
+ diffArtifact['@cds.persistence.skip'] = true;
428
+ cleanup.push(() => delete diffArtifact['@cds.persistence.skip']);
429
+ }
430
+ });
431
+ }
432
+
433
+ // Convert the diff to SQL.
434
+ if (!internalOptions.beta)
435
+ internalOptions.beta = {};
436
+
437
+ internalOptions.beta.sqlExtensions = true;
438
+
439
+ // eslint-disable-next-line no-unused-vars
440
+ const { deletions, migrations, ...hdbkinds } = toSql.toSqlDdl(diff, internalOptions);
441
+
442
+ cleanup.forEach(fn => fn());
443
+ // TODO: Handle `ADD CONSTRAINT` etc!
444
+ const sortOrder = sortViews({ sql: {}, csn: afterImage });
445
+
446
+ const dropSqls = [];
447
+ const createAndAlterSqls = [];
448
+ // Turn the structured result into just a flat dictionary of "artifact name": "sql"
449
+ const flatSqlDict = Object.values(hdbkinds).reduce((prev, curr) => {
450
+ forEach(curr, (name, value) => {
451
+ prev[name] = value;
452
+ });
453
+ return prev;
454
+ }, Object.create(null));
455
+
456
+ // Sort all the SQL statements according to the overall order
457
+ for (const { name } of sortOrder) {
458
+ if (drops.final[name])
459
+ dropSqls.push(drops.final[name]);
460
+ else if (drops.creates[name])
461
+ dropSqls.push(drops.creates[name]);
462
+
463
+ // No else-if, since we have drop-creates for views!
464
+ if (flatSqlDict[name])
465
+ createAndAlterSqls.push(flatSqlDict[name]);
466
+ else if (migrations[name])
467
+ createAndAlterSqls.push(...migrations[name].map(m => m.sql));
468
+ }
469
+
470
+ // We need to drop the things without dependants first - so inversely sorted
471
+ dropSqls.reverse();
472
+
473
+ throwWithError();
474
+
475
+ return {
476
+ afterImage,
477
+ drops: dropSqls,
478
+ createsAndAlters: createAndAlterSqls,
479
+ };
480
+ }
481
+
364
482
  /**
365
483
  * Return all changes in artifacts between two given models.
366
484
  * Note: Only supports changes in entities (not views etc.) compiled/rendered as HANA-CSN/SQL.
@@ -369,17 +487,7 @@ function remapName(key, csn, filter = () => true) {
369
487
  * @param {HdiOptions} options Options
370
488
  * @param {CSN.Model} beforeImage A HANA-transformed CSN representing the "before-image", or null in case no such image
371
489
  * is known, i.e. for the very first migration step
372
- * @returns {object} - afterImage: The desired after-image in HANA-CSN format
373
- * - definitions: An array of objects with all artifacts in the after-image. Each object specifies
374
- * the artifact filename, the suffix, and the corresponding SQL statement to create
375
- * the artifact.
376
- * - deletions: An array of objects with the deleted artifacts. Each object specifies the artifact
377
- * filename and the suffix.
378
- * - migrations: An array of objects with the changed (migrated) artifacts. Each object specifies the
379
- * artifact filename, the suffix, and the changeset (an array of changes, each specifying
380
- * whether it incurs potential data loss, and its respective SQL statement(s), with
381
- * multiple statements concatenated as a multi-line string in case the change e.g.
382
- * consists of a column drop and add).
490
+ * @returns {migration} The migration result
383
491
  */
384
492
  function hdiMigration(csn, options, beforeImage) {
385
493
  const internalOptions = prepareOptions.to.hdi(options);
@@ -387,11 +495,14 @@ function hdiMigration(csn, options, beforeImage) {
387
495
  // Prepare after-image.
388
496
  const afterImage = forHdi(csn, options);
389
497
 
390
- // Compare both images.
391
498
  const diff = modelCompare.compareModels(beforeImage || afterImage, afterImage, internalOptions);
392
499
 
393
500
  // Convert the diff to SQL.
394
- internalOptions.forHana = true; // Make it pass the SQL rendering
501
+ if (!internalOptions.beta)
502
+ internalOptions.beta = {};
503
+
504
+ internalOptions.beta.sqlExtensions = true;
505
+
395
506
  const { deletions, migrations, ...hdbkinds } = toSql.toSqlDdl(diff, internalOptions);
396
507
 
397
508
  return {
@@ -449,6 +560,8 @@ function createSqlMigrations(migrations, afterImage) {
449
560
 
450
561
  hdi.migration = hdiMigration;
451
562
 
563
+ sql.migration = sqlMigration;
564
+
452
565
  /**
453
566
  * Process the given CSN into HDBCDS artifacts.
454
567
  *
@@ -922,3 +1035,19 @@ function lazyload(moduleName) {
922
1035
  *
923
1036
  * @typedef {object} edms
924
1037
  */
1038
+
1039
+ /**
1040
+ * - afterImage: The desired after-image in db-CSN format
1041
+ * - definitions: An array of objects with all artifacts in the after-image. Each object specifies
1042
+ * the artifact filename, the suffix, and the corresponding SQL statement to create
1043
+ * the artifact.
1044
+ * - deletions: An array of objects with the deleted artifacts. Each object specifies the artifact
1045
+ * filename and the suffix.
1046
+ * - migrations: An array of objects with the changed (migrated) artifacts. Each object specifies the
1047
+ * artifact filename, the suffix, and the changeset (an array of changes, each specifying
1048
+ * whether it incurs potential data loss, and its respective SQL statement(s), with
1049
+ * multiple statements concatenated as a multi-line string in case the change e.g.
1050
+ * consists of a column drop and add).
1051
+ *
1052
+ * @typedef {object} migration
1053
+ */
@@ -78,7 +78,7 @@ const validators = {
78
78
  expected: () => 'type array',
79
79
  found: val => `type ${ typeof val }`,
80
80
  },
81
- sqlDialect: generateStringValidator([ 'sqlite', 'hana', 'plain', 'postgres' ]),
81
+ sqlDialect: generateStringValidator([ 'sqlite', 'hana', 'plain', 'postgres', 'h2' ]),
82
82
  sqlMapping: generateStringValidator([ 'plain', 'quoted', 'hdbcds' ]),
83
83
  odataVersion: generateStringValidator([ 'v2', 'v4' ]),
84
84
  odataFormat: generateStringValidator([ 'flat', 'structured' ]),
@@ -161,8 +161,13 @@ function validate(options, moduleName, customValidators = {}, combinationValidat
161
161
  forEach(options, (optionName, optionValue) => {
162
162
  const validator = customValidators[optionName] || validators[optionName] || booleanValidator;
163
163
 
164
- if (!validator.validate(optionValue))
165
- error('invalid-option', null, {}, `Expected option "${ optionName }" to have "${ validator.expected(optionValue) }". Found: "${ validator.found(optionValue) }"`);
164
+ if (!validator.validate(optionValue)) {
165
+ error('invalid-option', null, {
166
+ prop: optionName,
167
+ value: validator.expected(optionValue),
168
+ othervalue: validator.found(optionValue),
169
+ }, 'Expected option $(PROP) to have $(VALUE). Found: $(OTHERVALUE)');
170
+ }
166
171
  });
167
172
  throwWithAnyError();
168
173
  }
@@ -19,7 +19,7 @@ function dictAdd( dict, name, entry, duplicateCallback ) {
19
19
  duplicateCallback( name, found.name.location, found );
20
20
  }
21
21
  found.$duplicates.push( entry );
22
- if (Array.isArray(entry.$duplicates))
22
+ if (Array.isArray( entry.$duplicates ))
23
23
  found.$duplicates.push( ...entry.$duplicates )
24
24
  else if (duplicateCallback && name) // do not complain with empty name ''
25
25
  duplicateCallback( name, entry.name.location, entry );
@@ -31,7 +31,7 @@ function dictForEach( dict, callback ) {
31
31
  // TODO: probably define an extra dictForEachArray()
32
32
  for (const name in dict) {
33
33
  const entry = dict[name];
34
- if (Array.isArray(entry)) {
34
+ if (Array.isArray( entry )) {
35
35
  entry.forEach( callback );
36
36
  }
37
37
  else {
@@ -53,8 +53,8 @@ function dictAddArray( dict, name, entry, messageCallback ) {
53
53
  dict[name] = entry; // also ok if array (redefined)
54
54
  return entry;
55
55
  }
56
- if (Array.isArray(entry)) {
57
- if (Array.isArray(found)) {
56
+ if (Array.isArray( entry )) {
57
+ if (Array.isArray( found )) {
58
58
  dict[name] = [ ...found, ...entry ];
59
59
  }
60
60
  else {
@@ -65,7 +65,7 @@ function dictAddArray( dict, name, entry, messageCallback ) {
65
65
  }
66
66
  }
67
67
  else {
68
- if (Array.isArray(found)) {
68
+ if (Array.isArray( found )) {
69
69
  dict[name] = [ ...found, entry ];
70
70
  }
71
71
  else {
@@ -84,7 +84,7 @@ function dictAddArray( dict, name, entry, messageCallback ) {
84
84
  // Push `entry` to the array value with key `name` in the dictionary `dict`.
85
85
  function pushToDict( dict, name, entry ) {
86
86
  if (dict[name])
87
- dict[name].push(entry);
87
+ dict[name].push( entry );
88
88
  else
89
89
  dict[name] = [entry];
90
90
  }
@@ -842,5 +842,109 @@ module.exports = {
842
842
  'WHERE',
843
843
  'WINDOW',
844
844
  'WITH'
845
+ ],
846
+ // H2 keywords, used for smart quoting in to-sql.plain.postgres
847
+ // Taken from http://www.h2database.com/html/advanced.html#keywords
848
+ h2: [
849
+ 'ALL',
850
+ 'AND',
851
+ 'ANY',
852
+ 'ARRAY',
853
+ 'AS',
854
+ 'ASYMMETRIC',
855
+ 'AUTHORIZATION',
856
+ 'BETWEEN',
857
+ 'BOTH',
858
+ 'CASE',
859
+ 'CAST',
860
+ 'CHECK',
861
+ 'CONSTRAINT',
862
+ 'CROSS',
863
+ 'CURRENT_CATALOG',
864
+ 'CURRENT_DATE',
865
+ 'CURRENT_PATH',
866
+ 'CURRENT_ROLE',
867
+ 'CURRENT_SCHEMA',
868
+ 'CURRENT_TIME',
869
+ 'CURRENT_TIMESTAMP',
870
+ 'CURRENT_USER',
871
+ 'DAY',
872
+ 'DEFAULT',
873
+ 'DISTINCT',
874
+ 'ELSE',
875
+ 'END',
876
+ 'EXCEPT',
877
+ 'EXISTS',
878
+ 'FALSE',
879
+ 'FETCH',
880
+ 'FOR',
881
+ 'FOREIGN',
882
+ 'FROM',
883
+ 'FULL',
884
+ 'GROUP',
885
+ 'GROUPS',
886
+ 'HAVING',
887
+ 'HOUR',
888
+ 'IF',
889
+ 'ILIKE',
890
+ 'IN',
891
+ 'INNER',
892
+ 'INTERSECT',
893
+ 'INTERVAL',
894
+ 'IS',
895
+ 'JOIN',
896
+ 'KEY',
897
+ 'LEADING',
898
+ 'LEFT',
899
+ 'LIKE',
900
+ 'LIMIT',
901
+ 'LOCALTIME',
902
+ 'LOCALTIMESTAMP',
903
+ 'MINUS',
904
+ 'MINUTE',
905
+ 'MONTH',
906
+ 'NATURAL',
907
+ 'NOT',
908
+ 'NULL',
909
+ 'OFFSET',
910
+ 'ON',
911
+ 'OR',
912
+ 'ORDER',
913
+ 'OVER',
914
+ 'PARTITION',
915
+ 'PRIMARY',
916
+ 'QUALIFY',
917
+ 'RANGE',
918
+ 'REGEXP',
919
+ 'RIGHT',
920
+ 'ROW',
921
+ 'ROWNUM',
922
+ 'ROWS',
923
+ 'SECOND',
924
+ 'SELECT',
925
+ 'SESSION_USER',
926
+ 'SET',
927
+ 'SOME',
928
+ 'SYMMETRIC',
929
+ 'SYSTEM_USER',
930
+ 'TABLE',
931
+ 'TO',
932
+ 'TOP',
933
+ 'TRAILING',
934
+ 'TRUE',
935
+ 'UESCAPE',
936
+ 'UNION',
937
+ 'UNIQUE',
938
+ 'UNKNOWN',
939
+ 'USER',
940
+ 'USING',
941
+ 'VALUE',
942
+ 'VALUES',
943
+ 'WHEN',
944
+ 'WHERE',
945
+ 'WINDOW',
946
+ 'WITH',
947
+ 'YEAR',
948
+ '_ROWID_'
845
949
  ]
846
950
  }