rubydb 0.1.0

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 (436) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  4. data/.github/ISSUE_TEMPLATE/feature.yml +0 -0
  5. data/.github/ISSUE_TEMPLATE/performance.yml +0 -0
  6. data/.github/ISSUE_TEMPLATE/security.yml +0 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  8. data/.github/dependabot.yml +0 -0
  9. data/.github/workflows/benchmark.yml +26 -0
  10. data/.github/workflows/compatibility.yml +63 -0
  11. data/.github/workflows/fuzz.yml +33 -0
  12. data/.github/workflows/lint.yml +21 -0
  13. data/.github/workflows/operations.yml +24 -0
  14. data/.github/workflows/production-validation.yml +111 -0
  15. data/.github/workflows/release.yml +77 -0
  16. data/.github/workflows/security.yml +37 -0
  17. data/.github/workflows/test.yml +26 -0
  18. data/.github/workflows/workload.yml +58 -0
  19. data/.gitignore +43 -0
  20. data/.rspec +4 -0
  21. data/.rubocop.yml +44 -0
  22. data/.ruby-version +1 -0
  23. data/.standard.yml +14 -0
  24. data/ARCHITECTURE.md +21 -0
  25. data/CHANGELOG.md +31 -0
  26. data/CODE_OF_CONDUCT.md +13 -0
  27. data/CONTRIBUTING.md +29 -0
  28. data/GOVERNANCE.md +16 -0
  29. data/Gemfile +17 -0
  30. data/Gemfile.lock +71 -0
  31. data/LICENSE +60 -0
  32. data/README.md +162 -0
  33. data/ROADMAP.md +27 -0
  34. data/Rakefile +71 -0
  35. data/SECURITY.md +54 -0
  36. data/SUPPORT.md +14 -0
  37. data/adapters/activerecord/Gemfile +11 -0
  38. data/adapters/activerecord/README.md +9 -0
  39. data/adapters/activerecord/lib/active_record/connection_adapters/rubydb_adapter.rb +887 -0
  40. data/adapters/activerecord/rubydb-activerecord.gemspec +27 -0
  41. data/adapters/activerecord/spec/rubydb_adapter_integration_spec.rb +151 -0
  42. data/adapters/ruby/README.md +18 -0
  43. data/adapters/sequel/README.md +11 -0
  44. data/bin/rubydb +19 -0
  45. data/bin/rubydb-server +126 -0
  46. data/config/development.yml +0 -0
  47. data/config/monitoring/prometheus-alerts.yml +39 -0
  48. data/config/production.yml +36 -0
  49. data/config/test.yml +0 -0
  50. data/docs/README.md +71 -0
  51. data/docs/architecture/concurrency.md +14 -0
  52. data/docs/architecture/current-state.md +125 -0
  53. data/docs/architecture/execution-engine.md +25 -0
  54. data/docs/architecture/indexes.md +19 -0
  55. data/docs/architecture/mvcc.md +19 -0
  56. data/docs/architecture/overview.md +13 -0
  57. data/docs/architecture/pages.md +11 -0
  58. data/docs/architecture/production-roadmap.md +82 -0
  59. data/docs/architecture/query-planner.md +20 -0
  60. data/docs/architecture/recovery.md +18 -0
  61. data/docs/architecture/sql-engine.md +12 -0
  62. data/docs/architecture/storage-engine.md +14 -0
  63. data/docs/architecture/transactions.md +10 -0
  64. data/docs/architecture/wal.md +28 -0
  65. data/docs/cli-cheatsheet.md +98 -0
  66. data/docs/cli.md +275 -0
  67. data/docs/contributing/architecture.md +9 -0
  68. data/docs/contributing/benchmarking.md +14 -0
  69. data/docs/contributing/development.md +16 -0
  70. data/docs/contributing/release-process.md +49 -0
  71. data/docs/contributing/testing.md +16 -0
  72. data/docs/debugging.md +229 -0
  73. data/docs/developer/branching.md +10 -0
  74. data/docs/developer/database-diff.md +10 -0
  75. data/docs/developer/local-development.md +17 -0
  76. data/docs/developer/snapshots.md +9 -0
  77. data/docs/developer/temporal-data.md +10 -0
  78. data/docs/developer-guide.md +297 -0
  79. data/docs/getting-started/first-database.md +16 -0
  80. data/docs/getting-started/first-query.md +13 -0
  81. data/docs/getting-started/installation.md +19 -0
  82. data/docs/getting-started/local-to-production.md +300 -0
  83. data/docs/getting-started/quickstart.md +17 -0
  84. data/docs/getting-started/rails.md +16 -0
  85. data/docs/hardening_backlog.md +93 -0
  86. data/docs/lessons-learned.md +112 -0
  87. data/docs/operations/backups.md +33 -0
  88. data/docs/operations/disaster-recovery.md +31 -0
  89. data/docs/operations/failover.md +30 -0
  90. data/docs/operations/monitoring.md +25 -0
  91. data/docs/operations/production-guide.md +295 -0
  92. data/docs/operations/production-runbook.md +45 -0
  93. data/docs/operations/replication.md +33 -0
  94. data/docs/operations/restore.md +6 -0
  95. data/docs/operations/runbook.md +34 -0
  96. data/docs/operations/upgrades.md +14 -0
  97. data/docs/operations/workload-testing.md +17 -0
  98. data/docs/production-readiness.md +118 -0
  99. data/docs/production_validation.md +150 -0
  100. data/docs/rails/active-record.md +11 -0
  101. data/docs/rails/compatibility-guide.md +90 -0
  102. data/docs/rails/database-yml.md +92 -0
  103. data/docs/rails/installation.md +17 -0
  104. data/docs/rails/migrations.md +17 -0
  105. data/docs/rails/production.md +82 -0
  106. data/docs/rails/troubleshooting.md +18 -0
  107. data/docs/release.md +59 -0
  108. data/docs/server/architecture.md +10 -0
  109. data/docs/server/authentication.md +10 -0
  110. data/docs/server/configuration.md +16 -0
  111. data/docs/server/connection-pooling.md +10 -0
  112. data/docs/server/deployment.md +10 -0
  113. data/docs/server/protocol.md +12 -0
  114. data/docs/sql/compatibility-guide.md +82 -0
  115. data/docs/sql/compatibility.md +39 -0
  116. data/docs/sql/data-types.md +10 -0
  117. data/docs/sql/functions.md +9 -0
  118. data/docs/sql/joins.md +9 -0
  119. data/docs/sql/operators.md +9 -0
  120. data/docs/sql/sqlite-compatibility.md +21 -0
  121. data/docs/sql/syntax.md +10 -0
  122. data/docs/sql/transactions.md +10 -0
  123. data/docs/troubleshooting.md +244 -0
  124. data/exe/rubydb +23 -0
  125. data/lib/rubydb/backup/archive.rb +334 -0
  126. data/lib/rubydb/backup/backup.rb +401 -0
  127. data/lib/rubydb/backup/incremental.rb +353 -0
  128. data/lib/rubydb/backup/restore.rb +290 -0
  129. data/lib/rubydb/backup/snapshot.rb +267 -0
  130. data/lib/rubydb/backup/verification.rb +279 -0
  131. data/lib/rubydb/branching/branch.rb +181 -0
  132. data/lib/rubydb/branching/branch_manager.rb +311 -0
  133. data/lib/rubydb/branching/branch_metadata.rb +140 -0
  134. data/lib/rubydb/branching/checkout.rb +166 -0
  135. data/lib/rubydb/branching/copy_on_write.rb +272 -0
  136. data/lib/rubydb/branching/diff.rb +138 -0
  137. data/lib/rubydb/branching/merge.rb +285 -0
  138. data/lib/rubydb/build_info.rb +15 -0
  139. data/lib/rubydb/catalog/catalog.rb +391 -0
  140. data/lib/rubydb/catalog/column.rb +112 -0
  141. data/lib/rubydb/catalog/constraint.rb +180 -0
  142. data/lib/rubydb/catalog/database.rb +184 -0
  143. data/lib/rubydb/catalog/index.rb +97 -0
  144. data/lib/rubydb/catalog/schema.rb +103 -0
  145. data/lib/rubydb/catalog/sequence.rb +90 -0
  146. data/lib/rubydb/catalog/system_catalog.rb +698 -0
  147. data/lib/rubydb/catalog/table.rb +178 -0
  148. data/lib/rubydb/catalog/trigger.rb +102 -0
  149. data/lib/rubydb/catalog/view.rb +66 -0
  150. data/lib/rubydb/cli/application.rb +163 -0
  151. data/lib/rubydb/cli/commands/backup.rb +81 -0
  152. data/lib/rubydb/cli/commands/branch.rb +72 -0
  153. data/lib/rubydb/cli/commands/checkout.rb +54 -0
  154. data/lib/rubydb/cli/commands/create.rb +58 -0
  155. data/lib/rubydb/cli/commands/diff.rb +77 -0
  156. data/lib/rubydb/cli/commands/doctor.rb +74 -0
  157. data/lib/rubydb/cli/commands/drop.rb +57 -0
  158. data/lib/rubydb/cli/commands/init.rb +102 -0
  159. data/lib/rubydb/cli/commands/inspect.rb +95 -0
  160. data/lib/rubydb/cli/commands/merge.rb +63 -0
  161. data/lib/rubydb/cli/commands/migrate.rb +62 -0
  162. data/lib/rubydb/cli/commands/restart.rb +39 -0
  163. data/lib/rubydb/cli/commands/restore.rb +121 -0
  164. data/lib/rubydb/cli/commands/shell.rb +365 -0
  165. data/lib/rubydb/cli/commands/snapshot.rb +79 -0
  166. data/lib/rubydb/cli/commands/start.rb +82 -0
  167. data/lib/rubydb/cli/commands/status.rb +92 -0
  168. data/lib/rubydb/cli/commands/stop.rb +47 -0
  169. data/lib/rubydb/cli/commands/vacuum.rb +58 -0
  170. data/lib/rubydb/cli/formatter.rb +221 -0
  171. data/lib/rubydb/cli/output.rb +168 -0
  172. data/lib/rubydb/client/client.rb +304 -0
  173. data/lib/rubydb/client/connection.rb +415 -0
  174. data/lib/rubydb/client/connection_pool.rb +168 -0
  175. data/lib/rubydb/client/connection_url.rb +96 -0
  176. data/lib/rubydb/client/prepared_statement.rb +60 -0
  177. data/lib/rubydb/client/result.rb +123 -0
  178. data/lib/rubydb/client/statement.rb +52 -0
  179. data/lib/rubydb/client/transaction.rb +130 -0
  180. data/lib/rubydb/concurrency/concurrency.rb +19 -0
  181. data/lib/rubydb/concurrency/deadlock_detector.rb +150 -0
  182. data/lib/rubydb/concurrency/latch.rb +101 -0
  183. data/lib/rubydb/concurrency/lock_graph.rb +165 -0
  184. data/lib/rubydb/concurrency/mutex.rb +183 -0
  185. data/lib/rubydb/concurrency/rw_lock.rb +180 -0
  186. data/lib/rubydb/concurrency/scheduler.rb +250 -0
  187. data/lib/rubydb/concurrency/worker_pool.rb +143 -0
  188. data/lib/rubydb/configuration/config.rb +170 -0
  189. data/lib/rubydb/configuration/defaults.rb +179 -0
  190. data/lib/rubydb/configuration/environment.rb +152 -0
  191. data/lib/rubydb/configuration/parser.rb +185 -0
  192. data/lib/rubydb/configuration/validation.rb +221 -0
  193. data/lib/rubydb/constants.rb +74 -0
  194. data/lib/rubydb/constraints/check.rb +181 -0
  195. data/lib/rubydb/constraints/constraint.rb +101 -0
  196. data/lib/rubydb/constraints/foreign_key.rb +130 -0
  197. data/lib/rubydb/constraints/not_null.rb +64 -0
  198. data/lib/rubydb/constraints/primary_key.rb +99 -0
  199. data/lib/rubydb/constraints/unique.rb +108 -0
  200. data/lib/rubydb/constraints/validator.rb +350 -0
  201. data/lib/rubydb/errors/authentication_error.rb +10 -0
  202. data/lib/rubydb/errors/authorization_error.rb +23 -0
  203. data/lib/rubydb/errors/client_error.rb +10 -0
  204. data/lib/rubydb/errors/configuration_error.rb +10 -0
  205. data/lib/rubydb/errors/connection_error.rb +10 -0
  206. data/lib/rubydb/errors/constraint_error.rb +23 -0
  207. data/lib/rubydb/errors/corruption_error.rb +10 -0
  208. data/lib/rubydb/errors/database_error.rb +10 -0
  209. data/lib/rubydb/errors/error.rb +20 -0
  210. data/lib/rubydb/errors/execution_error.rb +10 -0
  211. data/lib/rubydb/errors/parser_error.rb +10 -0
  212. data/lib/rubydb/errors/recovery_error.rb +10 -0
  213. data/lib/rubydb/errors/replication_error.rb +10 -0
  214. data/lib/rubydb/errors/server_error.rb +6 -0
  215. data/lib/rubydb/errors/storage_error.rb +10 -0
  216. data/lib/rubydb/errors/transaction_error.rb +10 -0
  217. data/lib/rubydb/execution/aggregate_executor.rb +138 -0
  218. data/lib/rubydb/execution/delete_executor.rb +112 -0
  219. data/lib/rubydb/execution/distinct_executor.rb +135 -0
  220. data/lib/rubydb/execution/executor.rb +1192 -0
  221. data/lib/rubydb/execution/expression.rb +193 -0
  222. data/lib/rubydb/execution/index_scan.rb +142 -0
  223. data/lib/rubydb/execution/insert_executor.rb +217 -0
  224. data/lib/rubydb/execution/join_executor.rb +249 -0
  225. data/lib/rubydb/execution/limit_executor.rb +85 -0
  226. data/lib/rubydb/execution/optimizer.rb +215 -0
  227. data/lib/rubydb/execution/plan.rb +361 -0
  228. data/lib/rubydb/execution/planner.rb +546 -0
  229. data/lib/rubydb/execution/predicate.rb +235 -0
  230. data/lib/rubydb/execution/scan.rb +49 -0
  231. data/lib/rubydb/execution/sequential_scan.rb +63 -0
  232. data/lib/rubydb/execution/sort_executor.rb +185 -0
  233. data/lib/rubydb/execution/update_executor.rb +162 -0
  234. data/lib/rubydb/functions/aggregate.rb +70 -0
  235. data/lib/rubydb/functions/date_functions.rb +278 -0
  236. data/lib/rubydb/functions/function.rb +85 -0
  237. data/lib/rubydb/functions/json_functions.rb +215 -0
  238. data/lib/rubydb/functions/numeric_functions.rb +346 -0
  239. data/lib/rubydb/functions/scalar.rb +52 -0
  240. data/lib/rubydb/functions/string_functions.rb +383 -0
  241. data/lib/rubydb/functions/system_functions.rb +246 -0
  242. data/lib/rubydb/history/as_of.rb +238 -0
  243. data/lib/rubydb/history/change.rb +105 -0
  244. data/lib/rubydb/history/history.rb +131 -0
  245. data/lib/rubydb/history/history_manager.rb +229 -0
  246. data/lib/rubydb/history/temporal_query.rb +202 -0
  247. data/lib/rubydb/history/timeline.rb +144 -0
  248. data/lib/rubydb/indexes/btree.rb +186 -0
  249. data/lib/rubydb/indexes/btree_cursor.rb +258 -0
  250. data/lib/rubydb/indexes/btree_node.rb +385 -0
  251. data/lib/rubydb/indexes/hash_index.rb +150 -0
  252. data/lib/rubydb/indexes/index.rb +71 -0
  253. data/lib/rubydb/indexes/index_manager.rb +406 -0
  254. data/lib/rubydb/indexes/index_scan.rb +470 -0
  255. data/lib/rubydb/migrations/migration.rb +254 -0
  256. data/lib/rubydb/migrations/migration_lock.rb +146 -0
  257. data/lib/rubydb/migrations/migration_manager.rb +176 -0
  258. data/lib/rubydb/migrations/migration_version.rb +71 -0
  259. data/lib/rubydb/migrations/schema_diff.rb +211 -0
  260. data/lib/rubydb/migrations/schema_version.rb +64 -0
  261. data/lib/rubydb/monitoring/events.rb +160 -0
  262. data/lib/rubydb/monitoring/health.rb +222 -0
  263. data/lib/rubydb/monitoring/logger.rb +193 -0
  264. data/lib/rubydb/monitoring/metrics.rb +359 -0
  265. data/lib/rubydb/monitoring/performance.rb +176 -0
  266. data/lib/rubydb/monitoring/statistics.rb +170 -0
  267. data/lib/rubydb/mvcc/garbage_collector.rb +199 -0
  268. data/lib/rubydb/mvcc/mvcc.rb +16 -0
  269. data/lib/rubydb/mvcc/snapshot.rb +147 -0
  270. data/lib/rubydb/mvcc/vacuum.rb +180 -0
  271. data/lib/rubydb/mvcc/version.rb +106 -0
  272. data/lib/rubydb/mvcc/version_store.rb +398 -0
  273. data/lib/rubydb/mvcc/visibility.rb +109 -0
  274. data/lib/rubydb/protocol/capabilities.rb +125 -0
  275. data/lib/rubydb/protocol/decoder.rb +145 -0
  276. data/lib/rubydb/protocol/encoder.rb +136 -0
  277. data/lib/rubydb/protocol/handshake.rb +305 -0
  278. data/lib/rubydb/protocol/message.rb +121 -0
  279. data/lib/rubydb/protocol/protocol.rb +277 -0
  280. data/lib/rubydb/protocol/version.rb +54 -0
  281. data/lib/rubydb/rails/adapter.rb +239 -0
  282. data/lib/rubydb/rails/connection.rb +314 -0
  283. data/lib/rubydb/rails/database_statements.rb +122 -0
  284. data/lib/rubydb/rails/migration.rb +131 -0
  285. data/lib/rubydb/rails/quoting.rb +109 -0
  286. data/lib/rubydb/rails/result.rb +120 -0
  287. data/lib/rubydb/rails/schema_statements.rb +339 -0
  288. data/lib/rubydb/rails/transaction.rb +105 -0
  289. data/lib/rubydb/rails/type.rb +126 -0
  290. data/lib/rubydb/recovery/checkpoint.rb +257 -0
  291. data/lib/rubydb/recovery/consistency.rb +467 -0
  292. data/lib/rubydb/recovery/corruption_detector.rb +5 -0
  293. data/lib/rubydb/recovery/crash_recovery.rb +387 -0
  294. data/lib/rubydb/recovery/recovery_manager.rb +206 -0
  295. data/lib/rubydb/recovery/redo.rb +237 -0
  296. data/lib/rubydb/recovery/undo.rb +206 -0
  297. data/lib/rubydb/replication/failover.rb +5 -0
  298. data/lib/rubydb/replication/fencing.rb +63 -0
  299. data/lib/rubydb/replication/primary.rb +450 -0
  300. data/lib/rubydb/replication/replica.rb +384 -0
  301. data/lib/rubydb/replication/replication_log.rb +200 -0
  302. data/lib/rubydb/replication/replication_manager.rb +308 -0
  303. data/lib/rubydb/replication/replication_slot.rb +295 -0
  304. data/lib/rubydb/replication/replication_stream.rb +201 -0
  305. data/lib/rubydb/rubydb.rb +560 -0
  306. data/lib/rubydb/security/access_control.rb +254 -0
  307. data/lib/rubydb/security/audit_log.rb +213 -0
  308. data/lib/rubydb/security/authentication.rb +302 -0
  309. data/lib/rubydb/security/authorization.rb +282 -0
  310. data/lib/rubydb/security/credentials.rb +196 -0
  311. data/lib/rubydb/security/password.rb +215 -0
  312. data/lib/rubydb/security/permissions.rb +74 -0
  313. data/lib/rubydb/security/role.rb +101 -0
  314. data/lib/rubydb/security/user.rb +86 -0
  315. data/lib/rubydb/server/connection.rb +366 -0
  316. data/lib/rubydb/server/connection_pool.rb +193 -0
  317. data/lib/rubydb/server/lifecycle.rb +228 -0
  318. data/lib/rubydb/server/listener.rb +136 -0
  319. data/lib/rubydb/server/request_handler.rb +276 -0
  320. data/lib/rubydb/server/server.rb +364 -0
  321. data/lib/rubydb/server/session.rb +369 -0
  322. data/lib/rubydb/server/worker.rb +210 -0
  323. data/lib/rubydb/server/worker_pool.rb +168 -0
  324. data/lib/rubydb/sql/ast/alter_table.rb +169 -0
  325. data/lib/rubydb/sql/ast/begin_transaction.rb +47 -0
  326. data/lib/rubydb/sql/ast/commit.rb +37 -0
  327. data/lib/rubydb/sql/ast/constraint.rb +83 -0
  328. data/lib/rubydb/sql/ast/create_database.rb +41 -0
  329. data/lib/rubydb/sql/ast/create_index.rb +61 -0
  330. data/lib/rubydb/sql/ast/create_schema.rb +52 -0
  331. data/lib/rubydb/sql/ast/create_table.rb +187 -0
  332. data/lib/rubydb/sql/ast/delete.rb +54 -0
  333. data/lib/rubydb/sql/ast/drop_database.rb +41 -0
  334. data/lib/rubydb/sql/ast/drop_index.rb +41 -0
  335. data/lib/rubydb/sql/ast/drop_schema.rb +49 -0
  336. data/lib/rubydb/sql/ast/drop_table.rb +49 -0
  337. data/lib/rubydb/sql/ast/explain.rb +64 -0
  338. data/lib/rubydb/sql/ast/expression.rb +604 -0
  339. data/lib/rubydb/sql/ast/insert.rb +82 -0
  340. data/lib/rubydb/sql/ast/node.rb +42 -0
  341. data/lib/rubydb/sql/ast/rollback.rb +63 -0
  342. data/lib/rubydb/sql/ast/savepoint.rb +59 -0
  343. data/lib/rubydb/sql/ast/select.rb +88 -0
  344. data/lib/rubydb/sql/ast/set_operation.rb +20 -0
  345. data/lib/rubydb/sql/ast/trigger.rb +29 -0
  346. data/lib/rubydb/sql/ast/update.rb +88 -0
  347. data/lib/rubydb/sql/ast/vacuum.rb +19 -0
  348. data/lib/rubydb/sql/ast/view.rb +32 -0
  349. data/lib/rubydb/sql/ast/with.rb +32 -0
  350. data/lib/rubydb/sql/grammar.rb +86 -0
  351. data/lib/rubydb/sql/keywords.rb +156 -0
  352. data/lib/rubydb/sql/lexer.rb +214 -0
  353. data/lib/rubydb/sql/operators.rb +100 -0
  354. data/lib/rubydb/sql/parser.rb +1185 -0
  355. data/lib/rubydb/sql/planner/analyzer.rb +302 -0
  356. data/lib/rubydb/sql/planner/binder.rb +550 -0
  357. data/lib/rubydb/sql/planner/type_checker.rb +431 -0
  358. data/lib/rubydb/sql/token.rb +210 -0
  359. data/lib/rubydb/storage/buffer_frame.rb +44 -0
  360. data/lib/rubydb/storage/buffer_pool.rb +155 -0
  361. data/lib/rubydb/storage/database_lock.rb +74 -0
  362. data/lib/rubydb/storage/deserializer.rb +342 -0
  363. data/lib/rubydb/storage/engine.rb +2338 -0
  364. data/lib/rubydb/storage/file_manager.rb +187 -0
  365. data/lib/rubydb/storage/free_space_map.rb +81 -0
  366. data/lib/rubydb/storage/page.rb +94 -0
  367. data/lib/rubydb/storage/page_allocator.rb +855 -0
  368. data/lib/rubydb/storage/page_header.rb +67 -0
  369. data/lib/rubydb/storage/page_manager.rb +131 -0
  370. data/lib/rubydb/storage/record.rb +58 -0
  371. data/lib/rubydb/storage/row.rb +78 -0
  372. data/lib/rubydb/storage/serializer.rb +51 -0
  373. data/lib/rubydb/storage/storage_layout.rb +151 -0
  374. data/lib/rubydb/storage/storage_manager.rb +114 -0
  375. data/lib/rubydb/storage/tuple.rb +461 -0
  376. data/lib/rubydb/storage/visibility_map.rb +984 -0
  377. data/lib/rubydb/transactions/commit_manager.rb +220 -0
  378. data/lib/rubydb/transactions/isolation.rb +98 -0
  379. data/lib/rubydb/transactions/lock.rb +76 -0
  380. data/lib/rubydb/transactions/lock_manager.rb +362 -0
  381. data/lib/rubydb/transactions/savepoint.rb +143 -0
  382. data/lib/rubydb/transactions/transaction.rb +215 -0
  383. data/lib/rubydb/transactions/transaction_id.rb +84 -0
  384. data/lib/rubydb/transactions/transaction_log.rb +257 -0
  385. data/lib/rubydb/transactions/transaction_manager.rb +435 -0
  386. data/lib/rubydb/types/bigint.rb +36 -0
  387. data/lib/rubydb/types/blob.rb +37 -0
  388. data/lib/rubydb/types/boolean.rb +34 -0
  389. data/lib/rubydb/types/date.rb +39 -0
  390. data/lib/rubydb/types/decimal.rb +48 -0
  391. data/lib/rubydb/types/float.rb +34 -0
  392. data/lib/rubydb/types/integer.rb +36 -0
  393. data/lib/rubydb/types/json.rb +41 -0
  394. data/lib/rubydb/types/null.rb +34 -0
  395. data/lib/rubydb/types/smallint.rb +36 -0
  396. data/lib/rubydb/types/text.rb +37 -0
  397. data/lib/rubydb/types/time.rb +46 -0
  398. data/lib/rubydb/types/timestamp.rb +39 -0
  399. data/lib/rubydb/types/type.rb +119 -0
  400. data/lib/rubydb/types/uuid.rb +47 -0
  401. data/lib/rubydb/types/varchar.rb +37 -0
  402. data/lib/rubydb/version.rb +33 -0
  403. data/lib/rubydb/wal/archive.rb +193 -0
  404. data/lib/rubydb/wal/checkpoint.rb +183 -0
  405. data/lib/rubydb/wal/lsn.rb +94 -0
  406. data/lib/rubydb/wal/reader.rb +260 -0
  407. data/lib/rubydb/wal/record.rb +105 -0
  408. data/lib/rubydb/wal/segment.rb +193 -0
  409. data/lib/rubydb/wal/wal.rb +452 -0
  410. data/lib/rubydb/wal/writer.rb +236 -0
  411. data/lib/rubydb.rb +7 -0
  412. data/packaging/docker/Dockerfile +36 -0
  413. data/packaging/docker/docker-compose.failover.yml +43 -0
  414. data/packaging/docker/entrypoint.sh +15 -0
  415. data/packaging/homebrew/rubydb.rb +19 -0
  416. data/packaging/systemd/rubydb.service +22 -0
  417. data/rubydb.gemspec +57 -0
  418. data/scripts/benchmark +7 -0
  419. data/scripts/durability_drill +37 -0
  420. data/scripts/format +0 -0
  421. data/scripts/fuzz +63 -0
  422. data/scripts/lint +0 -0
  423. data/scripts/release +50 -0
  424. data/scripts/release_check +43 -0
  425. data/scripts/replication_failover_drill +250 -0
  426. data/scripts/replication_network_failover_drill +255 -0
  427. data/scripts/restore_drill +45 -0
  428. data/scripts/security +0 -0
  429. data/scripts/setup +0 -0
  430. data/scripts/test +0 -0
  431. data/scripts/test-chaos +0 -0
  432. data/scripts/test-crash +0 -0
  433. data/scripts/test-integration +0 -0
  434. data/scripts/test-unit +0 -0
  435. data/visibility_map.json +1 -0
  436. metadata +538 -0
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ # ROLLBACK statement AST node
7
+ class Rollback < Node
8
+ attr_reader :chain
9
+
10
+ def initialize(chain: false, location: nil)
11
+ super(location: location)
12
+ @chain = chain
13
+ end
14
+
15
+ def accept(visitor)
16
+ visitor.visit_rollback(self)
17
+ end
18
+
19
+ def clone
20
+ Rollback.new(chain: @chain, location: @location)
21
+ end
22
+
23
+ def to_sql
24
+ parts = ["ROLLBACK"]
25
+ parts << "AND CHAIN" if @chain
26
+ parts.join(" ")
27
+ end
28
+
29
+ def inspect
30
+ str = "Rollback"
31
+ str << " (chain: true)" if @chain
32
+ str
33
+ end
34
+ end
35
+
36
+ # ROLLBACK TO SAVEPOINT statement AST node
37
+ class RollbackToSavepoint < Node
38
+ attr_reader :savepoint_name
39
+
40
+ def initialize(savepoint_name, location: nil)
41
+ super(location: location)
42
+ @savepoint_name = savepoint_name
43
+ end
44
+
45
+ def accept(visitor)
46
+ visitor.visit_rollback_to_savepoint(self)
47
+ end
48
+
49
+ def clone
50
+ RollbackToSavepoint.new(@savepoint_name, location: @location)
51
+ end
52
+
53
+ def to_sql
54
+ "ROLLBACK TO SAVEPOINT #{@savepoint_name}"
55
+ end
56
+
57
+ def inspect
58
+ "RollbackToSavepoint(savepoint: #{@savepoint_name})"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ # SAVEPOINT statement AST node
7
+ class Savepoint < Node
8
+ attr_reader :name
9
+
10
+ def initialize(name, location: nil)
11
+ super(location: location)
12
+ @name = name
13
+ end
14
+
15
+ def accept(visitor)
16
+ visitor.visit_savepoint(self)
17
+ end
18
+
19
+ def clone
20
+ Savepoint.new(@name, location: @location)
21
+ end
22
+
23
+ def to_sql
24
+ "SAVEPOINT #{@name}"
25
+ end
26
+
27
+ def inspect
28
+ "Savepoint(name: #{@name})"
29
+ end
30
+ end
31
+
32
+ # RELEASE SAVEPOINT statement AST node
33
+ class ReleaseSavepoint < Node
34
+ attr_reader :name
35
+
36
+ def initialize(name, location: nil)
37
+ super(location: location)
38
+ @name = name
39
+ end
40
+
41
+ def accept(visitor)
42
+ visitor.visit_release_savepoint(self)
43
+ end
44
+
45
+ def clone
46
+ ReleaseSavepoint.new(@name, location: @location)
47
+ end
48
+
49
+ def to_sql
50
+ "RELEASE SAVEPOINT #{@name}"
51
+ end
52
+
53
+ def inspect
54
+ "ReleaseSavepoint(name: #{@name})"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ # SELECT statement AST node
7
+ class Select < Node
8
+ attr_reader :columns, :from, :where, :order_by, :limit, :offset, :distinct, :group_by, :having, :joins
9
+
10
+ def initialize(columns, from, where = nil, order_by = nil, limit = nil, offset = nil, distinct = false, joins: [], group_by: [], having: nil, location: nil)
11
+ super(location: location)
12
+ @columns = columns
13
+ @from = from
14
+ @where = where
15
+ @order_by = order_by || []
16
+ @limit = limit
17
+ @offset = offset
18
+ @distinct = distinct
19
+ @group_by = group_by
20
+ @having = having
21
+ @joins = joins
22
+ end
23
+
24
+ def accept(visitor)
25
+ visitor.visit_select(self)
26
+ end
27
+
28
+ def clone
29
+ Select.new(
30
+ @columns.map(&:clone),
31
+ @from&.clone,
32
+ @where&.clone,
33
+ @order_by.map(&:clone),
34
+ @limit&.clone,
35
+ @offset&.clone,
36
+ @distinct,
37
+ joins: @joins.map(&:clone), group_by: @group_by.map(&:clone), having: @having&.clone,
38
+ location: @location
39
+ )
40
+ end
41
+
42
+ def to_sql
43
+ parts = []
44
+ parts << "SELECT"
45
+ parts << "DISTINCT" if @distinct
46
+ parts << @columns.map(&:to_sql).join(", ")
47
+ parts << "FROM #{@from.to_sql}" if @from
48
+ parts.concat(@joins.map(&:to_sql))
49
+ parts << "WHERE #{@where.to_sql}" if @where
50
+ parts << "GROUP BY #{@group_by.map(&:to_sql).join(', ')}" if @group_by.any?
51
+ parts << "HAVING #{@having.to_sql}" if @having
52
+ parts << "ORDER BY #{@order_by.map(&:to_sql).join(", ")}" if @order_by.any?
53
+ parts << "LIMIT #{@limit.to_sql}" if @limit
54
+ parts << "OFFSET #{@offset.to_sql}" if @offset
55
+ parts.join(" ")
56
+ end
57
+
58
+ def inspect
59
+ cols = @columns.map(&:inspect).join(", ")
60
+ str = "Select(columns: [#{cols}], from: #{@from.inspect}"
61
+ str << ", joins: #{@joins.map(&:inspect).join(', ')}" if @joins.any?
62
+ str << ", where: #{@where.inspect}" if @where
63
+ str << ", order_by: #{@order_by.map(&:inspect).join(", ")}" if @order_by.any?
64
+ str << ", limit: #{@limit.inspect}" if @limit
65
+ str << ", offset: #{@offset.inspect}" if @offset
66
+ str << ", distinct: true" if @distinct
67
+ str << ")"
68
+ str
69
+ end
70
+
71
+ # Helper methods for semantic analysis
72
+ def has_star?
73
+ @columns.any? do |col|
74
+ col.is_a?(Star) || (col.respond_to?(:expression) && col.expression.is_a?(Star))
75
+ end
76
+ end
77
+
78
+ def column_count
79
+ @columns.size
80
+ end
81
+
82
+ def table_name
83
+ @from&.name
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ class SetOperation < Node
7
+ attr_reader :left, :right, :operator, :all
8
+
9
+ def initialize(left, right, operator, all: false, location: nil)
10
+ super(location: location)
11
+ @left, @right, @operator, @all = left, right, operator, all
12
+ end
13
+
14
+ def accept(visitor) = visitor.visit_set_operation(self)
15
+ def clone = SetOperation.new(@left.clone, @right.clone, @operator, all: @all, location: @location)
16
+ def to_sql = "#{@left.to_sql} #{@operator.to_s.upcase}#{@all ? ' ALL' : ''} #{@right.to_sql}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ class CreateTrigger < Node
7
+ attr_reader :name, :timing, :event, :table_name, :function_name
8
+ def initialize(name, timing, event, table_name, function_name, location: nil)
9
+ super(location: location)
10
+ @name, @timing, @event, @table_name, @function_name = name, timing, event, table_name, function_name
11
+ end
12
+ def accept(visitor) = visitor.visit_create_trigger(self)
13
+ def clone = self.class.new(@name, @timing, @event, @table_name, @function_name, location: @location)
14
+ def to_sql = "CREATE TRIGGER #{@name} #{@timing.to_s.upcase} #{@event.to_s.upcase} ON #{@table_name} EXECUTE FUNCTION #{@function_name}()"
15
+ end
16
+
17
+ class DropTrigger < Node
18
+ attr_reader :name, :if_exists
19
+ def initialize(name, if_exists: false, location: nil)
20
+ super(location: location)
21
+ @name, @if_exists = name, if_exists
22
+ end
23
+ def accept(visitor) = visitor.visit_drop_trigger(self)
24
+ def clone = self.class.new(@name, if_exists: @if_exists, location: @location)
25
+ def to_sql = "DROP TRIGGER #{@name}"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ # UPDATE statement AST node
7
+ class Update < Node
8
+ attr_reader :table, :assignments, :where
9
+
10
+ def initialize(table, assignments, where = nil, location: nil)
11
+ super(location: location)
12
+ @table = table
13
+ @assignments = assignments
14
+ @where = where
15
+ end
16
+
17
+ def accept(visitor)
18
+ visitor.visit_update(self)
19
+ end
20
+
21
+ def clone
22
+ Update.new(
23
+ @table,
24
+ @assignments.map(&:clone),
25
+ @where&.clone,
26
+ location: @location
27
+ )
28
+ end
29
+
30
+ def to_sql
31
+ parts = []
32
+ parts << "UPDATE #{@table}"
33
+ parts << "SET #{@assignments.map(&:to_sql).join(", ")}"
34
+ parts << "WHERE #{@where.to_sql}" if @where
35
+ parts.join(" ")
36
+ end
37
+
38
+ def inspect
39
+ ass = @assignments.map(&:inspect).join(", ")
40
+ str = "Update(table: #{@table}, assignments: [#{ass}]"
41
+ str << ", where: #{@where.inspect}" if @where
42
+ str << ")"
43
+ str
44
+ end
45
+
46
+ # Helper methods
47
+ def assignment_count
48
+ @assignments.size
49
+ end
50
+
51
+ def has_where?
52
+ !@where.nil?
53
+ end
54
+
55
+ def updated_columns
56
+ @assignments.map(&:column)
57
+ end
58
+ end
59
+
60
+ # Assignment in UPDATE statement
61
+ class Assignment < Node
62
+ attr_reader :column, :value
63
+
64
+ def initialize(column, value, location: nil)
65
+ super(location: location)
66
+ @column = column
67
+ @value = value
68
+ end
69
+
70
+ def accept(visitor)
71
+ visitor.visit_assignment(self)
72
+ end
73
+
74
+ def clone
75
+ Assignment.new(@column, @value.clone, location: @location)
76
+ end
77
+
78
+ def to_sql
79
+ "#{@column} = #{@value.to_sql}"
80
+ end
81
+
82
+ def inspect
83
+ "Assignment(#{@column} = #{@value.inspect})"
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ class Vacuum < Node
7
+ def accept(visitor)
8
+ visitor.visit_vacuum(self)
9
+ end
10
+
11
+ def clone
12
+ self.class.new(location: @location)
13
+ end
14
+
15
+ def to_sql = "VACUUM"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ class CreateView < Node
7
+ attr_reader :name, :query, :if_not_exists
8
+ def initialize(name, query, if_not_exists: false, location: nil)
9
+ super(location: location)
10
+ @name = name
11
+ @query = query
12
+ @if_not_exists = if_not_exists
13
+ end
14
+ def accept(visitor) = visitor.visit_create_view(self)
15
+ def clone = self.class.new(@name, @query.clone, if_not_exists: @if_not_exists, location: @location)
16
+ def to_sql = "CREATE VIEW #{@name} AS #{@query.to_sql}"
17
+ end
18
+
19
+ class DropView < Node
20
+ attr_reader :name, :if_exists
21
+ def initialize(name, if_exists: false, location: nil)
22
+ super(location: location)
23
+ @name = name
24
+ @if_exists = if_exists
25
+ end
26
+ def accept(visitor) = visitor.visit_drop_view(self)
27
+ def clone = self.class.new(@name, if_exists: @if_exists, location: @location)
28
+ def to_sql = "DROP VIEW #{@name}"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ module AST
6
+ # A materialized WITH query. Recursive CTEs are evaluated iteratively by
7
+ # the executor with a bounded working set.
8
+ class With < Node
9
+ attr_reader :ctes, :query, :recursive
10
+
11
+ def initialize(ctes, query, recursive: false, location: nil)
12
+ super(location: location)
13
+ @ctes = ctes
14
+ @query = query
15
+ @recursive = recursive
16
+ end
17
+
18
+ def accept(visitor) = visitor.visit_with(self)
19
+
20
+ def clone
21
+ With.new(@ctes.map { |name, query| [name, query.clone] }, @query.clone, recursive: @recursive, location: @location)
22
+ end
23
+
24
+ def to_sql
25
+ definitions = @ctes.map { |name, query| "#{name} AS (#{query.to_sql})" }.join(", ")
26
+ prefix = @recursive ? "WITH RECURSIVE" : "WITH"
27
+ "#{prefix} #{definitions} #{@query.to_sql}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ # SQL Grammar definitions - used for validation and reference
6
+ module Grammar
7
+ # SQL statement types
8
+ STATEMENT_TYPES = {
9
+ select: "SELECT ... FROM ... [WHERE ...] [ORDER BY ...] [LIMIT ...] [OFFSET ...]",
10
+ insert: "INSERT INTO table [(columns)] VALUES (values)[, (values)...]",
11
+ update: "UPDATE table SET column = value [WHERE ...]",
12
+ delete: "DELETE FROM table [WHERE ...]",
13
+ create_table: "CREATE TABLE name (column_definitions [, constraints])",
14
+ create_index: "CREATE [UNIQUE] INDEX name ON table (columns)",
15
+ create_database: "CREATE DATABASE name",
16
+ drop_table: "DROP TABLE name",
17
+ drop_index: "DROP INDEX name",
18
+ drop_database: "DROP DATABASE name",
19
+ alter_table: "ALTER TABLE name ADD/DROP column/constraint",
20
+ begin: "BEGIN [TRANSACTION]",
21
+ commit: "COMMIT [TRANSACTION]",
22
+ rollback: "ROLLBACK [TRANSACTION] [TO SAVEPOINT name]",
23
+ savepoint: "SAVEPOINT name",
24
+ release_savepoint: "RELEASE [SAVEPOINT] name",
25
+ explain: "EXPLAIN [ANALYZE] statement",
26
+ vacuum: "VACUUM",
27
+ create_view: "CREATE VIEW name AS SELECT ...",
28
+ create_trigger: "CREATE TRIGGER name BEFORE|AFTER event ON table EXECUTE FUNCTION name()"
29
+ }.freeze
30
+
31
+ # Column data types
32
+ DATA_TYPES = {
33
+ integer: "INTEGER",
34
+ bigint: "BIGINT",
35
+ smallint: "SMALLINT",
36
+ float: "FLOAT",
37
+ decimal: "DECIMAL(precision, scale)",
38
+ numeric: "NUMERIC(precision, scale)",
39
+ boolean: "BOOLEAN",
40
+ text: "TEXT",
41
+ varchar: "VARCHAR(length)",
42
+ char: "CHAR(length)",
43
+ blob: "BLOB",
44
+ date: "DATE",
45
+ time: "TIME",
46
+ timestamp: "TIMESTAMP",
47
+ json: "JSON",
48
+ uuid: "UUID"
49
+ }.freeze
50
+
51
+ # Operators
52
+ OPERATORS = {
53
+ comparison: ["=", "!=", "<>", "<", "<=", ">", ">="],
54
+ logical: ["AND", "OR", "NOT"],
55
+ arithmetic: ["+", "-", "*", "/", "%"],
56
+ bitwise: ["&", "|", "^", "~"],
57
+ other: ["LIKE", "ILIKE", "BETWEEN", "IN", "IS", "IS NOT"]
58
+ }.freeze
59
+
60
+ # Constraint types
61
+ CONSTRAINT_TYPES = {
62
+ primary_key: "PRIMARY KEY (columns)",
63
+ foreign_key: "FOREIGN KEY (columns) REFERENCES table (columns)",
64
+ unique: "UNIQUE (columns)",
65
+ check: "CHECK (condition)",
66
+ not_null: "NOT NULL"
67
+ }.freeze
68
+
69
+ def self.validate_statement_type(type)
70
+ STATEMENT_TYPES.key?(type) ? true : false
71
+ end
72
+
73
+ def self.validate_data_type(type)
74
+ DATA_TYPES.key?(type) ? true : false
75
+ end
76
+
77
+ def self.validate_operator(op)
78
+ OPERATORS.values.flatten.include?(op.to_s.upcase)
79
+ end
80
+
81
+ def self.validate_constraint_type(type)
82
+ CONSTRAINT_TYPES.key?(type) ? true : false
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyDB
4
+ module SQL
5
+ # SQL keyword definitions
6
+ module Keywords
7
+ # Map of keyword strings to token types
8
+ KEYWORD_MAP = {
9
+ "SELECT" => Token::Type::SELECT,
10
+ "INSERT" => Token::Type::INSERT,
11
+ "UPDATE" => Token::Type::UPDATE,
12
+ "DELETE" => Token::Type::DELETE,
13
+ "CREATE" => Token::Type::CREATE,
14
+ "ALTER" => Token::Type::ALTER,
15
+ "DROP" => Token::Type::DROP,
16
+ "TABLE" => Token::Type::TABLE,
17
+ "INDEX" => Token::Type::INDEX,
18
+ "DATABASE" => Token::Type::DATABASE,
19
+ "SCHEMA" => Token::Type::SCHEMA,
20
+ "VIEW" => Token::Type::VIEW,
21
+ "TRIGGER" => Token::Type::TRIGGER,
22
+ "FROM" => Token::Type::FROM,
23
+ "WHERE" => Token::Type::WHERE,
24
+ "SET" => Token::Type::SET,
25
+ "VALUES" => Token::Type::VALUES,
26
+ "INTO" => Token::Type::INTO,
27
+ "CONFLICT" => Token::Type::CONFLICT,
28
+ "DO" => Token::Type::DO,
29
+ "NOTHING" => Token::Type::NOTHING,
30
+ "JOIN" => Token::Type::JOIN,
31
+ "INNER" => Token::Type::INNER,
32
+ "LEFT" => Token::Type::LEFT,
33
+ "RIGHT" => Token::Type::RIGHT,
34
+ "OUTER" => Token::Type::OUTER,
35
+ "FULL" => Token::Type::FULL,
36
+ "CROSS" => Token::Type::CROSS,
37
+ "ON" => Token::Type::ON,
38
+ "AS" => Token::Type::AS,
39
+ "DISTINCT" => Token::Type::DISTINCT,
40
+ "ORDER" => Token::Type::ORDER,
41
+ "BY" => Token::Type::BY,
42
+ "ASC" => Token::Type::ASC,
43
+ "DESC" => Token::Type::DESC,
44
+ "GROUP" => Token::Type::GROUP,
45
+ "HAVING" => Token::Type::HAVING,
46
+ "LIMIT" => Token::Type::LIMIT,
47
+ "OFFSET" => Token::Type::OFFSET,
48
+ "UNION" => Token::Type::UNION,
49
+ "INTERSECT" => Token::Type::INTERSECT,
50
+ "EXCEPT" => Token::Type::EXCEPT,
51
+ "ALL" => Token::Type::ALL,
52
+ "ANY" => Token::Type::ANY,
53
+ "SOME" => Token::Type::SOME,
54
+ "EXISTS" => Token::Type::EXISTS,
55
+ "IF" => Token::Type::IF,
56
+ "BETWEEN" => Token::Type::BETWEEN,
57
+ "LIKE" => Token::Type::LIKE,
58
+ "ILIKE" => Token::Type::ILIKE,
59
+ "IN" => Token::Type::IN,
60
+ "IS" => Token::Type::IS,
61
+ "NULL" => Token::Type::NULL,
62
+ "NOT" => Token::Type::NOT,
63
+ "AND" => Token::Type::AND,
64
+ "OR" => Token::Type::OR,
65
+ "TRUE" => Token::Type::TRUE,
66
+ "FALSE" => Token::Type::FALSE,
67
+ "PRIMARY" => Token::Type::PRIMARY,
68
+ "FOREIGN" => Token::Type::FOREIGN,
69
+ "KEY" => Token::Type::KEY,
70
+ "UNIQUE" => Token::Type::UNIQUE,
71
+ "CHECK" => Token::Type::CHECK,
72
+ "DEFAULT" => Token::Type::DEFAULT,
73
+ "REFERENCES" => Token::Type::REFERENCES,
74
+ "CONSTRAINT" => Token::Type::CONSTRAINT,
75
+ "CASCADE" => Token::Type::CASCADE,
76
+ "RESTRICT" => Token::Type::RESTRICT,
77
+ "BEFORE" => Token::Type::BEFORE,
78
+ "AFTER" => Token::Type::AFTER,
79
+ "EXECUTE" => Token::Type::EXECUTE,
80
+ "FUNCTION" => Token::Type::FUNCTION,
81
+ "ADD" => Token::Type::ADD,
82
+ "TO" => Token::Type::TO,
83
+ "BEGIN" => Token::Type::BEGIN_TRANSACTION,
84
+ "COMMIT" => Token::Type::COMMIT,
85
+ "ROLLBACK" => Token::Type::ROLLBACK,
86
+ "SAVEPOINT" => Token::Type::SAVEPOINT,
87
+ "RELEASE" => Token::Type::RELEASE,
88
+ "TRANSACTION" => Token::Type::TRANSACTION,
89
+ "EXPLAIN" => Token::Type::EXPLAIN,
90
+ "ANALYZE" => Token::Type::ANALYZE,
91
+ "VACUUM" => Token::Type::VACUUM,
92
+ "WITH" => Token::Type::WITH,
93
+ "RECURSIVE" => Token::Type::RECURSIVE,
94
+ "OVER" => Token::Type::OVER,
95
+ "PARTITION" => Token::Type::PARTITION,
96
+ "ROWS" => Token::Type::ROWS,
97
+ "UNBOUNDED" => Token::Type::UNBOUNDED,
98
+ "PRECEDING" => Token::Type::PRECEDING,
99
+ "FOLLOWING" => Token::Type::FOLLOWING,
100
+ "CURRENT" => Token::Type::CURRENT,
101
+ "INTEGER" => Token::Type::INTEGER,
102
+ "BIGINT" => Token::Type::BIGINT,
103
+ "SMALLINT" => Token::Type::SMALLINT,
104
+ "FLOAT" => Token::Type::FLOAT,
105
+ "DECIMAL" => Token::Type::DECIMAL,
106
+ "NUMERIC" => Token::Type::NUMERIC,
107
+ "BOOLEAN" => Token::Type::BOOLEAN,
108
+ "TEXT" => Token::Type::TEXT,
109
+ "VARCHAR" => Token::Type::VARCHAR,
110
+ "CHAR" => Token::Type::CHAR,
111
+ "BLOB" => Token::Type::BLOB,
112
+ "DATE" => Token::Type::DATE,
113
+ "TIME" => Token::Type::TIME,
114
+ "TIMESTAMP" => Token::Type::TIMESTAMP,
115
+ "JSON" => Token::Type::JSON,
116
+ "UUID" => Token::Type::UUID
117
+ }.freeze
118
+
119
+ # SQL keywords that are reserved
120
+ RESERVED_KEYWORDS = %w[
121
+ SELECT INSERT UPDATE DELETE CREATE ALTER DROP
122
+ TABLE INDEX DATABASE SCHEMA VIEW TRIGGER
123
+ FROM WHERE SET VALUES INTO JOIN ON AS
124
+ DISTINCT ORDER BY ASC DESC GROUP HAVING LIMIT OFFSET
125
+ UNION INTERSECT EXCEPT ALL ANY SOME EXISTS
126
+ BETWEEN LIKE ILIKE IN IS NULL NOT AND OR
127
+ TRUE FALSE PRIMARY FOREIGN KEY UNIQUE CHECK
128
+ DEFAULT REFERENCES CONSTRAINT CASCADE RESTRICT
129
+ BEGIN COMMIT ROLLBACK SAVEPOINT RELEASE TRANSACTION
130
+ ].freeze
131
+
132
+ # Data type keywords
133
+ TYPE_KEYWORDS = %w[
134
+ INTEGER BIGINT SMALLINT FLOAT DECIMAL NUMERIC
135
+ BOOLEAN TEXT VARCHAR CHAR BLOB DATE TIME TIMESTAMP
136
+ JSON UUID
137
+ ].freeze
138
+
139
+ def self.keyword?(word)
140
+ KEYWORD_MAP.key?(word.upcase)
141
+ end
142
+
143
+ def self.token_type(word)
144
+ KEYWORD_MAP[word.upcase]
145
+ end
146
+
147
+ def self.reserved?(word)
148
+ RESERVED_KEYWORDS.include?(word.upcase)
149
+ end
150
+
151
+ def self.type_keyword?(word)
152
+ TYPE_KEYWORDS.include?(word.upcase)
153
+ end
154
+ end
155
+ end
156
+ end