@intentius/chant-lexicon-sql 0.124.46 → 0.124.49

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 (402) hide show
  1. package/dist/change-set.d.ts +1 -1
  2. package/dist/change-set.d.ts.map +1 -1
  3. package/dist/change-set.js +2 -1
  4. package/dist/clickhouse/apply/statements.d.ts +9 -0
  5. package/dist/clickhouse/apply/statements.d.ts.map +1 -1
  6. package/dist/clickhouse/apply/statements.js +24 -0
  7. package/dist/clickhouse/import/live-export.d.ts +7 -3
  8. package/dist/clickhouse/import/live-export.d.ts.map +1 -1
  9. package/dist/clickhouse/import/live-export.js +21 -5
  10. package/dist/clickhouse/live/named-collections.d.ts +27 -0
  11. package/dist/clickhouse/live/named-collections.d.ts.map +1 -0
  12. package/dist/clickhouse/live/named-collections.js +53 -0
  13. package/dist/clickhouse/live/undeclarable.d.ts +15 -3
  14. package/dist/clickhouse/live/undeclarable.d.ts.map +1 -1
  15. package/dist/clickhouse/live/undeclarable.js +18 -4
  16. package/dist/clickhouse/named-collections.d.ts +83 -0
  17. package/dist/clickhouse/named-collections.d.ts.map +1 -0
  18. package/dist/clickhouse/named-collections.js +203 -0
  19. package/dist/clickhouse/parser.d.ts.map +1 -1
  20. package/dist/clickhouse/parser.js +1 -1
  21. package/dist/clickhouse/plan/commands.d.ts +2 -1
  22. package/dist/clickhouse/plan/commands.d.ts.map +1 -1
  23. package/dist/clickhouse/plan/commands.js +17 -2
  24. package/dist/clickhouse/plan/diff.d.ts +15 -0
  25. package/dist/clickhouse/plan/diff.d.ts.map +1 -1
  26. package/dist/clickhouse/plan/diff.js +43 -1
  27. package/dist/clickhouse/plan/disruption.d.ts.map +1 -1
  28. package/dist/clickhouse/plan/disruption.js +5 -0
  29. package/dist/clickhouse/plan/rebuild-handoff.d.ts.map +1 -1
  30. package/dist/clickhouse/plan/rebuild-handoff.js +4 -0
  31. package/dist/clickhouse/plan/report.d.ts.map +1 -1
  32. package/dist/clickhouse/plan/report.js +6 -1
  33. package/dist/clickhouse/plan/rules.d.ts +5 -1
  34. package/dist/clickhouse/plan/rules.d.ts.map +1 -1
  35. package/dist/clickhouse/plan/rules.js +7 -3
  36. package/dist/clickhouse/plan/statements.d.ts +29 -0
  37. package/dist/clickhouse/plan/statements.d.ts.map +1 -0
  38. package/dist/clickhouse/plan/statements.js +334 -0
  39. package/dist/clickhouse/plan/stream.d.ts +40 -0
  40. package/dist/clickhouse/plan/stream.d.ts.map +1 -0
  41. package/dist/clickhouse/plan/stream.js +107 -0
  42. package/dist/clickhouse/rebuild/observe.d.ts +3 -1
  43. package/dist/clickhouse/rebuild/observe.d.ts.map +1 -1
  44. package/dist/clickhouse/rebuild/observe.js +14 -1
  45. package/dist/clickhouse/review-catalog.d.ts +213 -0
  46. package/dist/clickhouse/review-catalog.d.ts.map +1 -0
  47. package/dist/clickhouse/review-catalog.js +330 -0
  48. package/dist/codegen/classifier-page.d.ts.map +1 -1
  49. package/dist/codegen/classifier-page.js +44 -4
  50. package/dist/codegen/clickhouse-module.d.ts.map +1 -1
  51. package/dist/codegen/clickhouse-module.js +3 -0
  52. package/dist/codegen/coverage-page.d.ts.map +1 -1
  53. package/dist/codegen/coverage-page.js +5 -3
  54. package/dist/codegen/docs.js +1 -1
  55. package/dist/codegen/postgres-classifier-page.js +2 -2
  56. package/dist/codegen/registry.d.ts.map +1 -1
  57. package/dist/codegen/registry.js +10 -0
  58. package/dist/composites/catalog.d.ts.map +1 -1
  59. package/dist/composites/catalog.js +100 -0
  60. package/dist/composites/clickhouse.d.ts +2 -0
  61. package/dist/composites/clickhouse.d.ts.map +1 -1
  62. package/dist/composites/clickhouse.js +2 -0
  63. package/dist/composites/otel-tables.d.ts +100 -0
  64. package/dist/composites/otel-tables.d.ts.map +1 -0
  65. package/dist/composites/otel-tables.js +282 -0
  66. package/dist/composites/stream-ingest.d.ts +63 -0
  67. package/dist/composites/stream-ingest.d.ts.map +1 -0
  68. package/dist/composites/stream-ingest.js +39 -0
  69. package/dist/core/statement-class.d.ts +55 -0
  70. package/dist/core/statement-class.d.ts.map +1 -0
  71. package/dist/core/statement-class.js +43 -0
  72. package/dist/coverage/clickhouse.json +1 -1
  73. package/dist/coverage/postgres.json +12 -12
  74. package/dist/coverage.d.ts +16 -6
  75. package/dist/coverage.d.ts.map +1 -1
  76. package/dist/coverage.js +10 -5
  77. package/dist/drizzle-command.d.ts +17 -0
  78. package/dist/drizzle-command.d.ts.map +1 -0
  79. package/dist/drizzle-command.js +91 -0
  80. package/dist/drizzle.d.ts +70 -0
  81. package/dist/drizzle.d.ts.map +1 -0
  82. package/dist/drizzle.js +689 -0
  83. package/dist/files/clickhouse.d.ts.map +1 -1
  84. package/dist/files/clickhouse.js +8 -1
  85. package/dist/files/common.d.ts +13 -0
  86. package/dist/files/common.d.ts.map +1 -1
  87. package/dist/files/common.js +5 -0
  88. package/dist/files/postgres.d.ts.map +1 -1
  89. package/dist/files/postgres.js +35 -3
  90. package/dist/generated/clickhouse.d.ts +2 -0
  91. package/dist/generated/clickhouse.d.ts.map +1 -1
  92. package/dist/generated/clickhouse.js +2 -0
  93. package/dist/import-parser.d.ts +21 -1
  94. package/dist/import-parser.d.ts.map +1 -1
  95. package/dist/import-parser.js +79 -5
  96. package/dist/index.d.ts +1 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +1 -1
  99. package/dist/integrity.json +7 -6
  100. package/dist/lint/post-synth/audit-entries.d.ts.map +1 -1
  101. package/dist/lint/post-synth/audit-entries.js +1 -0
  102. package/dist/lint/post-synth/index.d.ts.map +1 -1
  103. package/dist/lint/post-synth/index.js +2 -0
  104. package/dist/lint/post-synth/postgres-names.d.ts.map +1 -1
  105. package/dist/lint/post-synth/postgres-names.js +3 -0
  106. package/dist/lint/post-synth/sqlch128.d.ts +18 -0
  107. package/dist/lint/post-synth/sqlch128.d.ts.map +1 -0
  108. package/dist/lint/post-synth/sqlch128.js +222 -0
  109. package/dist/lint/rules/postgres-templates.js +2 -2
  110. package/dist/lsp/postgres-template.d.ts.map +1 -1
  111. package/dist/lsp/postgres-template.js +21 -0
  112. package/dist/manifest.json +1 -1
  113. package/dist/mcp/postgres.js +1 -1
  114. package/dist/meta.json +50 -0
  115. package/dist/migrate/from-postgres/detect.d.ts +4 -0
  116. package/dist/migrate/from-postgres/detect.d.ts.map +1 -0
  117. package/dist/migrate/from-postgres/detect.js +7 -0
  118. package/dist/migrate/from-postgres/emit.d.ts +26 -0
  119. package/dist/migrate/from-postgres/emit.d.ts.map +1 -0
  120. package/dist/migrate/from-postgres/emit.js +86 -0
  121. package/dist/migrate/from-postgres/index.d.ts +51 -0
  122. package/dist/migrate/from-postgres/index.d.ts.map +1 -0
  123. package/dist/migrate/from-postgres/index.js +115 -0
  124. package/dist/migrate/from-postgres/translate.d.ts +73 -0
  125. package/dist/migrate/from-postgres/translate.d.ts.map +1 -0
  126. package/dist/migrate/from-postgres/translate.js +261 -0
  127. package/dist/migrate/from-postgres/types.d.ts +51 -0
  128. package/dist/migrate/from-postgres/types.d.ts.map +1 -0
  129. package/dist/migrate/from-postgres/types.js +211 -0
  130. package/dist/migration-classify.d.ts +23 -0
  131. package/dist/migration-classify.d.ts.map +1 -0
  132. package/dist/migration-classify.js +44 -0
  133. package/dist/migration-replay.d.ts +73 -0
  134. package/dist/migration-replay.d.ts.map +1 -0
  135. package/dist/migration-replay.js +294 -0
  136. package/dist/okf/index.md +11 -0
  137. package/dist/okf/rules/SQLCH128.md +11 -0
  138. package/dist/okf/types/PostgresForeignDataWrapper.md +9 -0
  139. package/dist/okf/types/PostgresForeignServer.md +9 -0
  140. package/dist/okf/types/PostgresForeignTable.md +9 -0
  141. package/dist/okf/types/PostgresOperator.md +9 -0
  142. package/dist/okf/types/PostgresOperatorClass.md +9 -0
  143. package/dist/okf/types/PostgresOperatorFamily.md +9 -0
  144. package/dist/okf/types/PostgresPublication.md +9 -0
  145. package/dist/okf/types/PostgresStatistics.md +9 -0
  146. package/dist/okf/types/PostgresTextSearchConfiguration.md +9 -0
  147. package/dist/okf/types/PostgresTextSearchDictionary.md +9 -0
  148. package/dist/op/activities/postgres-migration.d.ts.map +1 -1
  149. package/dist/op/activities/postgres-migration.js +4 -0
  150. package/dist/op/activity-contracts.d.ts +20 -0
  151. package/dist/op/activity-contracts.d.ts.map +1 -1
  152. package/dist/op/activity-contracts.js +2 -0
  153. package/dist/plugin.d.ts.map +1 -1
  154. package/dist/plugin.js +49 -2
  155. package/dist/postgres/access/acl.js +1 -1
  156. package/dist/postgres/access/import.js +1 -1
  157. package/dist/postgres/apply/apply.js +13 -1
  158. package/dist/postgres/apply/statements.d.ts.map +1 -1
  159. package/dist/postgres/apply/statements.js +243 -4
  160. package/dist/postgres/constraint-names.d.ts +30 -0
  161. package/dist/postgres/constraint-names.d.ts.map +1 -0
  162. package/dist/postgres/constraint-names.js +72 -0
  163. package/dist/postgres/entities.d.ts +229 -2
  164. package/dist/postgres/entities.d.ts.map +1 -1
  165. package/dist/postgres/entities.js +326 -5
  166. package/dist/postgres/entity-types.d.ts +10 -0
  167. package/dist/postgres/entity-types.d.ts.map +1 -1
  168. package/dist/postgres/entity-types.js +10 -0
  169. package/dist/postgres/import/generator.d.ts.map +1 -1
  170. package/dist/postgres/import/generator.js +65 -2
  171. package/dist/postgres/import/live-export.d.ts.map +1 -1
  172. package/dist/postgres/import/live-export.js +2 -0
  173. package/dist/postgres/live/catalog-kinds.d.ts +20 -0
  174. package/dist/postgres/live/catalog-kinds.d.ts.map +1 -1
  175. package/dist/postgres/live/catalog-kinds.js +452 -0
  176. package/dist/postgres/live/catalog.d.ts +2 -0
  177. package/dist/postgres/live/catalog.d.ts.map +1 -1
  178. package/dist/postgres/live/catalog.js +3 -1
  179. package/dist/postgres/live/describe-resources.d.ts.map +1 -1
  180. package/dist/postgres/live/describe-resources.js +12 -2
  181. package/dist/postgres/migrate/backfill.d.ts +2 -0
  182. package/dist/postgres/migrate/backfill.d.ts.map +1 -1
  183. package/dist/postgres/migrate/backfill.js +7 -1
  184. package/dist/postgres/migrate/carry.d.ts +45 -1
  185. package/dist/postgres/migrate/carry.d.ts.map +1 -1
  186. package/dist/postgres/migrate/carry.js +72 -8
  187. package/dist/postgres/migrate/observe.d.ts +28 -4
  188. package/dist/postgres/migrate/observe.d.ts.map +1 -1
  189. package/dist/postgres/migrate/observe.js +45 -13
  190. package/dist/postgres/migrate/op.d.ts +26 -1
  191. package/dist/postgres/migrate/op.d.ts.map +1 -1
  192. package/dist/postgres/migrate/op.js +3 -1
  193. package/dist/postgres/migrate/replication.d.ts +42 -0
  194. package/dist/postgres/migrate/replication.d.ts.map +1 -1
  195. package/dist/postgres/migrate/replication.js +53 -0
  196. package/dist/postgres/migrate/steps.d.ts +35 -2
  197. package/dist/postgres/migrate/steps.d.ts.map +1 -1
  198. package/dist/postgres/migrate/steps.js +158 -12
  199. package/dist/postgres/parser.d.ts +144 -1
  200. package/dist/postgres/parser.d.ts.map +1 -1
  201. package/dist/postgres/parser.js +370 -4
  202. package/dist/postgres/plan/deep.d.ts.map +1 -1
  203. package/dist/postgres/plan/deep.js +43 -4
  204. package/dist/postgres/plan/diff.d.ts.map +1 -1
  205. package/dist/postgres/plan/diff.js +154 -1
  206. package/dist/postgres/plan/normalize.d.ts +28 -2
  207. package/dist/postgres/plan/normalize.d.ts.map +1 -1
  208. package/dist/postgres/plan/normalize.js +260 -1
  209. package/dist/postgres/plan/rules.d.ts +4 -0
  210. package/dist/postgres/plan/rules.d.ts.map +1 -1
  211. package/dist/postgres/plan/rules.js +6 -2
  212. package/dist/postgres/plan/schema.js +1 -1
  213. package/dist/postgres/plan/statements.d.ts +26 -0
  214. package/dist/postgres/plan/statements.d.ts.map +1 -0
  215. package/dist/postgres/plan/statements.js +364 -0
  216. package/dist/postgres/secret-options.d.ts +10 -0
  217. package/dist/postgres/secret-options.d.ts.map +1 -0
  218. package/dist/postgres/secret-options.js +9 -0
  219. package/dist/postgres/testing/roundtrip-schema.d.ts +4 -2
  220. package/dist/postgres/testing/roundtrip-schema.d.ts.map +1 -1
  221. package/dist/postgres/testing/roundtrip-schema.js +24 -1
  222. package/dist/postgres.d.ts +1 -1
  223. package/dist/postgres.d.ts.map +1 -1
  224. package/dist/postgres.js +1 -1
  225. package/dist/rules/audit-entries.ts +1 -0
  226. package/dist/rules/postgres-names.ts +2 -0
  227. package/dist/rules/postgres-templates.ts +2 -2
  228. package/dist/rules/sqlch128.ts +230 -0
  229. package/dist/serializer.d.ts +5 -0
  230. package/dist/serializer.d.ts.map +1 -1
  231. package/dist/serializer.js +13 -2
  232. package/dist/sql-types-command.d.ts +13 -0
  233. package/dist/sql-types-command.d.ts.map +1 -1
  234. package/dist/sql-types-command.js +31 -16
  235. package/dist/sql-types.d.ts +22 -0
  236. package/dist/sql-types.d.ts.map +1 -1
  237. package/dist/sql-types.js +10 -6
  238. package/dist/sqlserver/lexer.d.ts +37 -0
  239. package/dist/sqlserver/lexer.d.ts.map +1 -0
  240. package/dist/sqlserver/lexer.js +254 -0
  241. package/dist/sqlserver/parse.d.ts +185 -0
  242. package/dist/sqlserver/parse.d.ts.map +1 -0
  243. package/dist/sqlserver/parse.js +767 -0
  244. package/dist/sqlserver/translate.d.ts +34 -0
  245. package/dist/sqlserver/translate.d.ts.map +1 -0
  246. package/dist/sqlserver/translate.js +495 -0
  247. package/dist/sqlserver/types.d.ts +44 -0
  248. package/dist/sqlserver/types.d.ts.map +1 -0
  249. package/dist/sqlserver/types.js +133 -0
  250. package/dist/sqlserver/validate.d.ts +31 -0
  251. package/dist/sqlserver/validate.d.ts.map +1 -0
  252. package/dist/sqlserver/validate.js +67 -0
  253. package/dist/validate.d.ts.map +1 -1
  254. package/dist/validate.js +10 -0
  255. package/package.json +2 -2
  256. package/src/change-set.ts +2 -1
  257. package/src/clickhouse/apply/statements.ts +25 -0
  258. package/src/clickhouse/import/live-export.ts +20 -5
  259. package/src/clickhouse/live/named-collections.e2e.test.ts +88 -0
  260. package/src/clickhouse/live/named-collections.ts +61 -0
  261. package/src/clickhouse/live/undeclarable.e2e.test.ts +5 -3
  262. package/src/clickhouse/live/undeclarable.ts +20 -4
  263. package/src/clickhouse/named-collections.test.ts +187 -0
  264. package/src/clickhouse/named-collections.ts +224 -0
  265. package/src/clickhouse/parser.ts +2 -1
  266. package/src/clickhouse/plan/commands.ts +17 -2
  267. package/src/clickhouse/plan/diff.ts +57 -1
  268. package/src/clickhouse/plan/disruption.ts +5 -0
  269. package/src/clickhouse/plan/rebuild-handoff.ts +3 -0
  270. package/src/clickhouse/plan/report.ts +6 -1
  271. package/src/clickhouse/plan/rules.ts +14 -4
  272. package/src/clickhouse/plan/statements.test.ts +61 -0
  273. package/src/clickhouse/plan/statements.ts +306 -0
  274. package/src/clickhouse/plan/stream-s3queue.e2e.test.ts +148 -0
  275. package/src/clickhouse/plan/stream.test.ts +237 -0
  276. package/src/clickhouse/plan/stream.ts +111 -0
  277. package/src/clickhouse/rebuild/observe.ts +15 -1
  278. package/src/clickhouse/review-catalog.test.ts +181 -0
  279. package/src/clickhouse/review-catalog.ts +489 -0
  280. package/src/codegen/classifier-page.ts +44 -4
  281. package/src/codegen/clickhouse-module.ts +3 -0
  282. package/src/codegen/coverage-page.ts +5 -3
  283. package/src/codegen/docs.ts +1 -1
  284. package/src/codegen/postgres-classifier-page.ts +2 -2
  285. package/src/codegen/registry.ts +10 -0
  286. package/src/composites/catalog.test.ts +6 -1
  287. package/src/composites/catalog.ts +100 -0
  288. package/src/composites/clickhouse.ts +2 -0
  289. package/src/composites/composites.test.ts +1 -1
  290. package/src/composites/otel-tables.test.ts +118 -0
  291. package/src/composites/otel-tables.ts +339 -0
  292. package/src/composites/stream-ingest.test.ts +114 -0
  293. package/src/composites/stream-ingest.ts +82 -0
  294. package/src/core/statement-class.ts +88 -0
  295. package/src/core/undeclarable.test.ts +6 -5
  296. package/src/coverage/clickhouse.json +1 -1
  297. package/src/coverage/postgres.json +12 -12
  298. package/src/coverage.test.ts +27 -2
  299. package/src/coverage.ts +18 -7
  300. package/src/drizzle-command.ts +94 -0
  301. package/src/drizzle-kit.e2e.test.ts +89 -0
  302. package/src/drizzle-types.e2e.test.ts +67 -0
  303. package/src/drizzle.test.ts +358 -0
  304. package/src/drizzle.ts +742 -0
  305. package/src/files/clickhouse.ts +8 -1
  306. package/src/files/common.ts +14 -1
  307. package/src/files/postgres.ts +34 -3
  308. package/src/generated/clickhouse.ts +3 -0
  309. package/src/generated/lexicon-sql.json +50 -0
  310. package/src/import-parser.sqlserver.test.ts +92 -0
  311. package/src/import-parser.ts +79 -5
  312. package/src/index.ts +1 -1
  313. package/src/lint/post-synth/audit-entries.ts +1 -0
  314. package/src/lint/post-synth/index.ts +2 -0
  315. package/src/lint/post-synth/postgres-checks.test.ts +8 -1
  316. package/src/lint/post-synth/postgres-names.ts +2 -0
  317. package/src/lint/post-synth/sqlch128.test.ts +107 -0
  318. package/src/lint/post-synth/sqlch128.ts +230 -0
  319. package/src/lint/rules/postgres-templates.ts +2 -2
  320. package/src/lsp/postgres-template.ts +20 -0
  321. package/src/mcp/postgres.ts +1 -1
  322. package/src/migrate/from-postgres/cli.test.ts +165 -0
  323. package/src/migrate/from-postgres/detect.ts +7 -0
  324. package/src/migrate/from-postgres/emit.ts +96 -0
  325. package/src/migrate/from-postgres/example.test.ts +205 -0
  326. package/src/migrate/from-postgres/index.ts +122 -0
  327. package/src/migrate/from-postgres/translate.test.ts +242 -0
  328. package/src/migrate/from-postgres/translate.ts +359 -0
  329. package/src/migrate/from-postgres/types.test.ts +116 -0
  330. package/src/migrate/from-postgres/types.ts +236 -0
  331. package/src/migrate/from-postgres/validate.e2e.test.ts +44 -0
  332. package/src/migrate/from-postgres/workspace.e2e.test.ts +114 -0
  333. package/src/migration-classify.test.ts +150 -0
  334. package/src/migration-classify.ts +45 -0
  335. package/src/migration-replay.e2e.test.ts +155 -0
  336. package/src/migration-replay.test.ts +173 -0
  337. package/src/migration-replay.ts +289 -0
  338. package/src/op/__snapshots__/watch-pipeline.test.ts.snap +2 -2
  339. package/src/op/activities/postgres-migration.ts +4 -0
  340. package/src/op/activity-contracts.ts +2 -0
  341. package/src/op/watch-pipeline.test.ts +8 -1
  342. package/src/plugin.ts +51 -2
  343. package/src/postgres/access/acl.ts +1 -1
  344. package/src/postgres/access/import.ts +1 -1
  345. package/src/postgres/apply/apply.ts +14 -1
  346. package/src/postgres/apply/statements.ts +225 -4
  347. package/src/postgres/constraint-names.ts +71 -0
  348. package/src/postgres/database-kinds.test.ts +865 -0
  349. package/src/postgres/entities.ts +541 -5
  350. package/src/postgres/entity-types.ts +10 -0
  351. package/src/postgres/import/generator.ts +54 -2
  352. package/src/postgres/import/live-export.ts +1 -0
  353. package/src/postgres/live/catalog-kinds.ts +494 -0
  354. package/src/postgres/live/catalog.ts +6 -1
  355. package/src/postgres/live/database-kinds.e2e.test.ts +164 -0
  356. package/src/postgres/live/describe-resources.ts +13 -2
  357. package/src/postgres/live/undeclarable.e2e.test.ts +13 -6
  358. package/src/postgres/migrate/backfill.ts +13 -1
  359. package/src/postgres/migrate/carry.ts +103 -8
  360. package/src/postgres/migrate/followups.e2e.test.ts +218 -0
  361. package/src/postgres/migrate/followups.test.ts +199 -0
  362. package/src/postgres/migrate/kinds.e2e.test.ts +5 -5
  363. package/src/postgres/migrate/observe.ts +56 -15
  364. package/src/postgres/migrate/op.ts +28 -1
  365. package/src/postgres/migrate/partition.e2e.test.ts +129 -0
  366. package/src/postgres/migrate/partition.test.ts +206 -0
  367. package/src/postgres/migrate/replication.ts +66 -0
  368. package/src/postgres/migrate/steps.ts +157 -12
  369. package/src/postgres/migrate/subscriber.e2e.test.ts +141 -0
  370. package/src/postgres/migrate/subscriber.test.ts +59 -0
  371. package/src/postgres/parser.ts +455 -4
  372. package/src/postgres/plan/deep.ts +42 -4
  373. package/src/postgres/plan/diff.ts +137 -1
  374. package/src/postgres/plan/normalize.ts +277 -1
  375. package/src/postgres/plan/rules.ts +32 -4
  376. package/src/postgres/plan/schema.ts +1 -1
  377. package/src/postgres/plan/statements.test.ts +78 -0
  378. package/src/postgres/plan/statements.ts +299 -0
  379. package/src/postgres/secret-options.ts +10 -0
  380. package/src/postgres/testing/roundtrip-schema.ts +24 -1
  381. package/src/postgres.ts +33 -0
  382. package/src/serializer.ts +13 -2
  383. package/src/skills/chant-sql-postgres-migration.md +4 -3
  384. package/src/skills/chant-sql-postgres.md +11 -1
  385. package/src/skills/chant-sql.md +2 -1
  386. package/src/sql-files.test.ts +33 -0
  387. package/src/sql-types-command.ts +38 -16
  388. package/src/sql-types.ts +11 -6
  389. package/src/sqlserver/fixture.test.ts +186 -0
  390. package/src/sqlserver/import-cli.test.ts +61 -0
  391. package/src/sqlserver/lexer.ts +260 -0
  392. package/src/sqlserver/parse.ts +865 -0
  393. package/src/sqlserver/translate.test.ts +396 -0
  394. package/src/sqlserver/translate.ts +558 -0
  395. package/src/sqlserver/types.test.ts +102 -0
  396. package/src/sqlserver/types.ts +154 -0
  397. package/src/sqlserver/validate.e2e.test.ts +32 -0
  398. package/src/sqlserver/validate.test.ts +49 -0
  399. package/src/sqlserver/validate.ts +76 -0
  400. package/src/validate.ts +10 -0
  401. package/src/workspace-kinds.test.ts +11 -0
  402. package/workspace-kinds.json +100 -2
@@ -0,0 +1,334 @@
1
+ /**
2
+ * The ClickHouse statement classifier (#4407): a migration file's statements,
3
+ * each given the class and rule the schema-diff classifier (`./rules.ts`)
4
+ * gives the same change. It reads text and contacts no server.
5
+ *
6
+ * `CREATE` goes through the declaration parser (`../parser.ts`), which also
7
+ * tells the classifier a table's keys when the file creates the table. The
8
+ * parser has no `ALTER` grammar, so `ALTER`, `DROP` and `RENAME` are read word
9
+ * by word from the same tokens.
10
+ *
11
+ * A statement alone cannot decide some changes, and those answer `undecided`
12
+ * naming both rules, the way `./disruption.ts` answers `unknown`:
13
+ *
14
+ * - `MODIFY COLUMN c <type>` is SQLCH210 (a rewrite), or SQLCH211 (a rebuild)
15
+ * when `c` is in a key. The file states the keys only when it creates the
16
+ * table.
17
+ * - `DROP COLUMN` is SQLCH202 or SQLCH213, and `RENAME COLUMN` SQLCH212 or
18
+ * SQLCH213, on the same condition.
19
+ * - `MODIFY ORDER BY` that the same `ALTER` pairs with `ADD COLUMN` is SQLCH216
20
+ * when it only appends those columns and SQLCH220 (a rebuild) otherwise.
21
+ * Without such a column it is SQLCH220.
22
+ */
23
+ import { MERGE_TREE_SETTINGS } from "../../generated/clickhouse.js";
24
+ import { isTrivia, tokenizeText } from "../tokens.js";
25
+ import { parseCreate } from "../parser.js";
26
+ import { classifiedOf, splitTopLevel, sqlHead } from "../../core/statement-class.js";
27
+ import { CHANGE_CLASSES, CLASSIFIER_RULES } from "./rules.js";
28
+ const classified = (id, extra = {}) => classifiedOf(CLASSIFIER_RULES, CHANGE_CLASSES.label, id, extra);
29
+ const rule = (id, extra) => ({ rules: [{ id, ...(extra ? { extra } : {}) }] });
30
+ /** Settings only a stream engine takes (the same list `./disruption.ts` reads). */
31
+ const STREAM_SETTING = /^(?:kafka_|rabbitmq_|nats_|s3queue_|azure_queue_|keeper_path$)/;
32
+ const bare = (name) => (name.split(".").pop() ?? name).replace(/^[`"]|[`"]$/g, "").toLowerCase();
33
+ const text = (tokens, s) => (s ? tokens.slice(s.from, s.to).filter((t) => !isTrivia(t)).map((t) => t.text).join(" ") : "");
34
+ /** The identifier tokens of a key expression that are not function names. */
35
+ function columnsOf(tokens, s) {
36
+ if (!s)
37
+ return [];
38
+ const toks = tokens.slice(s.from, s.to).filter((t) => !isTrivia(t));
39
+ return toks.flatMap((t, i) => ((t.kind === "ident" || t.kind === "qident") && toks[i + 1]?.text !== "(" ? [bare(t.text)] : []));
40
+ }
41
+ function nameAt(words, i) {
42
+ let name = words[i] ?? "";
43
+ let j = i + 1;
44
+ while (words[j] === "." && words[j + 1] !== undefined) {
45
+ name += `.${words[j + 1]}`;
46
+ j += 2;
47
+ }
48
+ return { name, next: j };
49
+ }
50
+ const KNOWN_VERBS = new Set(["ADD", "DROP", "RENAME", "MODIFY", "COMMENT", "CLEAR", "MATERIALIZE", "UPDATE", "DELETE", "ATTACH", "DETACH", "FREEZE", "FETCH", "MOVE", "REPLACE", "RESET", "REMOVE", "APPLY", "UNFREEZE", "EXECUTE"]);
51
+ /** Normalise a key expression for comparing an old and a new one: no spaces, no outer parentheses. */
52
+ const keyText = (words) => {
53
+ let t = words.join("").toLowerCase();
54
+ while (t.startsWith("(") && t.endsWith(")"))
55
+ t = t.slice(1, -1);
56
+ return t;
57
+ };
58
+ function columnVerdict(kind, col, ctx) {
59
+ const plain = kind === "drop" ? "SQLCH202" : "SQLCH212";
60
+ const extra = kind === "drop" ? { destructive: true } : undefined;
61
+ if (ctx.created) {
62
+ return ctx.created.keys.has(bare(col)) ? rule("SQLCH213", extra) : rule(plain, extra);
63
+ }
64
+ return { undecided: [plain, "SQLCH213"], note: `${col} is a column change or, in a key, a rebuild; the file does not create the table, so its keys are not known offline` };
65
+ }
66
+ function tableAction(a, ctx) {
67
+ const u = a.map((w) => w.toUpperCase());
68
+ const first = u[0];
69
+ const second = u[1];
70
+ if (first === "ADD") {
71
+ if (second === "COLUMN")
72
+ return rule("SQLCH201");
73
+ if (second === "INDEX")
74
+ return rule("SQLCH204");
75
+ if (second === "PROJECTION")
76
+ return rule("SQLCH214");
77
+ if (second === "CONSTRAINT")
78
+ return rule("SQLCH215");
79
+ return { none: `ALTER TABLE ${u.slice(0, 2).join(" ")}` };
80
+ }
81
+ if (first === "DROP") {
82
+ if (second === "COLUMN") {
83
+ const k = u[2] === "IF" ? 4 : 2;
84
+ return columnVerdict("drop", a[k] ?? "column", ctx);
85
+ }
86
+ if (second === "INDEX")
87
+ return rule("SQLCH204");
88
+ if (second === "PROJECTION")
89
+ return rule("SQLCH214");
90
+ if (second === "CONSTRAINT")
91
+ return rule("SQLCH215");
92
+ return { none: `ALTER TABLE ${u.slice(0, 2).join(" ")} (removes data parts, no rule covers it)` };
93
+ }
94
+ if (first === "CLEAR") {
95
+ if (second === "INDEX")
96
+ return rule("SQLCH204");
97
+ if (second === "PROJECTION")
98
+ return rule("SQLCH214");
99
+ return { none: `ALTER TABLE CLEAR ${second ?? ""}`.trim() };
100
+ }
101
+ if (first === "RENAME" && second === "COLUMN") {
102
+ const k = u[2] === "IF" ? 4 : 2;
103
+ return columnVerdict("rename", a[k] ?? "column", ctx);
104
+ }
105
+ if (first === "COMMENT" && second === "COLUMN")
106
+ return rule("SQLCH203");
107
+ if (first === "MODIFY" || first === "RESET") {
108
+ if (second === "COLUMN") {
109
+ let k = 2;
110
+ if (u[k] === "IF" && u[k + 1] === "EXISTS")
111
+ k += 2;
112
+ const col = a[k] ?? "column";
113
+ const after = u[k + 1];
114
+ if (after === "REMOVE") {
115
+ const what = u[k + 2];
116
+ return what === "CODEC" ? rule("SQLCH208") : what === "COMMENT" ? rule("SQLCH203") : what === "TTL" ? rule("SQLCH205") : rule("SQLCH207");
117
+ }
118
+ if (after === "DEFAULT" || after === "MATERIALIZED" || after === "ALIAS" || after === "EPHEMERAL")
119
+ return rule("SQLCH207");
120
+ if (after === "CODEC")
121
+ return rule("SQLCH208");
122
+ if (after === "COMMENT")
123
+ return rule("SQLCH203");
124
+ if (after === "TTL")
125
+ return rule("SQLCH205");
126
+ if (after === "MODIFY" || after === "RESET")
127
+ return { none: "MODIFY COLUMN ... SETTING" };
128
+ if (after === undefined)
129
+ return { none: "MODIFY COLUMN with no change" };
130
+ if (ctx.created)
131
+ return ctx.created.keys.has(bare(col)) ? rule("SQLCH211") : rule("SQLCH210");
132
+ return { undecided: ["SQLCH210", "SQLCH211"], note: `a type change of ${col} is a background rewrite or, when ${col} is in a key, a rebuild; the file does not create the table, so its keys are not known offline` };
133
+ }
134
+ if (second === "ORDER" && u[2] === "BY") {
135
+ const next = a.slice(3);
136
+ if (ctx.created?.orderBy !== undefined) {
137
+ const was = ctx.created.orderBy;
138
+ const now = keyText(next);
139
+ const tail = now.startsWith(was) ? now.slice(was.length) : undefined;
140
+ const extra = tail === undefined ? [] : tail.split(/[^a-z0-9_]+/).filter(Boolean);
141
+ if (tail !== undefined && extra.length > 0 && extra.every((c) => ctx.added.has(c)))
142
+ return rule("SQLCH216");
143
+ return rule("SQLCH220");
144
+ }
145
+ const mentions = next.some((w) => ctx.added.has(bare(w)));
146
+ if (mentions)
147
+ return { undecided: ["SQLCH216", "SQLCH220"], note: "the new key appends the columns this ALTER adds only if its other elements are the old key's, which the file does not state" };
148
+ return rule("SQLCH220");
149
+ }
150
+ if (second === "SAMPLE" && u[2] === "BY")
151
+ return rule("SQLCH217");
152
+ if (second === "TTL")
153
+ return rule("SQLCH205");
154
+ if (second === "COMMENT")
155
+ return rule("SQLCH203");
156
+ if (second === "QUERY")
157
+ return rule("SQLCH241");
158
+ if (second === "REFRESH")
159
+ return rule("SQLCH244");
160
+ if (second === "SETTING" || second === "SETTINGS") {
161
+ const key = (a[2] ?? "").toLowerCase();
162
+ return settingRule(key);
163
+ }
164
+ return { none: `ALTER TABLE ${u.slice(0, 2).join(" ")}` };
165
+ }
166
+ if (first === "REMOVE") {
167
+ if (second === "TTL")
168
+ return rule("SQLCH205");
169
+ if (second === "SAMPLE" && u[2] === "BY")
170
+ return rule("SQLCH217");
171
+ return { none: `ALTER TABLE REMOVE ${second ?? ""}`.trim() };
172
+ }
173
+ if (first === "UPDATE" || first === "DELETE")
174
+ return { data: "a mutation: it rewrites the parts it touches in the background (system.mutations) and has no rollback" };
175
+ return { none: `ALTER TABLE ${u.slice(0, 2).join(" ")}` };
176
+ }
177
+ function settingRule(key) {
178
+ if (STREAM_SETTING.test(key))
179
+ return rule("SQLCH225", { note: `${key} belongs to a stream engine, which has no MODIFY SETTING` });
180
+ const spec = MERGE_TREE_SETTINGS[key];
181
+ return spec?.readonly ? rule("SQLCH218", { note: `${key} is fixed at creation` }) : rule("SQLCH206");
182
+ }
183
+ /** The `ALTER TABLE` actions of one statement, in order, a `MODIFY SETTING` list kept together. */
184
+ function alterTable(words, u, created) {
185
+ let i = 2;
186
+ if (u[i] === "IF" && u[i + 1] === "EXISTS")
187
+ i += 2;
188
+ const { name, next } = nameAt(words, i);
189
+ i = next;
190
+ if (u[i] === "ON" && u[i + 1] === "CLUSTER")
191
+ i += 3;
192
+ const actions = splitTopLevel(words.slice(i));
193
+ const added = new Set();
194
+ for (const a of actions) {
195
+ const au = a.map((w) => w.toUpperCase());
196
+ if (au[0] === "ADD" && au[1] === "COLUMN") {
197
+ const k = au[2] === "IF" ? 5 : 2;
198
+ if (a[k])
199
+ added.add(bare(a[k]));
200
+ }
201
+ }
202
+ const ctx = { added, ...(created.has(bare(name)) ? { created: created.get(bare(name)) } : {}) };
203
+ const out = [];
204
+ let inSettings = false;
205
+ for (const a of actions) {
206
+ const au = a.map((w) => w.toUpperCase());
207
+ if (inSettings && au[0] !== undefined && !KNOWN_VERBS.has(au[0])) {
208
+ out.push(settingRule((a[0] ?? "").toLowerCase()));
209
+ continue;
210
+ }
211
+ inSettings = (au[0] === "MODIFY" || au[0] === "RESET") && (au[1] === "SETTING" || au[1] === "SETTINGS");
212
+ out.push(tableAction(a, ctx));
213
+ }
214
+ return out;
215
+ }
216
+ const OBJECTS = { USER: "SQLCH271", ROLE: "SQLCH270", QUOTA: "SQLCH275" };
217
+ function alterOther(u) {
218
+ const obj = u[1];
219
+ if (obj && OBJECTS[obj])
220
+ return rule(OBJECTS[obj]);
221
+ if (obj === "ROW" && u[2] === "POLICY")
222
+ return rule("SQLCH272");
223
+ if (obj === "POLICY")
224
+ return rule("SQLCH272");
225
+ if (obj === "SETTINGS" && u[2] === "PROFILE")
226
+ return rule("SQLCH276");
227
+ if (obj === "DATABASE" && u.includes("COMMENT"))
228
+ return rule("SQLCH203");
229
+ return { none: `ALTER ${obj ?? ""}`.trim() };
230
+ }
231
+ const DATA_WORDS = new Set(["INSERT", "SELECT", "WITH", "SYSTEM", "OPTIMIZE", "TRUNCATE", "SET", "USE", "EXPLAIN", "EXISTS", "DESCRIBE", "DESC", "SHOW", "CHECK", "KILL", "WATCH"]);
232
+ /** A `CREATE` or `ATTACH`: the parser reads tables, views, dictionaries, databases and functions; the rest go by key words. */
233
+ function create(tokens, u, created) {
234
+ let i = 1;
235
+ const orReplace = u[i] === "OR" && u[i + 1] === "REPLACE";
236
+ if (orReplace)
237
+ i += 2;
238
+ let node;
239
+ try {
240
+ node = parseCreate(tokens);
241
+ }
242
+ catch {
243
+ node = undefined;
244
+ }
245
+ if (node?.statement === "table") {
246
+ const name = text(tokens, node.name).replace(/\s*\.\s*/g, ".");
247
+ const keys = new Set([...columnsOf(tokens, node.orderBy), ...columnsOf(tokens, node.primaryKey), ...columnsOf(tokens, node.partitionBy), ...columnsOf(tokens, node.sampleBy)]);
248
+ for (const c of node.columns)
249
+ if (c.primaryKey)
250
+ keys.add(bare(c.name));
251
+ created.set(bare(name), { keys, ...(node.orderBy ? { orderBy: keyText(text(tokens, node.orderBy).split(" ")) } : {}) });
252
+ }
253
+ if (orReplace && u[i] === "FUNCTION")
254
+ return rule("SQLCH260");
255
+ if (orReplace && (u[i] === "TABLE" || node?.statement === "table"))
256
+ return rule("SQLCH200", { note: "OR REPLACE drops an existing table of that name, and its rows, before it creates this one" });
257
+ return rule("SQLCH200");
258
+ }
259
+ function read(sql, created) {
260
+ let tokens;
261
+ try {
262
+ tokens = tokenizeText(sql, 0);
263
+ }
264
+ catch {
265
+ return [{ none: "text the tokenizer could not read" }];
266
+ }
267
+ const words = tokens.filter((t) => !isTrivia(t) && t.text !== ";").map((t) => t.text);
268
+ const u = words.map((w) => w.toUpperCase());
269
+ const head = u[0];
270
+ if (head === undefined)
271
+ return [{ data: "an empty statement" }];
272
+ if (head === "CREATE")
273
+ return [create(tokens, u, created)];
274
+ if (head === "ALTER" && u[1] === "TABLE")
275
+ return alterTable(words, u, created);
276
+ if (head === "ALTER")
277
+ return [alterOther(u)];
278
+ if (head === "DROP")
279
+ return [rule("SQLCH250", { destructive: true })];
280
+ if (head === "RENAME") {
281
+ if (u[1] === "DATABASE")
282
+ return [rule("SQLCH231")];
283
+ if (u[1] === "TABLE" || u[1] === "DICTIONARY")
284
+ return [rule("SQLCH230")];
285
+ return [{ none: `RENAME ${u[1] ?? ""}`.trim() }];
286
+ }
287
+ if (head === "GRANT")
288
+ return [rule("SQLCH273")];
289
+ if (head === "REVOKE")
290
+ return [rule("SQLCH274")];
291
+ if (head === "EXCHANGE")
292
+ return [{ none: "EXCHANGE TABLES swaps two tables; no rule covers it" }];
293
+ if (head === "TRUNCATE")
294
+ return [{ data: "TRUNCATE removes every row of the table" }];
295
+ if (DATA_WORDS.has(head))
296
+ return [{ data: `${head} reads or writes rows or the session, not the schema` }];
297
+ return [{ none: `${head} is not a statement the classifier reads` }];
298
+ }
299
+ /**
300
+ * Classify a migration's up statements, in order. The statements are the
301
+ * file's own text, one per entry.
302
+ */
303
+ export function classifyClickHouseStatements(statements) {
304
+ const created = new Map();
305
+ return statements.map((sql, k) => {
306
+ const readings = read(sql, created);
307
+ const out = { index: k + 1, sql: sqlHead(sql), outcome: "classified", changes: [] };
308
+ const none = [];
309
+ const notes = [];
310
+ for (const r of readings) {
311
+ if ("rules" in r)
312
+ out.changes.push(...r.rules.map((x) => classified(x.id, x.extra)));
313
+ else if ("undecided" in r) {
314
+ out.candidates = [...(out.candidates ?? []), ...r.undecided.map((id) => classified(id))];
315
+ notes.push(r.note);
316
+ }
317
+ else if ("none" in r)
318
+ none.push(r.none);
319
+ else
320
+ notes.push(r.data);
321
+ }
322
+ if (out.candidates)
323
+ out.outcome = "undecided";
324
+ else if (out.changes.length === 0 && none.length === 0)
325
+ out.outcome = "data";
326
+ else if (none.length > 0) {
327
+ out.outcome = out.changes.length > 0 ? "classified" : "unclassified";
328
+ notes.push(`no rule covers ${none.join("; ")}`);
329
+ }
330
+ if (notes.length > 0)
331
+ out.note = notes.join("; ");
332
+ return out;
333
+ });
334
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Stream engines (#4396): Kafka, S3Queue, AzureQueue, RabbitMQ, NATS and
3
+ * FileLog. A table on one of them stores no rows. It is a consumer: the
4
+ * materialized views that read it pull messages (or files) through it into a
5
+ * target, and the position it has reached lives outside the table, in the
6
+ * broker's committed offsets or in Keeper.
7
+ *
8
+ * What follows from that, and what this file holds:
9
+ *
10
+ * - There is no ALTER for the engine's arguments, and nothing to copy to a
11
+ * new table, so a change is neither `metadata` nor a `rebuild`: the table is
12
+ * replaced, with the views that read it detached around the replacement
13
+ * (SQLCH225, `./rules.ts`).
14
+ * - A replacement can lose the table's position. The two changes that do
15
+ * are found here and reported on the change as a note.
16
+ */
17
+ import type { CanonicalObject } from "./normalize.js";
18
+ /** The stream engines, as `system.tables.engine` names them. */
19
+ export declare const STREAM_ENGINES: ReadonlySet<string>;
20
+ /** Whether an engine name is a stream engine. */
21
+ export declare const isStreamEngine: (engine: string | undefined) => boolean;
22
+ /** Whether a canonical table is on a stream engine. */
23
+ export declare const isStreamTable: (o: CanonicalObject) => boolean;
24
+ /** The arguments inside an engine's parentheses, split at top-level commas, string quotes removed. Empty when it has none. */
25
+ export declare function streamEngineArguments(engine: string | undefined): string[];
26
+ /**
27
+ * What a replacement would lose, in a sentence each (#4396):
28
+ *
29
+ * - a different `kafka_group_name` is a different consumer group: it starts
30
+ * from the group's committed offsets, or from the topic's start when the
31
+ * group has none (`auto.offset.reset`);
32
+ * - a different S3Queue `keeper_path` is a different place for the table's
33
+ * record of processed files, so every file already seen is processed again.
34
+ *
35
+ * Neither is a refusal: a new group or path is sometimes the point.
36
+ */
37
+ export declare function positionWarnings(before: CanonicalObject, after: CanonicalObject): string[];
38
+ /** Whether a materialized view reads from the table: its SELECT names the table, qualified or, in the table's own database, bare. */
39
+ export declare function readsTable(view: CanonicalObject, table: CanonicalObject): boolean;
40
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/clickhouse/plan/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,gEAAgE;AAChE,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,CAA8E,CAAC;AAE9H,iDAAiD;AACjD,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,GAAG,SAAS,KAAG,OAA6D,CAAC;AAE1H,uDAAuD;AACvD,eAAO,MAAM,aAAa,GAAI,GAAG,eAAe,KAAG,OAA6D,CAAC;AAEjH,8HAA8H;AAC9H,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CA0B1E;AAWD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,eAAe,GAAG,MAAM,EAAE,CAsB1F;AAED,qIAAqI;AACrI,wBAAgB,UAAU,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAQjF"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Stream engines (#4396): Kafka, S3Queue, AzureQueue, RabbitMQ, NATS and
3
+ * FileLog. A table on one of them stores no rows. It is a consumer: the
4
+ * materialized views that read it pull messages (or files) through it into a
5
+ * target, and the position it has reached lives outside the table, in the
6
+ * broker's committed offsets or in Keeper.
7
+ *
8
+ * What follows from that, and what this file holds:
9
+ *
10
+ * - There is no ALTER for the engine's arguments, and nothing to copy to a
11
+ * new table, so a change is neither `metadata` nor a `rebuild`: the table is
12
+ * replaced, with the views that read it detached around the replacement
13
+ * (SQLCH225, `./rules.ts`).
14
+ * - A replacement can lose the table's position. The two changes that do
15
+ * are found here and reported on the change as a note.
16
+ */
17
+ /** The stream engines, as `system.tables.engine` names them. */
18
+ export const STREAM_ENGINES = new Set(["Kafka", "S3Queue", "AzureQueue", "RabbitMQ", "NATS", "FileLog"]);
19
+ /** Whether an engine name is a stream engine. */
20
+ export const isStreamEngine = (engine) => engine !== undefined && STREAM_ENGINES.has(engine);
21
+ /** Whether a canonical table is on a stream engine. */
22
+ export const isStreamTable = (o) => o.kind === "table" && isStreamEngine(o.engineName);
23
+ /** The arguments inside an engine's parentheses, split at top-level commas, string quotes removed. Empty when it has none. */
24
+ export function streamEngineArguments(engine) {
25
+ const open = engine?.indexOf("(") ?? -1;
26
+ if (engine === undefined || open < 0 || !engine.endsWith(")"))
27
+ return [];
28
+ const inner = engine.slice(open + 1, -1);
29
+ const out = [];
30
+ let depth = 0;
31
+ let quote;
32
+ let cur = "";
33
+ for (let i = 0; i < inner.length; i++) {
34
+ const ch = inner[i];
35
+ if (quote) {
36
+ cur += ch;
37
+ if (ch === "\\")
38
+ cur += inner[++i] ?? "";
39
+ else if (ch === quote)
40
+ quote = undefined;
41
+ continue;
42
+ }
43
+ if (ch === "'" || ch === '"' || ch === "`")
44
+ quote = ch;
45
+ if (ch === "(" || ch === "[")
46
+ depth++;
47
+ if (ch === ")" || ch === "]")
48
+ depth--;
49
+ if (ch === "," && depth === 0) {
50
+ out.push(cur.trim());
51
+ cur = "";
52
+ }
53
+ else
54
+ cur += ch;
55
+ }
56
+ if (cur.trim())
57
+ out.push(cur.trim());
58
+ return out.map((a) => (/^'.*'$/.test(a) ? a.slice(1, -1) : a));
59
+ }
60
+ /** Kafka's positional arguments, in the order the engine takes them. */
61
+ const KAFKA_POSITIONAL = ["kafka_broker_list", "kafka_topic_list", "kafka_group_name", "kafka_format"];
62
+ /** A Kafka setting, from SETTINGS or from the engine's positional arguments. */
63
+ function kafkaSetting(o, name) {
64
+ const at = KAFKA_POSITIONAL.indexOf(name);
65
+ return o.settings[name] ?? (at >= 0 ? streamEngineArguments(o.engine)[at] : undefined);
66
+ }
67
+ /**
68
+ * What a replacement would lose, in a sentence each (#4396):
69
+ *
70
+ * - a different `kafka_group_name` is a different consumer group: it starts
71
+ * from the group's committed offsets, or from the topic's start when the
72
+ * group has none (`auto.offset.reset`);
73
+ * - a different S3Queue `keeper_path` is a different place for the table's
74
+ * record of processed files, so every file already seen is processed again.
75
+ *
76
+ * Neither is a refusal: a new group or path is sometimes the point.
77
+ */
78
+ export function positionWarnings(before, after) {
79
+ const out = [];
80
+ if (before.engineName === "Kafka" && after.engineName === "Kafka") {
81
+ const b = kafkaSetting(before, "kafka_group_name");
82
+ const a = kafkaSetting(after, "kafka_group_name");
83
+ if (b !== a) {
84
+ out.push(`kafka_group_name changes from ${b ?? "none"} to ${a ?? "none"}: the new group starts from its own committed offsets, or from the start of the topic when it has none, ` +
85
+ "so messages already consumed may be read again or skipped");
86
+ }
87
+ }
88
+ if (before.engineName === "S3Queue" && after.engineName === "S3Queue") {
89
+ const b = before.settings.keeper_path;
90
+ const a = after.settings.keeper_path;
91
+ if (b !== a) {
92
+ out.push(`keeper_path changes from ${b ?? "none"} to ${a ?? "none"}: the new path holds no record of processed files, so every file already seen is processed again`);
93
+ }
94
+ }
95
+ return out;
96
+ }
97
+ /** Whether a materialized view reads from the table: its SELECT names the table, qualified or, in the table's own database, bare. */
98
+ export function readsTable(view, table) {
99
+ if (view.kind !== "materializedView" || view.select === undefined)
100
+ return false;
101
+ const escaped = table.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
102
+ const sameDatabase = view.database === table.database;
103
+ const database = table.database?.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
104
+ // The canonical SELECT drops the view's own database from a name, so a bare name is a table in the view's database.
105
+ const names = [...(sameDatabase ? [escaped] : []), ...(database ? [`${database}\\s*\\.\\s*${escaped}`] : [])];
106
+ return names.some((n) => new RegExp(`(?:^|[^\\w.])${n}(?![\\w.])`).test(view.select));
107
+ }
@@ -27,7 +27,9 @@
27
27
  *
28
28
  * Anything else is refused with a {@link RebuildRefusal}: a database that is
29
29
  * neither Atomic nor Replicated, a table that is not there, a change that is
30
- * not a rebuild, a working object chant did not make.
30
+ * not a rebuild, a working object chant did not make, a table on a stream
31
+ * engine (Kafka, S3Queue, AzureQueue, RabbitMQ, NATS, FileLog), which holds no
32
+ * rows to copy and is replaced by the applier instead (#4396).
31
33
  *
32
34
  * A Replicated database (#3249) is Atomic on every replica, with its DDL run
33
35
  * on each through Keeper, so the same EXCHANGE swaps the table everywhere.
@@ -1 +1 @@
1
- {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../../src/clickhouse/rebuild/observe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../../src/clickhouse/rebuild/observe.ts"],"names":[],"mappings":"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"}
@@ -27,7 +27,9 @@
27
27
  *
28
28
  * Anything else is refused with a {@link RebuildRefusal}: a database that is
29
29
  * neither Atomic nor Replicated, a table that is not there, a change that is
30
- * not a rebuild, a working object chant did not make.
30
+ * not a rebuild, a working object chant did not make, a table on a stream
31
+ * engine (Kafka, S3Queue, AzureQueue, RabbitMQ, NATS, FileLog), which holds no
32
+ * rows to copy and is replaced by the applier instead (#4396).
31
33
  *
32
34
  * A Replicated database (#3249) is Atomic on every replica, with its DDL run
33
35
  * on each through Keeper, so the same EXCHANGE swaps the table everywhere.
@@ -44,6 +46,7 @@ import { dropFormattingOnly } from "../plan/server-format.js";
44
46
  import { CLASSIFIER_RULES } from "../plan/rules.js";
45
47
  import { CLICKHOUSE_ENTITY_TYPES } from "../entities.js";
46
48
  import { carriesMarker, readTrailerPairs, REBUILD_TRAILER_KEY, stripMarkerFromStatement } from "../ownership.js";
49
+ import { isStreamEngine } from "../plan/stream.js";
47
50
  import { ident, isRebuild, qualifiedIdent, sqlString } from "../apply/statements.js";
48
51
  /** A refusal: the rebuild cannot start, or cannot go on, for a reason a person has to act on. */
49
52
  export class RebuildRefusal extends Error {
@@ -140,10 +143,18 @@ function ownWorkingObject(o, names, role, marker) {
140
143
  }
141
144
  return o;
142
145
  }
146
+ /** The refusal for a stream-engine table, naming the engine and where its change goes instead (#4396). */
147
+ function streamRefusal(key, engine, side) {
148
+ return new RebuildRefusal(`${key} is ${side === "declared" ? "declared on" : "on the server as"} the ${engine} engine, a stream engine: it stores no rows, so there is nothing to backfill, and a direct SELECT from it either fails ` +
149
+ `or consumes messages. A change to it is SQLCH225 (replace a stream table), which the applier makes in place: it detaches the materialized views that read the table, drops and creates it, and attaches the views again ` +
150
+ `(ApplyOp with target "clickhouse").`);
151
+ }
143
152
  /** Observe the rebuild of the declared table on the server. */
144
153
  export async function observeRebuild(target, declared, marker) {
145
154
  const database = declared.canonical.database ?? target.defaultDatabase;
146
155
  const names = rebuildNames(database, declared.canonical.name);
156
+ if (isStreamEngine(declared.canonical.engineName))
157
+ throw streamRefusal(names.key, declared.canonical.engineName, "declared");
147
158
  const [db] = await clickhouseQuery(target.endpoint, `SELECT engine FROM system.databases WHERE name = ${sqlString(database)}`);
148
159
  if (!db)
149
160
  throw new RebuildRefusal(`database ${database} is not on the server, so there is no ${names.key} to rebuild; the applier creates it`);
@@ -160,6 +171,8 @@ export async function observeRebuild(target, declared, marker) {
160
171
  // Between EXCHANGE and the end of the swap, the table's own name holds the
161
172
  // new table, still carrying role=new, and the new table's name holds the
162
173
  // old table until it is renamed; the swap step finishes that.
174
+ if (isStreamEngine(liveRow.engine))
175
+ throw streamRefusal(names.key, liveRow.engine, "live");
163
176
  const exchanged = liveRow.pairs?.get(REBUILD_TRAILER_KEY) === names.key && liveRow.pairs.get("role") === "new";
164
177
  const newTable = exchanged ? undefined : ownWorkingObject(objects.get(names.newName), names, "new", marker);
165
178
  const exchangedOld = exchanged ? objects.get(names.newName) : undefined;