@neverinfamous/mysql-mcp 2.3.0 → 3.0.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 (347) hide show
  1. package/.dockerignore +1 -0
  2. package/.gitattributes +18 -0
  3. package/.github/workflows/codeql.yml +2 -10
  4. package/.github/workflows/docker-publish.yml +15 -13
  5. package/CHANGELOG.md +287 -1
  6. package/DOCKER_README.md +100 -265
  7. package/Dockerfile +5 -0
  8. package/README.md +124 -59
  9. package/VERSION +1 -1
  10. package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
  11. package/dist/__tests__/mocks/adapter.js +2 -0
  12. package/dist/__tests__/mocks/adapter.js.map +1 -1
  13. package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
  14. package/dist/adapters/DatabaseAdapter.js +50 -9
  15. package/dist/adapters/DatabaseAdapter.js.map +1 -1
  16. package/dist/adapters/mysql/MySQLAdapter.d.ts +6 -0
  17. package/dist/adapters/mysql/MySQLAdapter.d.ts.map +1 -1
  18. package/dist/adapters/mysql/MySQLAdapter.js +8 -0
  19. package/dist/adapters/mysql/MySQLAdapter.js.map +1 -1
  20. package/dist/adapters/mysql/SchemaManager.js +16 -15
  21. package/dist/adapters/mysql/SchemaManager.js.map +1 -1
  22. package/dist/adapters/mysql/prompts/index.js +10 -20
  23. package/dist/adapters/mysql/prompts/index.js.map +1 -1
  24. package/dist/adapters/mysql/prompts/proxysqlSetup.js +1 -1
  25. package/dist/adapters/mysql/resources/docstore.d.ts.map +1 -1
  26. package/dist/adapters/mysql/resources/docstore.js +10 -7
  27. package/dist/adapters/mysql/resources/docstore.js.map +1 -1
  28. package/dist/adapters/mysql/resources/events.js +11 -8
  29. package/dist/adapters/mysql/resources/events.js.map +1 -1
  30. package/dist/adapters/mysql/resources/indexes.d.ts.map +1 -1
  31. package/dist/adapters/mysql/resources/indexes.js +12 -15
  32. package/dist/adapters/mysql/resources/indexes.js.map +1 -1
  33. package/dist/adapters/mysql/resources/innodb.d.ts.map +1 -1
  34. package/dist/adapters/mysql/resources/innodb.js +20 -17
  35. package/dist/adapters/mysql/resources/innodb.js.map +1 -1
  36. package/dist/adapters/mysql/resources/locks.d.ts.map +1 -1
  37. package/dist/adapters/mysql/resources/locks.js +9 -6
  38. package/dist/adapters/mysql/resources/locks.js.map +1 -1
  39. package/dist/adapters/mysql/resources/performance.d.ts.map +1 -1
  40. package/dist/adapters/mysql/resources/performance.js +15 -15
  41. package/dist/adapters/mysql/resources/performance.js.map +1 -1
  42. package/dist/adapters/mysql/resources/spatial.d.ts.map +1 -1
  43. package/dist/adapters/mysql/resources/spatial.js +9 -6
  44. package/dist/adapters/mysql/resources/spatial.js.map +1 -1
  45. package/dist/adapters/mysql/resources/sysschema.d.ts.map +1 -1
  46. package/dist/adapters/mysql/resources/sysschema.js +12 -9
  47. package/dist/adapters/mysql/resources/sysschema.js.map +1 -1
  48. package/dist/adapters/mysql/tools/admin/backup.d.ts.map +1 -1
  49. package/dist/adapters/mysql/tools/admin/backup.js +170 -121
  50. package/dist/adapters/mysql/tools/admin/backup.js.map +1 -1
  51. package/dist/adapters/mysql/tools/admin/maintenance.d.ts.map +1 -1
  52. package/dist/adapters/mysql/tools/admin/maintenance.js +106 -57
  53. package/dist/adapters/mysql/tools/admin/maintenance.js.map +1 -1
  54. package/dist/adapters/mysql/tools/admin/monitoring.d.ts.map +1 -1
  55. package/dist/adapters/mysql/tools/admin/monitoring.js +183 -101
  56. package/dist/adapters/mysql/tools/admin/monitoring.js.map +1 -1
  57. package/dist/adapters/mysql/tools/cluster/group-replication.d.ts.map +1 -1
  58. package/dist/adapters/mysql/tools/cluster/group-replication.js +164 -120
  59. package/dist/adapters/mysql/tools/cluster/group-replication.js.map +1 -1
  60. package/dist/adapters/mysql/tools/cluster/innodb-cluster.d.ts.map +1 -1
  61. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js +212 -145
  62. package/dist/adapters/mysql/tools/cluster/innodb-cluster.js.map +1 -1
  63. package/dist/adapters/mysql/tools/codemode/index.d.ts.map +1 -1
  64. package/dist/adapters/mysql/tools/codemode/index.js +6 -4
  65. package/dist/adapters/mysql/tools/codemode/index.js.map +1 -1
  66. package/dist/adapters/mysql/tools/core.d.ts.map +1 -1
  67. package/dist/adapters/mysql/tools/core.js +152 -29
  68. package/dist/adapters/mysql/tools/core.js.map +1 -1
  69. package/dist/adapters/mysql/tools/docstore.d.ts.map +1 -1
  70. package/dist/adapters/mysql/tools/docstore.js +340 -163
  71. package/dist/adapters/mysql/tools/docstore.js.map +1 -1
  72. package/dist/adapters/mysql/tools/events.d.ts.map +1 -1
  73. package/dist/adapters/mysql/tools/events.js +284 -198
  74. package/dist/adapters/mysql/tools/events.js.map +1 -1
  75. package/dist/adapters/mysql/tools/json/core.d.ts.map +1 -1
  76. package/dist/adapters/mysql/tools/json/core.js +11 -39
  77. package/dist/adapters/mysql/tools/json/core.js.map +1 -1
  78. package/dist/adapters/mysql/tools/json/enhanced.d.ts.map +1 -1
  79. package/dist/adapters/mysql/tools/json/enhanced.js +15 -33
  80. package/dist/adapters/mysql/tools/json/enhanced.js.map +1 -1
  81. package/dist/adapters/mysql/tools/json/helpers.d.ts.map +1 -1
  82. package/dist/adapters/mysql/tools/json/helpers.js +13 -24
  83. package/dist/adapters/mysql/tools/json/helpers.js.map +1 -1
  84. package/dist/adapters/mysql/tools/partitioning.js +3 -0
  85. package/dist/adapters/mysql/tools/partitioning.js.map +1 -1
  86. package/dist/adapters/mysql/tools/performance/analysis.d.ts.map +1 -1
  87. package/dist/adapters/mysql/tools/performance/analysis.js +89 -60
  88. package/dist/adapters/mysql/tools/performance/analysis.js.map +1 -1
  89. package/dist/adapters/mysql/tools/performance/optimization.d.ts.map +1 -1
  90. package/dist/adapters/mysql/tools/performance/optimization.js +151 -127
  91. package/dist/adapters/mysql/tools/performance/optimization.js.map +1 -1
  92. package/dist/adapters/mysql/tools/proxysql.d.ts +1 -1
  93. package/dist/adapters/mysql/tools/proxysql.d.ts.map +1 -1
  94. package/dist/adapters/mysql/tools/proxysql.js +289 -176
  95. package/dist/adapters/mysql/tools/proxysql.js.map +1 -1
  96. package/dist/adapters/mysql/tools/replication.js +75 -49
  97. package/dist/adapters/mysql/tools/replication.js.map +1 -1
  98. package/dist/adapters/mysql/tools/roles.d.ts.map +1 -1
  99. package/dist/adapters/mysql/tools/roles.js +224 -182
  100. package/dist/adapters/mysql/tools/roles.js.map +1 -1
  101. package/dist/adapters/mysql/tools/router.d.ts.map +1 -1
  102. package/dist/adapters/mysql/tools/router.js +168 -67
  103. package/dist/adapters/mysql/tools/router.js.map +1 -1
  104. package/dist/adapters/mysql/tools/schema/constraints.d.ts.map +1 -1
  105. package/dist/adapters/mysql/tools/schema/constraints.js +21 -3
  106. package/dist/adapters/mysql/tools/schema/constraints.js.map +1 -1
  107. package/dist/adapters/mysql/tools/schema/management.d.ts.map +1 -1
  108. package/dist/adapters/mysql/tools/schema/management.js +61 -14
  109. package/dist/adapters/mysql/tools/schema/management.js.map +1 -1
  110. package/dist/adapters/mysql/tools/schema/routines.d.ts.map +1 -1
  111. package/dist/adapters/mysql/tools/schema/routines.js +27 -4
  112. package/dist/adapters/mysql/tools/schema/routines.js.map +1 -1
  113. package/dist/adapters/mysql/tools/schema/scheduled_events.d.ts.map +1 -1
  114. package/dist/adapters/mysql/tools/schema/scheduled_events.js +24 -3
  115. package/dist/adapters/mysql/tools/schema/scheduled_events.js.map +1 -1
  116. package/dist/adapters/mysql/tools/schema/triggers.d.ts.map +1 -1
  117. package/dist/adapters/mysql/tools/schema/triggers.js +23 -2
  118. package/dist/adapters/mysql/tools/schema/triggers.js.map +1 -1
  119. package/dist/adapters/mysql/tools/schema/views.d.ts.map +1 -1
  120. package/dist/adapters/mysql/tools/schema/views.js +47 -7
  121. package/dist/adapters/mysql/tools/schema/views.js.map +1 -1
  122. package/dist/adapters/mysql/tools/security/audit.d.ts.map +1 -1
  123. package/dist/adapters/mysql/tools/security/audit.js +102 -34
  124. package/dist/adapters/mysql/tools/security/audit.js.map +1 -1
  125. package/dist/adapters/mysql/tools/security/data-protection.d.ts.map +1 -1
  126. package/dist/adapters/mysql/tools/security/data-protection.js +264 -205
  127. package/dist/adapters/mysql/tools/security/data-protection.js.map +1 -1
  128. package/dist/adapters/mysql/tools/security/encryption.d.ts.map +1 -1
  129. package/dist/adapters/mysql/tools/security/encryption.js +137 -104
  130. package/dist/adapters/mysql/tools/security/encryption.js.map +1 -1
  131. package/dist/adapters/mysql/tools/shell/backup.d.ts.map +1 -1
  132. package/dist/adapters/mysql/tools/shell/backup.js +71 -59
  133. package/dist/adapters/mysql/tools/shell/backup.js.map +1 -1
  134. package/dist/adapters/mysql/tools/shell/restore.d.ts.map +1 -1
  135. package/dist/adapters/mysql/tools/shell/restore.js +61 -47
  136. package/dist/adapters/mysql/tools/shell/restore.js.map +1 -1
  137. package/dist/adapters/mysql/tools/spatial/geometry.d.ts.map +1 -1
  138. package/dist/adapters/mysql/tools/spatial/geometry.js +19 -5
  139. package/dist/adapters/mysql/tools/spatial/geometry.js.map +1 -1
  140. package/dist/adapters/mysql/tools/spatial/operations.d.ts.map +1 -1
  141. package/dist/adapters/mysql/tools/spatial/operations.js +42 -17
  142. package/dist/adapters/mysql/tools/spatial/operations.js.map +1 -1
  143. package/dist/adapters/mysql/tools/spatial/queries.d.ts.map +1 -1
  144. package/dist/adapters/mysql/tools/spatial/queries.js +109 -57
  145. package/dist/adapters/mysql/tools/spatial/queries.js.map +1 -1
  146. package/dist/adapters/mysql/tools/spatial/setup.d.ts.map +1 -1
  147. package/dist/adapters/mysql/tools/spatial/setup.js +103 -50
  148. package/dist/adapters/mysql/tools/spatial/setup.js.map +1 -1
  149. package/dist/adapters/mysql/tools/stats/comparative.d.ts.map +1 -1
  150. package/dist/adapters/mysql/tools/stats/comparative.js +128 -79
  151. package/dist/adapters/mysql/tools/stats/comparative.js.map +1 -1
  152. package/dist/adapters/mysql/tools/stats/descriptive.d.ts.map +1 -1
  153. package/dist/adapters/mysql/tools/stats/descriptive.js +174 -102
  154. package/dist/adapters/mysql/tools/stats/descriptive.js.map +1 -1
  155. package/dist/adapters/mysql/tools/sysschema/activity.d.ts.map +1 -1
  156. package/dist/adapters/mysql/tools/sysschema/activity.js +50 -25
  157. package/dist/adapters/mysql/tools/sysschema/activity.js.map +1 -1
  158. package/dist/adapters/mysql/tools/sysschema/performance.d.ts.map +1 -1
  159. package/dist/adapters/mysql/tools/sysschema/performance.js +121 -66
  160. package/dist/adapters/mysql/tools/sysschema/performance.js.map +1 -1
  161. package/dist/adapters/mysql/tools/sysschema/resources.d.ts.map +1 -1
  162. package/dist/adapters/mysql/tools/sysschema/resources.js +101 -64
  163. package/dist/adapters/mysql/tools/sysschema/resources.js.map +1 -1
  164. package/dist/adapters/mysql/tools/text/fulltext.d.ts.map +1 -1
  165. package/dist/adapters/mysql/tools/text/fulltext.js +18 -32
  166. package/dist/adapters/mysql/tools/text/fulltext.js.map +1 -1
  167. package/dist/adapters/mysql/tools/transactions.d.ts.map +1 -1
  168. package/dist/adapters/mysql/tools/transactions.js +48 -23
  169. package/dist/adapters/mysql/tools/transactions.js.map +1 -1
  170. package/dist/adapters/mysql/types/proxysql-types.d.ts +15 -0
  171. package/dist/adapters/mysql/types/proxysql-types.d.ts.map +1 -1
  172. package/dist/adapters/mysql/types/proxysql-types.js +33 -1
  173. package/dist/adapters/mysql/types/proxysql-types.js.map +1 -1
  174. package/dist/adapters/mysql/types/router-types.d.ts +1 -1
  175. package/dist/adapters/mysql/types/router-types.js +1 -1
  176. package/dist/adapters/mysql/types/router-types.js.map +1 -1
  177. package/dist/adapters/mysql/types/shell-types.js +2 -2
  178. package/dist/adapters/mysql/types/shell-types.js.map +1 -1
  179. package/dist/adapters/mysql/types.d.ts +485 -21
  180. package/dist/adapters/mysql/types.d.ts.map +1 -1
  181. package/dist/adapters/mysql/types.js +546 -19
  182. package/dist/adapters/mysql/types.js.map +1 -1
  183. package/dist/auth/scopes.js +1 -1
  184. package/dist/auth/scopes.js.map +1 -1
  185. package/dist/codemode/api.d.ts +3 -2
  186. package/dist/codemode/api.d.ts.map +1 -1
  187. package/dist/codemode/api.js +80 -5
  188. package/dist/codemode/api.js.map +1 -1
  189. package/dist/codemode/sandbox-factory.js +1 -1
  190. package/dist/codemode/sandbox-factory.js.map +1 -1
  191. package/dist/codemode/types.d.ts +26 -0
  192. package/dist/codemode/types.d.ts.map +1 -1
  193. package/dist/codemode/types.js +2 -0
  194. package/dist/codemode/types.js.map +1 -1
  195. package/dist/codemode/worker-sandbox.d.ts +4 -2
  196. package/dist/codemode/worker-sandbox.d.ts.map +1 -1
  197. package/dist/codemode/worker-sandbox.js +66 -7
  198. package/dist/codemode/worker-sandbox.js.map +1 -1
  199. package/dist/codemode/worker-script.d.ts +3 -0
  200. package/dist/codemode/worker-script.d.ts.map +1 -1
  201. package/dist/codemode/worker-script.js +128 -75
  202. package/dist/codemode/worker-script.js.map +1 -1
  203. package/dist/constants/ServerInstructions.d.ts +1 -1
  204. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  205. package/dist/constants/ServerInstructions.js +37 -31
  206. package/dist/constants/ServerInstructions.js.map +1 -1
  207. package/dist/filtering/ToolConstants.d.ts +1 -1
  208. package/dist/filtering/ToolConstants.d.ts.map +1 -1
  209. package/dist/filtering/ToolConstants.js +1 -2
  210. package/dist/filtering/ToolConstants.js.map +1 -1
  211. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  212. package/dist/pool/ConnectionPool.js.map +1 -1
  213. package/dist/transports/http.d.ts.map +1 -1
  214. package/dist/transports/http.js +6 -0
  215. package/dist/transports/http.js.map +1 -1
  216. package/dist/utils/validators.d.ts +1 -1
  217. package/dist/utils/validators.d.ts.map +1 -1
  218. package/dist/utils/validators.js.map +1 -1
  219. package/package.json +4 -4
  220. package/releases/v2.3.0-release-notes.md +20 -20
  221. package/releases/v2.3.1-release-notes.md +34 -0
  222. package/releases/v3.0.0-release-notes.md +81 -0
  223. package/src/__tests__/mocks/adapter.ts +3 -0
  224. package/src/__tests__/perf.test.ts +6 -6
  225. package/src/adapters/DatabaseAdapter.ts +58 -9
  226. package/src/adapters/__tests__/DatabaseAdapter.test.ts +89 -8
  227. package/src/adapters/mysql/MySQLAdapter.ts +17 -2
  228. package/src/adapters/mysql/SchemaManager.ts +21 -21
  229. package/src/adapters/mysql/__tests__/MySQLAdapter.test.ts +1 -1
  230. package/src/adapters/mysql/prompts/index.ts +12 -22
  231. package/src/adapters/mysql/prompts/proxysqlSetup.ts +1 -1
  232. package/src/adapters/mysql/resources/docstore.ts +13 -10
  233. package/src/adapters/mysql/resources/events.ts +12 -12
  234. package/src/adapters/mysql/resources/indexes.ts +17 -19
  235. package/src/adapters/mysql/resources/innodb.ts +23 -22
  236. package/src/adapters/mysql/resources/locks.ts +9 -7
  237. package/src/adapters/mysql/resources/performance.ts +23 -18
  238. package/src/adapters/mysql/resources/spatial.ts +9 -7
  239. package/src/adapters/mysql/resources/sysschema.ts +12 -11
  240. package/src/adapters/mysql/tools/__tests__/core.test.ts +126 -55
  241. package/src/adapters/mysql/tools/__tests__/docstore.test.ts +459 -88
  242. package/src/adapters/mysql/tools/__tests__/events.test.ts +281 -103
  243. package/src/adapters/mysql/tools/__tests__/proxysql.test.ts +128 -28
  244. package/src/adapters/mysql/tools/__tests__/replication.test.ts +48 -2
  245. package/src/adapters/mysql/tools/__tests__/roles.test.ts +15 -18
  246. package/src/adapters/mysql/tools/__tests__/router.test.ts +32 -5
  247. package/src/adapters/mysql/tools/__tests__/security.test.ts +126 -2
  248. package/src/adapters/mysql/tools/__tests__/security_injection.test.ts +84 -76
  249. package/src/adapters/mysql/tools/__tests__/security_integration.test.ts +47 -50
  250. package/src/adapters/mysql/tools/__tests__/spatial.test.ts +11 -10
  251. package/src/adapters/mysql/tools/__tests__/spatial_handler.test.ts +54 -38
  252. package/src/adapters/mysql/tools/__tests__/stats.test.ts +285 -152
  253. package/src/adapters/mysql/tools/__tests__/transactions.test.ts +13 -13
  254. package/src/adapters/mysql/tools/admin/__tests__/backup.test.ts +171 -25
  255. package/src/adapters/mysql/tools/admin/__tests__/maintenance.test.ts +240 -4
  256. package/src/adapters/mysql/tools/admin/__tests__/monitoring-summary.test.ts +274 -0
  257. package/src/adapters/mysql/tools/admin/__tests__/monitoring.test.ts +94 -5
  258. package/src/adapters/mysql/tools/admin/backup.ts +193 -143
  259. package/src/adapters/mysql/tools/admin/maintenance.ts +118 -69
  260. package/src/adapters/mysql/tools/admin/monitoring.ts +201 -125
  261. package/src/adapters/mysql/tools/cluster/__tests__/group-replication.test.ts +69 -0
  262. package/src/adapters/mysql/tools/cluster/__tests__/innodb-cluster.test.ts +141 -0
  263. package/src/adapters/mysql/tools/cluster/group-replication.ts +172 -132
  264. package/src/adapters/mysql/tools/cluster/innodb-cluster.ts +231 -157
  265. package/src/adapters/mysql/tools/codemode/__tests__/codemode-tool.test.ts +227 -0
  266. package/src/adapters/mysql/tools/codemode/index.ts +5 -3
  267. package/src/adapters/mysql/tools/core.ts +152 -38
  268. package/src/adapters/mysql/tools/docstore.ts +422 -205
  269. package/src/adapters/mysql/tools/events.ts +334 -233
  270. package/src/adapters/mysql/tools/json/__tests__/core.test.ts +20 -0
  271. package/src/adapters/mysql/tools/json/__tests__/enhanced.test.ts +82 -50
  272. package/src/adapters/mysql/tools/json/__tests__/helpers.test.ts +42 -3
  273. package/src/adapters/mysql/tools/json/core.ts +21 -42
  274. package/src/adapters/mysql/tools/json/enhanced.ts +22 -37
  275. package/src/adapters/mysql/tools/json/helpers.ts +21 -25
  276. package/src/adapters/mysql/tools/partitioning.ts +3 -0
  277. package/src/adapters/mysql/tools/performance/__tests__/analysis.test.ts +98 -5
  278. package/src/adapters/mysql/tools/performance/__tests__/optimization-coverage.test.ts +515 -0
  279. package/src/adapters/mysql/tools/performance/__tests__/optimization.test.ts +187 -0
  280. package/src/adapters/mysql/tools/performance/analysis.ts +95 -69
  281. package/src/adapters/mysql/tools/performance/optimization.ts +182 -153
  282. package/src/adapters/mysql/tools/proxysql.ts +314 -209
  283. package/src/adapters/mysql/tools/replication.ts +84 -57
  284. package/src/adapters/mysql/tools/roles.ts +274 -226
  285. package/src/adapters/mysql/tools/router.ts +181 -85
  286. package/src/adapters/mysql/tools/schema/__tests__/constraints.test.ts +13 -0
  287. package/src/adapters/mysql/tools/schema/__tests__/management.test.ts +60 -25
  288. package/src/adapters/mysql/tools/schema/__tests__/scheduled_events.test.ts +11 -0
  289. package/src/adapters/mysql/tools/schema/__tests__/triggers.test.ts +25 -4
  290. package/src/adapters/mysql/tools/schema/__tests__/views.test.ts +46 -14
  291. package/src/adapters/mysql/tools/schema/constraints.ts +22 -3
  292. package/src/adapters/mysql/tools/schema/management.ts +60 -15
  293. package/src/adapters/mysql/tools/schema/routines.ts +26 -4
  294. package/src/adapters/mysql/tools/schema/scheduled_events.ts +25 -3
  295. package/src/adapters/mysql/tools/schema/triggers.ts +27 -2
  296. package/src/adapters/mysql/tools/schema/views.ts +46 -8
  297. package/src/adapters/mysql/tools/security/__tests__/audit.test.ts +90 -4
  298. package/src/adapters/mysql/tools/security/audit.ts +113 -39
  299. package/src/adapters/mysql/tools/security/data-protection.ts +293 -233
  300. package/src/adapters/mysql/tools/security/encryption.ts +172 -139
  301. package/src/adapters/mysql/tools/shell/__tests__/backup.test.ts +29 -0
  302. package/src/adapters/mysql/tools/shell/backup.ts +90 -73
  303. package/src/adapters/mysql/tools/shell/restore.ts +62 -48
  304. package/src/adapters/mysql/tools/spatial/__tests__/operations.test.ts +22 -14
  305. package/src/adapters/mysql/tools/spatial/__tests__/queries.test.ts +65 -51
  306. package/src/adapters/mysql/tools/spatial/geometry.ts +23 -7
  307. package/src/adapters/mysql/tools/spatial/operations.ts +60 -31
  308. package/src/adapters/mysql/tools/spatial/queries.ts +142 -65
  309. package/src/adapters/mysql/tools/spatial/setup.ts +121 -55
  310. package/src/adapters/mysql/tools/stats/__tests__/comparative.test.ts +12 -10
  311. package/src/adapters/mysql/tools/stats/comparative.ts +150 -98
  312. package/src/adapters/mysql/tools/stats/descriptive.ts +204 -127
  313. package/src/adapters/mysql/tools/sysschema/__tests__/error-paths.test.ts +222 -0
  314. package/src/adapters/mysql/tools/sysschema/__tests__/performance.test.ts +45 -0
  315. package/src/adapters/mysql/tools/sysschema/__tests__/resources.test.ts +6 -3
  316. package/src/adapters/mysql/tools/sysschema/activity.ts +52 -27
  317. package/src/adapters/mysql/tools/sysschema/performance.ts +132 -68
  318. package/src/adapters/mysql/tools/sysschema/resources.ts +105 -67
  319. package/src/adapters/mysql/tools/text/__tests__/fulltext.test.ts +45 -17
  320. package/src/adapters/mysql/tools/text/fulltext.ts +27 -38
  321. package/src/adapters/mysql/tools/transactions.ts +49 -24
  322. package/src/adapters/mysql/types/proxysql-types.ts +38 -1
  323. package/src/adapters/mysql/types/router-types.ts +1 -1
  324. package/src/adapters/mysql/types/shell-types.ts +2 -2
  325. package/src/adapters/mysql/types.ts +632 -19
  326. package/src/auth/__tests__/scopes.test.ts +2 -2
  327. package/src/auth/scopes.ts +1 -1
  328. package/src/codemode/__tests__/api.test.ts +417 -0
  329. package/src/codemode/__tests__/sandbox-factory.test.ts +158 -0
  330. package/src/codemode/__tests__/sandbox.test.ts +301 -0
  331. package/src/codemode/__tests__/security.test.ts +368 -0
  332. package/src/codemode/__tests__/worker-sandbox.test.ts +179 -0
  333. package/src/codemode/__tests__/worker-script.test.ts +226 -0
  334. package/src/codemode/api.ts +89 -5
  335. package/src/codemode/sandbox-factory.ts +1 -1
  336. package/src/codemode/types.ts +34 -0
  337. package/src/codemode/worker-sandbox.ts +74 -7
  338. package/src/codemode/worker-script.ts +157 -86
  339. package/src/constants/ServerInstructions.ts +37 -31
  340. package/src/filtering/ToolConstants.ts +1 -2
  341. package/src/filtering/__tests__/ToolFilter.test.ts +9 -9
  342. package/src/pool/ConnectionPool.ts +4 -1
  343. package/src/transports/__tests__/http.test.ts +15 -3
  344. package/src/transports/http.ts +12 -0
  345. package/src/utils/validators.ts +2 -1
  346. package/vitest.config.ts +3 -1
  347. package/CODE_MODE.md +0 -245
@@ -5,12 +5,45 @@
5
5
  * 4 tools: distance, distance_sphere, contains, within.
6
6
  */
7
7
 
8
- import { z } from "zod";
8
+ import { z, ZodError } from "zod";
9
9
  import type { MySQLAdapter } from "../../MySQLAdapter.js";
10
10
  import type {
11
11
  ToolDefinition,
12
12
  RequestContext,
13
13
  } from "../../../../types/index.js";
14
+ import {
15
+ validateQualifiedIdentifier,
16
+ escapeQualifiedTable,
17
+ } from "../../../../utils/validators.js";
18
+ import { ValidationError } from "../../../../utils/validators.js";
19
+
20
+ // =============================================================================
21
+ // Helpers
22
+ // =============================================================================
23
+
24
+ /** Extract human-readable messages from a ZodError instead of raw JSON array */
25
+ function formatZodError(error: ZodError): string {
26
+ return error.issues.map((i) => i.message).join("; ");
27
+ }
28
+
29
+ /** Strip verbose adapter prefixes from MySQL error messages */
30
+ function stripErrorPrefix(msg: string): string {
31
+ return msg.replace(/^(Query failed:\s*)?(Execute failed:\s*)?/i, "");
32
+ }
33
+
34
+ /** Safely extract a string field from raw params for error context */
35
+ function paramStr(params: unknown, key: string): string {
36
+ if (
37
+ params !== null &&
38
+ params !== undefined &&
39
+ typeof params === "object" &&
40
+ key in params
41
+ ) {
42
+ const val = (params as Record<string, unknown>)[key];
43
+ return typeof val === "string" ? val : "";
44
+ }
45
+ return "";
46
+ }
14
47
 
15
48
  // =============================================================================
16
49
  // Zod Schemas
@@ -71,25 +104,24 @@ export function createSpatialDistanceTool(
71
104
  idempotentHint: true,
72
105
  },
73
106
  handler: async (params: unknown, _context: RequestContext) => {
74
- const { table, spatialColumn, point, maxDistance, limit, srid } =
75
- DistanceSchema.parse(params);
107
+ try {
108
+ const { table, spatialColumn, point, maxDistance, limit, srid } =
109
+ DistanceSchema.parse(params);
76
110
 
77
- // Validate identifiers
78
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
79
- throw new Error("Invalid table name");
80
- }
81
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
82
- throw new Error("Invalid column name");
83
- }
111
+ // Validate identifiers
112
+ validateQualifiedIdentifier(table, "table");
113
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
114
+ return { success: false, error: "Invalid column name" };
115
+ }
84
116
 
85
- try {
86
117
  // Use 'axis-order=long-lat' to accept natural longitude-latitude order
87
118
  const pointWkt = `POINT(${String(point.longitude)} ${String(point.latitude)})`;
119
+ const escapedTable = escapeQualifiedTable(table);
88
120
 
89
121
  let query = `
90
- SELECT *,
122
+ SELECT *, ST_AsText(\`${spatialColumn}\`) as ${spatialColumn}_wkt,
91
123
  ST_Distance(\`${spatialColumn}\`, ST_GeomFromText(?, ${String(srid)}, 'axis-order=long-lat')) as distance
92
- FROM \`${table}\`
124
+ FROM ${escapedTable}
93
125
  `;
94
126
 
95
127
  const queryParams: unknown[] = [pointWkt];
@@ -102,17 +134,29 @@ export function createSpatialDistanceTool(
102
134
  query += ` ORDER BY distance LIMIT ${String(limit)}`;
103
135
 
104
136
  const result = await adapter.executeQuery(query, queryParams);
137
+ // Strip raw binary spatial column from each row
138
+ const rows = (result.rows ?? []).map((row: Record<string, unknown>) =>
139
+ Object.fromEntries(
140
+ Object.entries(row).filter(([key]) => key !== spatialColumn),
141
+ ),
142
+ );
105
143
  return {
106
- results: result.rows ?? [],
107
- count: result.rows?.length ?? 0,
144
+ results: rows,
145
+ count: rows.length,
108
146
  referencePoint: point,
109
147
  };
110
148
  } catch (error) {
149
+ if (error instanceof ZodError) {
150
+ return { success: false, error: formatZodError(error) };
151
+ }
152
+ if (error instanceof ValidationError) {
153
+ return { success: false, error: error.message };
154
+ }
111
155
  const msg = error instanceof Error ? error.message : String(error);
112
156
  if (msg.includes("doesn't exist")) {
113
- return { exists: false, table };
157
+ return { exists: false, table: paramStr(params, "table") };
114
158
  }
115
- return { success: false, error: msg };
159
+ return { success: false, error: stripErrorPrefix(msg) };
116
160
  }
117
161
  },
118
162
  };
@@ -137,25 +181,24 @@ export function createSpatialDistanceSphereTool(
137
181
  idempotentHint: true,
138
182
  },
139
183
  handler: async (params: unknown, _context: RequestContext) => {
140
- const { table, spatialColumn, point, maxDistance, limit, srid } =
141
- DistanceSchema.parse(params);
184
+ try {
185
+ const { table, spatialColumn, point, maxDistance, limit, srid } =
186
+ DistanceSchema.parse(params);
142
187
 
143
- // Validate identifiers
144
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
145
- throw new Error("Invalid table name");
146
- }
147
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
148
- throw new Error("Invalid column name");
149
- }
188
+ // Validate identifiers
189
+ validateQualifiedIdentifier(table, "table");
190
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
191
+ return { success: false, error: "Invalid column name" };
192
+ }
150
193
 
151
- try {
152
194
  // Use 'axis-order=long-lat' to accept natural longitude-latitude order
153
195
  const pointWkt = `POINT(${String(point.longitude)} ${String(point.latitude)})`;
196
+ const escapedTable = escapeQualifiedTable(table);
154
197
 
155
198
  let query = `
156
- SELECT *,
199
+ SELECT *, ST_AsText(\`${spatialColumn}\`) as ${spatialColumn}_wkt,
157
200
  ST_Distance_Sphere(\`${spatialColumn}\`, ST_GeomFromText(?, ${String(srid)}, 'axis-order=long-lat')) as distance_meters
158
- FROM \`${table}\`
201
+ FROM ${escapedTable}
159
202
  `;
160
203
 
161
204
  const queryParams: unknown[] = [pointWkt];
@@ -168,18 +211,30 @@ export function createSpatialDistanceSphereTool(
168
211
  query += ` ORDER BY distance_meters LIMIT ${String(limit)}`;
169
212
 
170
213
  const result = await adapter.executeQuery(query, queryParams);
214
+ // Strip raw binary spatial column from each row
215
+ const rows = (result.rows ?? []).map((row: Record<string, unknown>) =>
216
+ Object.fromEntries(
217
+ Object.entries(row).filter(([key]) => key !== spatialColumn),
218
+ ),
219
+ );
171
220
  return {
172
- results: result.rows ?? [],
173
- count: result.rows?.length ?? 0,
221
+ results: rows,
222
+ count: rows.length,
174
223
  referencePoint: point,
175
224
  unit: "meters",
176
225
  };
177
226
  } catch (error) {
227
+ if (error instanceof ZodError) {
228
+ return { success: false, error: formatZodError(error) };
229
+ }
230
+ if (error instanceof ValidationError) {
231
+ return { success: false, error: error.message };
232
+ }
178
233
  const msg = error instanceof Error ? error.message : String(error);
179
234
  if (msg.includes("doesn't exist")) {
180
- return { exists: false, table };
235
+ return { exists: false, table: paramStr(params, "table") };
181
236
  }
182
- return { success: false, error: msg };
237
+ return { success: false, error: stripErrorPrefix(msg) };
183
238
  }
184
239
  },
185
240
  };
@@ -204,36 +259,47 @@ export function createSpatialContainsTool(
204
259
  idempotentHint: true,
205
260
  },
206
261
  handler: async (params: unknown, _context: RequestContext) => {
207
- const { table, spatialColumn, polygon, limit, srid } =
208
- ContainsSchema.parse(params);
262
+ try {
263
+ const { table, spatialColumn, polygon, limit, srid } =
264
+ ContainsSchema.parse(params);
209
265
 
210
- // Validate identifiers
211
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
212
- throw new Error("Invalid table name");
213
- }
214
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
215
- throw new Error("Invalid column name");
216
- }
266
+ // Validate identifiers
267
+ validateQualifiedIdentifier(table, "table");
268
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
269
+ return { success: false, error: "Invalid column name" };
270
+ }
217
271
 
218
- try {
272
+ const escapedTable = escapeQualifiedTable(table);
219
273
  const query = `
220
- SELECT *
221
- FROM \`${table}\`
274
+ SELECT *, ST_AsText(\`${spatialColumn}\`) as ${spatialColumn}_wkt
275
+ FROM ${escapedTable}
222
276
  WHERE ST_Contains(ST_GeomFromText(?, ${String(srid)}, 'axis-order=long-lat'), \`${spatialColumn}\`)
223
277
  LIMIT ${String(limit)}
224
278
  `;
225
279
 
226
280
  const result = await adapter.executeQuery(query, [polygon]);
281
+ // Strip raw binary spatial column from each row
282
+ const rows = (result.rows ?? []).map((row: Record<string, unknown>) =>
283
+ Object.fromEntries(
284
+ Object.entries(row).filter(([key]) => key !== spatialColumn),
285
+ ),
286
+ );
227
287
  return {
228
- results: result.rows ?? [],
229
- count: result.rows?.length ?? 0,
288
+ results: rows,
289
+ count: rows.length,
230
290
  };
231
291
  } catch (error) {
292
+ if (error instanceof ZodError) {
293
+ return { success: false, error: formatZodError(error) };
294
+ }
295
+ if (error instanceof ValidationError) {
296
+ return { success: false, error: error.message };
297
+ }
232
298
  const msg = error instanceof Error ? error.message : String(error);
233
299
  if (msg.includes("doesn't exist")) {
234
- return { exists: false, table };
300
+ return { exists: false, table: paramStr(params, "table") };
235
301
  }
236
- return { success: false, error: msg };
302
+ return { success: false, error: stripErrorPrefix(msg) };
237
303
  }
238
304
  },
239
305
  };
@@ -255,36 +321,47 @@ export function createSpatialWithinTool(adapter: MySQLAdapter): ToolDefinition {
255
321
  idempotentHint: true,
256
322
  },
257
323
  handler: async (params: unknown, _context: RequestContext) => {
258
- const { table, spatialColumn, geometry, limit, srid } =
259
- WithinSchema.parse(params);
324
+ try {
325
+ const { table, spatialColumn, geometry, limit, srid } =
326
+ WithinSchema.parse(params);
260
327
 
261
- // Validate identifiers
262
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
263
- throw new Error("Invalid table name");
264
- }
265
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
266
- throw new Error("Invalid column name");
267
- }
328
+ // Validate identifiers
329
+ validateQualifiedIdentifier(table, "table");
330
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(spatialColumn)) {
331
+ return { success: false, error: "Invalid column name" };
332
+ }
268
333
 
269
- try {
334
+ const escapedTable = escapeQualifiedTable(table);
270
335
  const query = `
271
- SELECT *
272
- FROM \`${table}\`
336
+ SELECT *, ST_AsText(\`${spatialColumn}\`) as ${spatialColumn}_wkt
337
+ FROM ${escapedTable}
273
338
  WHERE ST_Within(\`${spatialColumn}\`, ST_GeomFromText(?, ${String(srid)}, 'axis-order=long-lat'))
274
339
  LIMIT ${String(limit)}
275
340
  `;
276
341
 
277
342
  const result = await adapter.executeQuery(query, [geometry]);
343
+ // Strip raw binary spatial column from each row
344
+ const rows = (result.rows ?? []).map((row: Record<string, unknown>) =>
345
+ Object.fromEntries(
346
+ Object.entries(row).filter(([key]) => key !== spatialColumn),
347
+ ),
348
+ );
278
349
  return {
279
- results: result.rows ?? [],
280
- count: result.rows?.length ?? 0,
350
+ results: rows,
351
+ count: rows.length,
281
352
  };
282
353
  } catch (error) {
354
+ if (error instanceof ZodError) {
355
+ return { success: false, error: formatZodError(error) };
356
+ }
357
+ if (error instanceof ValidationError) {
358
+ return { success: false, error: error.message };
359
+ }
283
360
  const msg = error instanceof Error ? error.message : String(error);
284
361
  if (msg.includes("doesn't exist")) {
285
- return { exists: false, table };
362
+ return { exists: false, table: paramStr(params, "table") };
286
363
  }
287
- return { success: false, error: msg };
364
+ return { success: false, error: stripErrorPrefix(msg) };
288
365
  }
289
366
  },
290
367
  };
@@ -5,33 +5,65 @@
5
5
  * 2 tools: column creation and index creation.
6
6
  */
7
7
 
8
- import { z } from "zod";
8
+ import { z, ZodError } from "zod";
9
9
  import type { MySQLAdapter } from "../../MySQLAdapter.js";
10
10
  import type {
11
11
  ToolDefinition,
12
12
  RequestContext,
13
13
  } from "../../../../types/index.js";
14
+ import {
15
+ validateQualifiedIdentifier,
16
+ escapeQualifiedTable,
17
+ } from "../../../../utils/validators.js";
18
+ import { ValidationError } from "../../../../utils/validators.js";
19
+
20
+ // =============================================================================
21
+ // Helpers
22
+ // =============================================================================
23
+
24
+ /** Extract human-readable messages from a ZodError instead of raw JSON array */
25
+ function formatZodError(error: ZodError): string {
26
+ return error.issues.map((i) => i.message).join("; ");
27
+ }
28
+
29
+ /** Strip verbose adapter prefixes from MySQL error messages */
30
+ function stripErrorPrefix(msg: string): string {
31
+ return msg.replace(/^(Query failed:\s*)?(Execute failed:\s*)?/i, "");
32
+ }
33
+
34
+ /** Safely extract a string field from raw params for error context */
35
+ function paramStr(params: unknown, key: string): string {
36
+ if (
37
+ params !== null &&
38
+ params !== undefined &&
39
+ typeof params === "object" &&
40
+ key in params
41
+ ) {
42
+ const val = (params as Record<string, unknown>)[key];
43
+ return typeof val === "string" ? val : "";
44
+ }
45
+ return "";
46
+ }
14
47
 
15
48
  // =============================================================================
16
49
  // Zod Schemas
17
50
  // =============================================================================
18
51
 
52
+ const VALID_GEOMETRY_TYPES = new Set([
53
+ "POINT",
54
+ "LINESTRING",
55
+ "POLYGON",
56
+ "GEOMETRY",
57
+ "MULTIPOINT",
58
+ "MULTILINESTRING",
59
+ "MULTIPOLYGON",
60
+ "GEOMETRYCOLLECTION",
61
+ ]);
62
+
19
63
  const SpatialColumnSchema = z.object({
20
64
  table: z.string().describe("Table name"),
21
65
  column: z.string().describe("Column name"),
22
- type: z
23
- .enum([
24
- "POINT",
25
- "LINESTRING",
26
- "POLYGON",
27
- "GEOMETRY",
28
- "MULTIPOINT",
29
- "MULTILINESTRING",
30
- "MULTIPOLYGON",
31
- "GEOMETRYCOLLECTION",
32
- ])
33
- .default("GEOMETRY")
34
- .describe("Geometry type"),
66
+ type: z.string().default("GEOMETRY").describe("Geometry type"),
35
67
  srid: z
36
68
  .number()
37
69
  .default(4326)
@@ -65,25 +97,33 @@ export function createSpatialCreateColumnTool(
65
97
  readOnlyHint: false,
66
98
  },
67
99
  handler: async (params: unknown, _context: RequestContext) => {
68
- const { table, column, type, srid, nullable } =
69
- SpatialColumnSchema.parse(params);
100
+ try {
101
+ const { table, column, type, srid, nullable } =
102
+ SpatialColumnSchema.parse(params);
70
103
 
71
- // Validate identifiers
72
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
73
- throw new Error("Invalid table name");
74
- }
75
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(column)) {
76
- throw new Error("Invalid column name");
77
- }
104
+ // Validate identifiers
105
+ validateQualifiedIdentifier(table, "table");
106
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(column)) {
107
+ return { success: false, error: "Invalid column name" };
108
+ }
109
+
110
+ // Validate geometry type
111
+ const upperType = type.toUpperCase();
112
+ if (!VALID_GEOMETRY_TYPES.has(upperType)) {
113
+ return {
114
+ success: false,
115
+ error: `Invalid type: '${type}' — expected one of: ${[...VALID_GEOMETRY_TYPES].join(", ")}`,
116
+ };
117
+ }
78
118
 
79
- try {
80
119
  const nullClause = nullable ? "" : " NOT NULL";
81
120
  const sridClause = srid ? ` SRID ${String(srid)}` : "";
82
121
 
83
122
  await adapter.executeQuery(
84
- `ALTER TABLE \`${table}\` ADD COLUMN \`${column}\` ${type}${sridClause}${nullClause}`,
123
+ `ALTER TABLE ${escapeQualifiedTable(table)} ADD COLUMN \`${column}\` ${upperType}${sridClause}${nullClause}`,
85
124
  );
86
125
 
126
+ adapter.clearSchemaCache();
87
127
  return {
88
128
  success: true,
89
129
  table,
@@ -93,17 +133,25 @@ export function createSpatialCreateColumnTool(
93
133
  nullable,
94
134
  };
95
135
  } catch (error) {
136
+ if (error instanceof ZodError) {
137
+ return { success: false, error: formatZodError(error) };
138
+ }
139
+ if (error instanceof ValidationError) {
140
+ return { success: false, error: error.message };
141
+ }
96
142
  const msg = error instanceof Error ? error.message : String(error);
97
143
  if (msg.includes("doesn't exist")) {
98
- return { exists: false, table };
144
+ return { exists: false, table: paramStr(params, "table") };
99
145
  }
100
146
  if (msg.includes("Duplicate column name")) {
147
+ const col = paramStr(params, "column");
148
+ const tbl = paramStr(params, "table");
101
149
  return {
102
150
  success: false,
103
- reason: `Column '${column}' already exists on table '${table}'`,
151
+ error: `Column '${col}' already exists on table '${tbl}'`,
104
152
  };
105
153
  }
106
- return { success: false, error: msg };
154
+ return { success: false, error: stripErrorPrefix(msg) };
107
155
  }
108
156
  },
109
157
  };
@@ -127,27 +175,32 @@ export function createSpatialCreateIndexTool(
127
175
  readOnlyHint: false,
128
176
  },
129
177
  handler: async (params: unknown, _context: RequestContext) => {
130
- const { table, column, indexName } = SpatialIndexSchema.parse(params);
178
+ try {
179
+ const { table, column, indexName } = SpatialIndexSchema.parse(params);
131
180
 
132
- // Validate identifiers
133
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(table)) {
134
- throw new Error("Invalid table name");
135
- }
136
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(column)) {
137
- throw new Error("Invalid column name");
138
- }
181
+ // Validate identifiers
182
+ validateQualifiedIdentifier(table, "table");
183
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(column)) {
184
+ return { success: false, error: "Invalid column name" };
185
+ }
139
186
 
140
- const idxName = indexName ?? `idx_spatial_${table}_${column}`;
141
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(idxName)) {
142
- throw new Error("Invalid index name");
143
- }
187
+ // For qualified names (schema.table), split for information_schema queries
188
+ const parts = table.split(".");
189
+ const bareTable = parts.length > 1 ? parts[1] : parts[0];
190
+ const schemaClause =
191
+ parts.length > 1 ? "TABLE_SCHEMA = ?" : "TABLE_SCHEMA = DATABASE()";
192
+ const schemaParams = parts.length > 1 ? [parts[0]] : [];
193
+
194
+ const idxName = indexName ?? `idx_spatial_${bareTable}_${column}`;
195
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(idxName)) {
196
+ return { success: false, error: "Invalid index name" };
197
+ }
144
198
 
145
- try {
146
199
  // Check if column is nullable - SPATIAL indexes require NOT NULL
147
200
  const colInfo = await adapter.executeQuery(
148
201
  `SELECT IS_NULLABLE, DATA_TYPE FROM information_schema.COLUMNS
149
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?`,
150
- [table, column],
202
+ WHERE ${schemaClause} AND TABLE_NAME = ? AND COLUMN_NAME = ?`,
203
+ [...schemaParams, bareTable, column],
151
204
  );
152
205
 
153
206
  const colRow = colInfo.rows?.[0];
@@ -155,20 +208,22 @@ export function createSpatialCreateIndexTool(
155
208
  const isNullable = colRow["IS_NULLABLE"] === "YES";
156
209
  const dataType = String(colRow["DATA_TYPE"]).toUpperCase();
157
210
  if (isNullable) {
158
- throw new Error(
159
- `Cannot create SPATIAL index on nullable column '${column}'. ` +
211
+ return {
212
+ success: false,
213
+ error:
214
+ `Cannot create SPATIAL index on nullable column '${column}'. ` +
160
215
  `Alter the column to NOT NULL first: ` +
161
- `ALTER TABLE \`${table}\` MODIFY \`${column}\` ${dataType} NOT NULL`,
162
- );
216
+ `ALTER TABLE ${escapeQualifiedTable(table)} MODIFY \`${column}\` ${dataType} NOT NULL`,
217
+ };
163
218
  }
164
219
  }
165
220
 
166
221
  // Check if a SPATIAL index already exists on this column (any name)
167
222
  const existingIdx = await adapter.executeQuery(
168
223
  `SELECT INDEX_NAME FROM information_schema.STATISTICS
169
- WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ? AND INDEX_TYPE = 'SPATIAL'
224
+ WHERE ${schemaClause} AND TABLE_NAME = ? AND COLUMN_NAME = ? AND INDEX_TYPE = 'SPATIAL'
170
225
  LIMIT 1`,
171
- [table, column],
226
+ [...schemaParams, bareTable, column],
172
227
  );
173
228
 
174
229
  const existingRow = existingIdx.rows?.[0];
@@ -176,14 +231,15 @@ export function createSpatialCreateIndexTool(
176
231
  const existingName = String(existingRow["INDEX_NAME"]);
177
232
  return {
178
233
  success: false,
179
- reason: `Spatial index '${existingName}' already exists on column '${column}' of table '${table}'`,
234
+ error: `Spatial index '${existingName}' already exists on column '${column}' of table '${table}'`,
180
235
  };
181
236
  }
182
237
 
183
238
  await adapter.executeQuery(
184
- `CREATE SPATIAL INDEX \`${idxName}\` ON \`${table}\`(\`${column}\`)`,
239
+ `CREATE SPATIAL INDEX \`${idxName}\` ON ${escapeQualifiedTable(table)}(\`${column}\`)`,
185
240
  );
186
241
 
242
+ adapter.clearSchemaCache();
187
243
  return {
188
244
  success: true,
189
245
  table,
@@ -191,20 +247,30 @@ export function createSpatialCreateIndexTool(
191
247
  indexName: idxName,
192
248
  };
193
249
  } catch (error) {
250
+ if (error instanceof ZodError) {
251
+ return { success: false, error: formatZodError(error) };
252
+ }
253
+ if (error instanceof ValidationError) {
254
+ return { success: false, error: error.message };
255
+ }
194
256
  const msg = error instanceof Error ? error.message : String(error);
257
+ const tbl = paramStr(params, "table");
195
258
  if (msg.includes("doesn't exist")) {
196
- return { exists: false, table };
259
+ return { exists: false, table: tbl };
197
260
  }
198
261
  if (msg.includes("Cannot create SPATIAL index on nullable column")) {
199
- return { success: false, reason: msg };
262
+ return { success: false, error: stripErrorPrefix(msg) };
200
263
  }
264
+ const idxFromParams = paramStr(params, "indexName");
265
+ const idx =
266
+ idxFromParams || `idx_spatial_${tbl}_${paramStr(params, "column")}`;
201
267
  if (msg.includes("Duplicate key name")) {
202
268
  return {
203
269
  success: false,
204
- reason: `Index '${idxName}' already exists on table '${table}'`,
270
+ error: `Index '${idx}' already exists on table '${tbl}'`,
205
271
  };
206
272
  }
207
- return { success: false, error: msg };
273
+ return { success: false, error: stripErrorPrefix(msg) };
208
274
  }
209
275
  },
210
276
  };
@@ -67,16 +67,17 @@ describe("Comparative Stats Tools", () => {
67
67
  });
68
68
 
69
69
  it("should validate inputs", async () => {
70
- await expect(
71
- correlationTool.handler(
72
- {
73
- table: "bad;table",
74
- column1: "x",
75
- column2: "y",
76
- },
77
- {} as any,
78
- ),
79
- ).rejects.toThrow("Invalid table name");
70
+ const result: any = await correlationTool.handler(
71
+ {
72
+ table: "bad;table",
73
+ column1: "x",
74
+ column2: "y",
75
+ },
76
+ {} as any,
77
+ );
78
+
79
+ expect(result.success).toBe(false);
80
+ expect(result.error).toContain("Invalid table name");
80
81
  });
81
82
  });
82
83
 
@@ -95,6 +96,7 @@ describe("Comparative Stats Tools", () => {
95
96
  {} as any,
96
97
  );
97
98
 
99
+ expect(result.success).toBe(false);
98
100
  expect(result.error).toContain("Insufficient data");
99
101
  });
100
102