benchbox 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

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 (728) hide show
  1. benchbox/__init__.py +1 -1
  2. benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query72.tpl +1 -1
  3. benchbox/_binaries/tpc-ds/{darwin-x86_64/query_templates/ansi.tpl → templates/query_templates/sqlserver.tpl} +1 -1
  4. benchbox/_binaries/tpc-ds/templates/query_variants/README +6 -0
  5. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query10.tpl → templates/query_variants/query10a.tpl} +13 -14
  6. benchbox/_binaries/tpc-ds/{darwin-x86_64/query_templates/query14.tpl → templates/query_variants/query14a.tpl} +30 -26
  7. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query18.tpl → templates/query_variants/query18a.tpl} +40 -19
  8. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query22.tpl → templates/query_variants/query22a.tpl} +31 -9
  9. benchbox/_binaries/tpc-ds/{darwin-x86_64/query_templates/query27.tpl → templates/query_variants/query27a.tpl} +23 -10
  10. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query35.tpl → templates/query_variants/query35a.tpl} +9 -8
  11. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query36.tpl → templates/query_variants/query36a.tpl} +24 -12
  12. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query51.tpl → templates/query_variants/query51a.tpl} +37 -20
  13. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query5.tpl → templates/query_variants/query5a.tpl} +15 -10
  14. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query67.tpl → templates/query_variants/query67a.tpl} +46 -18
  15. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query70.tpl → templates/query_variants/query70a.tpl} +31 -27
  16. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query77.tpl → templates/query_variants/query77a.tpl} +22 -15
  17. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query80.tpl → templates/query_variants/query80a.tpl} +22 -8
  18. benchbox/_binaries/tpc-ds/{linux-arm64/query_templates/query86.tpl → templates/query_variants/query86a.tpl} +22 -13
  19. benchbox/_binaries/tpc-h/templates/dists.dss +836 -0
  20. benchbox/_binaries/tpc-h/templates/queries/1.sql +28 -0
  21. benchbox/_binaries/tpc-h/templates/queries/10.sql +38 -0
  22. benchbox/_binaries/tpc-h/templates/queries/11.sql +34 -0
  23. benchbox/_binaries/tpc-h/templates/queries/12.sql +35 -0
  24. benchbox/_binaries/tpc-h/templates/queries/13.sql +27 -0
  25. benchbox/_binaries/tpc-h/templates/queries/14.sql +20 -0
  26. benchbox/_binaries/tpc-h/templates/queries/15.sql +40 -0
  27. benchbox/_binaries/tpc-h/templates/queries/16.sql +37 -0
  28. benchbox/_binaries/tpc-h/templates/queries/17.sql +24 -0
  29. benchbox/_binaries/tpc-h/templates/queries/18.sql +39 -0
  30. benchbox/_binaries/tpc-h/templates/queries/19.sql +42 -0
  31. benchbox/_binaries/tpc-h/templates/queries/2.sql +50 -0
  32. benchbox/_binaries/tpc-h/templates/queries/20.sql +44 -0
  33. benchbox/_binaries/tpc-h/templates/queries/21.sql +46 -0
  34. benchbox/_binaries/tpc-h/templates/queries/22.sql +44 -0
  35. benchbox/_binaries/tpc-h/templates/queries/3.sql +29 -0
  36. benchbox/_binaries/tpc-h/templates/queries/4.sql +28 -0
  37. benchbox/_binaries/tpc-h/templates/queries/5.sql +31 -0
  38. benchbox/_binaries/tpc-h/templates/queries/6.sql +16 -0
  39. benchbox/_binaries/tpc-h/templates/queries/7.sql +46 -0
  40. benchbox/_binaries/tpc-h/templates/queries/8.sql +44 -0
  41. benchbox/_binaries/tpc-h/templates/queries/9.sql +39 -0
  42. benchbox/_binaries/tpc-h/templates/variants/12a.sql +27 -0
  43. benchbox/_binaries/tpc-h/templates/variants/13a.sql +30 -0
  44. benchbox/_binaries/tpc-h/templates/variants/14a.sql +18 -0
  45. benchbox/_binaries/tpc-h/templates/variants/15a.sql +39 -0
  46. benchbox/_binaries/tpc-h/templates/variants/8a.sql +77 -0
  47. benchbox/base.py +88 -121
  48. benchbox/cli/benchmarks.py +3 -3
  49. benchbox/cli/commands/calculate_qphh.py +55 -14
  50. benchbox/cli/commands/checks.py +1 -4
  51. benchbox/cli/commands/convert.py +8 -3
  52. benchbox/cli/commands/metrics.py +55 -14
  53. benchbox/cli/commands/results.py +131 -3
  54. benchbox/cli/commands/run.py +157 -22
  55. benchbox/cli/commands/visualize.py +3 -3
  56. benchbox/cli/composite_params.py +1 -1
  57. benchbox/cli/config.py +13 -3
  58. benchbox/cli/database.py +3 -3
  59. benchbox/cli/dryrun.py +30 -4
  60. benchbox/cli/exceptions.py +2 -1
  61. benchbox/cli/execution_pipeline.py +2 -1
  62. benchbox/cli/orchestrator.py +25 -71
  63. benchbox/cli/tuning.py +1 -1
  64. benchbox/core/ai_primitives/benchmark.py +53 -0
  65. benchbox/core/ai_primitives/dataframe_operations.py +1217 -0
  66. benchbox/core/base_benchmark.py +90 -68
  67. benchbox/core/coffeeshop/queries.py +1 -1
  68. benchbox/core/coffeeshop/schema.py +1 -1
  69. benchbox/core/comparison/plotter.py +5 -4
  70. benchbox/core/dataframe/__init__.py +26 -0
  71. benchbox/core/dataframe/benchmark_suite.py +5 -4
  72. benchbox/core/dataframe/context.py +45 -0
  73. benchbox/core/dataframe/data_loader.py +180 -79
  74. benchbox/core/dataframe/maintenance_interface.py +866 -0
  75. benchbox/core/dryrun.py +152 -22
  76. benchbox/core/expected_results/registry.py +22 -5
  77. benchbox/core/manifest/io.py +4 -3
  78. benchbox/core/metadata_primitives/__init__.py +31 -0
  79. benchbox/core/metadata_primitives/benchmark.py +337 -0
  80. benchbox/core/metadata_primitives/dataframe_operations.py +1824 -0
  81. benchbox/core/platform_registry.py +134 -45
  82. benchbox/core/read_primitives/benchmark.py +56 -4
  83. benchbox/core/read_primitives/dataframe_queries.py +6547 -0
  84. benchbox/core/results/__init__.py +47 -6
  85. benchbox/core/results/builder.py +909 -0
  86. benchbox/core/results/database.py +5 -5
  87. benchbox/core/results/exporter.py +58 -96
  88. benchbox/core/results/filenames.py +102 -0
  89. benchbox/core/results/loader.py +10 -9
  90. benchbox/core/results/metrics.py +211 -0
  91. benchbox/core/results/models.py +3 -1
  92. benchbox/core/results/normalizer.py +346 -0
  93. benchbox/core/results/platform_info.py +235 -0
  94. benchbox/core/results/query_normalizer.py +200 -0
  95. benchbox/core/results/schema.py +368 -69
  96. benchbox/core/runner/conversion.py +2 -0
  97. benchbox/core/runner/dataframe_runner.py +135 -131
  98. benchbox/core/runner/runner.py +111 -18
  99. benchbox/core/schemas.py +145 -3
  100. benchbox/core/ssb/generator.py +14 -2
  101. benchbox/core/tpc_compliance.py +4 -4
  102. benchbox/core/tpc_metrics.py +9 -4
  103. benchbox/core/tpcdi/generator/manifest.py +15 -2
  104. benchbox/core/tpcds/benchmark/runner.py +3 -7
  105. benchbox/core/tpcds/c_tools.py +34 -28
  106. benchbox/core/tpcds/dataframe_queries/queries.py +44 -21
  107. benchbox/core/tpcds/generator/filesystem.py +23 -11
  108. benchbox/core/tpcds/generator/manager.py +3 -2
  109. benchbox/core/tpcds/maintenance_test.py +281 -0
  110. benchbox/core/tpcds/power_test.py +21 -11
  111. benchbox/core/tpcds/throughput_test.py +27 -9
  112. benchbox/core/tpcds_obt/etl/transformer.py +24 -5
  113. benchbox/core/tpch/dataframe_queries.py +46 -43
  114. benchbox/core/tpch/generator.py +21 -8
  115. benchbox/core/tpch/maintenance_test.py +87 -0
  116. benchbox/core/tpch/power_test.py +21 -5
  117. benchbox/core/tpch/queries.py +2 -7
  118. benchbox/core/tpch/streams.py +3 -19
  119. benchbox/core/transaction_primitives/benchmark.py +99 -0
  120. benchbox/core/transaction_primitives/dataframe_operations.py +1294 -0
  121. benchbox/core/transaction_primitives/generator.py +11 -4
  122. benchbox/core/visualization/__init__.py +2 -2
  123. benchbox/core/visualization/charts.py +4 -4
  124. benchbox/core/visualization/dependencies.py +1 -12
  125. benchbox/core/visualization/exporters.py +15 -26
  126. benchbox/core/visualization/result_plotter.py +90 -49
  127. benchbox/core/visualization/templates.py +6 -6
  128. benchbox/core/write_primitives/__init__.py +13 -0
  129. benchbox/core/write_primitives/benchmark.py +66 -0
  130. benchbox/core/write_primitives/dataframe_operations.py +912 -0
  131. benchbox/core/write_primitives/generator.py +11 -4
  132. benchbox/mcp/__init__.py +5 -1
  133. benchbox/mcp/errors.py +29 -0
  134. benchbox/mcp/resources/registry.py +12 -7
  135. benchbox/mcp/schemas.py +62 -0
  136. benchbox/mcp/server.py +17 -14
  137. benchbox/mcp/tools/__init__.py +3 -0
  138. benchbox/mcp/tools/analytics.py +550 -582
  139. benchbox/mcp/tools/benchmark.py +603 -611
  140. benchbox/mcp/tools/discovery.py +156 -205
  141. benchbox/mcp/tools/results.py +332 -533
  142. benchbox/mcp/tools/visualization.py +449 -0
  143. benchbox/platforms/__init__.py +740 -622
  144. benchbox/platforms/adapter_factory.py +6 -6
  145. benchbox/platforms/azure_synapse.py +3 -7
  146. benchbox/platforms/base/adapter.py +189 -49
  147. benchbox/platforms/base/cloud_spark/config.py +8 -0
  148. benchbox/platforms/base/cloud_spark/mixins.py +96 -0
  149. benchbox/platforms/base/cloud_spark/session.py +4 -2
  150. benchbox/platforms/base/cloud_spark/staging.py +15 -7
  151. benchbox/platforms/base/data_loading.py +315 -1
  152. benchbox/platforms/base/format_capabilities.py +37 -2
  153. benchbox/platforms/base/utils.py +6 -4
  154. benchbox/platforms/bigquery.py +5 -6
  155. benchbox/platforms/clickhouse_cloud.py +263 -0
  156. benchbox/platforms/databricks/adapter.py +16 -15
  157. benchbox/platforms/databricks/dataframe_adapter.py +4 -1
  158. benchbox/platforms/dataframe/__init__.py +31 -0
  159. benchbox/platforms/dataframe/benchmark_mixin.py +779 -0
  160. benchbox/platforms/dataframe/cudf_df.py +3 -3
  161. benchbox/platforms/dataframe/dask_df.py +3 -3
  162. benchbox/platforms/dataframe/datafusion_df.py +152 -15
  163. benchbox/platforms/dataframe/delta_lake_maintenance.py +341 -0
  164. benchbox/platforms/dataframe/ducklake_maintenance.py +402 -0
  165. benchbox/platforms/dataframe/expression_family.py +47 -8
  166. benchbox/platforms/dataframe/hudi_maintenance.py +437 -0
  167. benchbox/platforms/dataframe/iceberg_maintenance.py +605 -0
  168. benchbox/platforms/dataframe/modin_df.py +3 -3
  169. benchbox/platforms/dataframe/pandas_df.py +3 -3
  170. benchbox/platforms/dataframe/pandas_family.py +59 -8
  171. benchbox/platforms/dataframe/platform_checker.py +16 -49
  172. benchbox/platforms/dataframe/polars_df.py +14 -12
  173. benchbox/platforms/dataframe/polars_maintenance.py +630 -0
  174. benchbox/platforms/dataframe/pyspark_df.py +15 -0
  175. benchbox/platforms/dataframe/pyspark_maintenance.py +613 -0
  176. benchbox/platforms/datafusion.py +5 -6
  177. benchbox/platforms/duckdb.py +2 -1
  178. benchbox/platforms/fabric_warehouse.py +15 -15
  179. benchbox/platforms/firebolt.py +3 -2
  180. benchbox/platforms/influxdb/adapter.py +7 -3
  181. benchbox/platforms/motherduck.py +3 -2
  182. benchbox/platforms/onehouse/__init__.py +39 -0
  183. benchbox/platforms/onehouse/onehouse_client.py +509 -0
  184. benchbox/platforms/onehouse/quanton_adapter.py +646 -0
  185. benchbox/platforms/postgresql.py +5 -9
  186. benchbox/platforms/presto.py +2 -2
  187. benchbox/platforms/pyspark/session.py +3 -3
  188. benchbox/platforms/pyspark/sql_adapter.py +2 -3
  189. benchbox/platforms/redshift.py +7 -7
  190. benchbox/platforms/snowflake.py +4 -4
  191. benchbox/platforms/snowpark_connect.py +2 -1
  192. benchbox/platforms/trino.py +2 -2
  193. benchbox/release/__init__.py +17 -0
  194. benchbox/release/content_validation.py +745 -0
  195. benchbox/release/workflow.py +17 -0
  196. benchbox/utils/VERSION_MANAGEMENT.md +1 -1
  197. benchbox/utils/cloud_storage.py +7 -5
  198. benchbox/utils/compression.py +8 -8
  199. benchbox/utils/compression_mixin.py +2 -1
  200. benchbox/utils/data_validation.py +23 -14
  201. benchbox/utils/dependencies.py +47 -7
  202. benchbox/utils/file_format.py +407 -0
  203. benchbox/utils/format_converters/__init__.py +5 -1
  204. benchbox/utils/format_converters/ducklake_converter.py +227 -0
  205. benchbox/utils/format_converters/vortex_converter.py +168 -0
  206. benchbox/utils/tpc_compilation.py +43 -0
  207. benchbox/utils/version.py +14 -2
  208. {benchbox-0.1.0.dist-info → benchbox-0.1.1.dist-info}/METADATA +15 -15
  209. benchbox-0.1.1.dist-info/RECORD +839 -0
  210. {benchbox-0.1.0.dist-info → benchbox-0.1.1.dist-info}/WHEEL +1 -1
  211. benchbox/_binaries/tpc-ds/darwin-arm64/query_templates/sqlserver.tpl +0 -37
  212. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/README +0 -4
  213. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/db2.tpl +0 -38
  214. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/netezza.tpl +0 -38
  215. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/oracle.tpl +0 -38
  216. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query1.tpl +0 -62
  217. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query10.tpl +0 -98
  218. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query11.tpl +0 -119
  219. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query12.tpl +0 -72
  220. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query13.tpl +0 -89
  221. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query15.tpl +0 -56
  222. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query16.tpl +0 -76
  223. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query17.tpl +0 -80
  224. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query18.tpl +0 -73
  225. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query19.tpl +0 -64
  226. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query2.tpl +0 -94
  227. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query20.tpl +0 -67
  228. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query21.tpl +0 -65
  229. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query22.tpl +0 -54
  230. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query23.tpl +0 -144
  231. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query24.tpl +0 -147
  232. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query25.tpl +0 -84
  233. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query26.tpl +0 -61
  234. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query28.tpl +0 -90
  235. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query29.tpl +0 -85
  236. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query3.tpl +0 -58
  237. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query30.tpl +0 -66
  238. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query31.tpl +0 -88
  239. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query32.tpl +0 -65
  240. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query33.tpl +0 -113
  241. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query34.tpl +0 -77
  242. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query35.tpl +0 -98
  243. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query36.tpl +0 -74
  244. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query37.tpl +0 -57
  245. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query38.tpl +0 -58
  246. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query39.tpl +0 -93
  247. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query4.tpl +0 -154
  248. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query40.tpl +0 -63
  249. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query41.tpl +0 -90
  250. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query42.tpl +0 -64
  251. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query43.tpl +0 -55
  252. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query44.tpl +0 -72
  253. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query45.tpl +0 -56
  254. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query46.tpl +0 -78
  255. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query47.tpl +0 -89
  256. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query48.tpl +0 -104
  257. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query49.tpl +0 -164
  258. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query5.tpl +0 -165
  259. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query50.tpl +0 -96
  260. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query51.tpl +0 -80
  261. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query52.tpl +0 -59
  262. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query53.tpl +0 -64
  263. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query54.tpl +0 -95
  264. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query55.tpl +0 -52
  265. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query56.tpl +0 -108
  266. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query57.tpl +0 -87
  267. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query58.tpl +0 -101
  268. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query59.tpl +0 -79
  269. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query6.tpl +0 -62
  270. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query60.tpl +0 -115
  271. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query61.tpl +0 -83
  272. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query62.tpl +0 -71
  273. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query63.tpl +0 -64
  274. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query64.tpl +0 -157
  275. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query65.tpl +0 -62
  276. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query66.tpl +0 -261
  277. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query67.tpl +0 -81
  278. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query68.tpl +0 -82
  279. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query69.tpl +0 -85
  280. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query7.tpl +0 -60
  281. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query70.tpl +0 -73
  282. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query71.tpl +0 -74
  283. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query72.tpl +0 -67
  284. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query73.tpl +0 -69
  285. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query74.tpl +0 -99
  286. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query75.tpl +0 -107
  287. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query76.tpl +0 -64
  288. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query77.tpl +0 -145
  289. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query78.tpl +0 -94
  290. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query79.tpl +0 -60
  291. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query8.tpl +0 -144
  292. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query80.tpl +0 -131
  293. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query81.tpl +0 -68
  294. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query82.tpl +0 -56
  295. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query83.tpl +0 -104
  296. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query84.tpl +0 -58
  297. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query85.tpl +0 -121
  298. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query86.tpl +0 -60
  299. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query87.tpl +0 -56
  300. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query88.tpl +0 -128
  301. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query89.tpl +0 -75
  302. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query9.tpl +0 -88
  303. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query90.tpl +0 -58
  304. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query91.tpl +0 -68
  305. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query92.tpl +0 -68
  306. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query93.tpl +0 -53
  307. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query94.tpl +0 -67
  308. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query95.tpl +0 -71
  309. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query96.tpl +0 -52
  310. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query97.tpl +0 -62
  311. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query98.tpl +0 -70
  312. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/query99.tpl +0 -69
  313. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/sqlserver.tpl +0 -37
  314. benchbox/_binaries/tpc-ds/darwin-x86_64/query_templates/templates.lst +0 -99
  315. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/README +0 -4
  316. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/ansi.tpl +0 -38
  317. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/db2.tpl +0 -38
  318. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/netezza.tpl +0 -38
  319. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/oracle.tpl +0 -38
  320. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query1.tpl +0 -62
  321. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query11.tpl +0 -119
  322. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query12.tpl +0 -72
  323. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query13.tpl +0 -89
  324. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query14.tpl +0 -247
  325. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query15.tpl +0 -56
  326. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query16.tpl +0 -76
  327. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query17.tpl +0 -80
  328. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query19.tpl +0 -64
  329. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query2.tpl +0 -94
  330. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query20.tpl +0 -67
  331. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query21.tpl +0 -65
  332. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query23.tpl +0 -144
  333. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query24.tpl +0 -147
  334. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query25.tpl +0 -84
  335. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query26.tpl +0 -61
  336. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query27.tpl +0 -68
  337. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query28.tpl +0 -90
  338. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query29.tpl +0 -85
  339. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query3.tpl +0 -58
  340. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query30.tpl +0 -66
  341. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query31.tpl +0 -88
  342. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query32.tpl +0 -65
  343. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query33.tpl +0 -113
  344. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query34.tpl +0 -77
  345. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query37.tpl +0 -57
  346. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query38.tpl +0 -58
  347. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query39.tpl +0 -93
  348. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query4.tpl +0 -154
  349. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query40.tpl +0 -63
  350. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query41.tpl +0 -90
  351. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query42.tpl +0 -64
  352. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query43.tpl +0 -55
  353. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query44.tpl +0 -72
  354. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query45.tpl +0 -56
  355. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query46.tpl +0 -78
  356. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query47.tpl +0 -89
  357. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query48.tpl +0 -104
  358. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query49.tpl +0 -164
  359. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query50.tpl +0 -96
  360. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query52.tpl +0 -59
  361. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query53.tpl +0 -64
  362. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query54.tpl +0 -95
  363. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query55.tpl +0 -52
  364. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query56.tpl +0 -108
  365. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query57.tpl +0 -87
  366. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query58.tpl +0 -101
  367. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query59.tpl +0 -79
  368. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query6.tpl +0 -62
  369. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query60.tpl +0 -115
  370. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query61.tpl +0 -83
  371. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query62.tpl +0 -71
  372. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query63.tpl +0 -64
  373. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query64.tpl +0 -157
  374. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query65.tpl +0 -62
  375. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query66.tpl +0 -261
  376. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query68.tpl +0 -82
  377. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query69.tpl +0 -85
  378. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query7.tpl +0 -60
  379. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query71.tpl +0 -74
  380. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query72.tpl +0 -67
  381. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query73.tpl +0 -69
  382. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query74.tpl +0 -99
  383. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query75.tpl +0 -107
  384. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query76.tpl +0 -64
  385. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query78.tpl +0 -94
  386. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query79.tpl +0 -60
  387. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query8.tpl +0 -144
  388. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query81.tpl +0 -68
  389. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query82.tpl +0 -56
  390. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query83.tpl +0 -104
  391. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query84.tpl +0 -58
  392. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query85.tpl +0 -121
  393. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query87.tpl +0 -56
  394. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query88.tpl +0 -128
  395. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query89.tpl +0 -75
  396. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query9.tpl +0 -88
  397. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query90.tpl +0 -58
  398. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query91.tpl +0 -68
  399. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query92.tpl +0 -68
  400. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query93.tpl +0 -53
  401. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query94.tpl +0 -67
  402. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query95.tpl +0 -71
  403. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query96.tpl +0 -52
  404. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query97.tpl +0 -62
  405. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query98.tpl +0 -70
  406. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/query99.tpl +0 -69
  407. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/sqlserver.tpl +0 -37
  408. benchbox/_binaries/tpc-ds/linux-arm64/query_templates/templates.lst +0 -99
  409. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/README +0 -4
  410. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/ansi.tpl +0 -38
  411. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/db2.tpl +0 -38
  412. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/netezza.tpl +0 -38
  413. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/oracle.tpl +0 -38
  414. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query1.tpl +0 -62
  415. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query10.tpl +0 -98
  416. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query11.tpl +0 -119
  417. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query12.tpl +0 -72
  418. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query13.tpl +0 -89
  419. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query14.tpl +0 -247
  420. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query15.tpl +0 -56
  421. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query16.tpl +0 -76
  422. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query17.tpl +0 -80
  423. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query18.tpl +0 -73
  424. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query19.tpl +0 -64
  425. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query2.tpl +0 -94
  426. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query20.tpl +0 -67
  427. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query21.tpl +0 -65
  428. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query22.tpl +0 -54
  429. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query23.tpl +0 -144
  430. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query24.tpl +0 -147
  431. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query25.tpl +0 -84
  432. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query26.tpl +0 -61
  433. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query27.tpl +0 -68
  434. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query28.tpl +0 -90
  435. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query29.tpl +0 -85
  436. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query3.tpl +0 -58
  437. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query30.tpl +0 -66
  438. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query31.tpl +0 -88
  439. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query32.tpl +0 -65
  440. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query33.tpl +0 -113
  441. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query34.tpl +0 -77
  442. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query35.tpl +0 -98
  443. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query36.tpl +0 -74
  444. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query37.tpl +0 -57
  445. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query38.tpl +0 -58
  446. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query39.tpl +0 -93
  447. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query4.tpl +0 -154
  448. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query40.tpl +0 -63
  449. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query41.tpl +0 -90
  450. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query42.tpl +0 -64
  451. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query43.tpl +0 -55
  452. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query44.tpl +0 -72
  453. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query45.tpl +0 -56
  454. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query46.tpl +0 -78
  455. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query47.tpl +0 -89
  456. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query48.tpl +0 -104
  457. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query49.tpl +0 -164
  458. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query5.tpl +0 -165
  459. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query50.tpl +0 -96
  460. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query51.tpl +0 -80
  461. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query52.tpl +0 -59
  462. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query53.tpl +0 -64
  463. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query54.tpl +0 -95
  464. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query55.tpl +0 -52
  465. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query56.tpl +0 -108
  466. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query57.tpl +0 -87
  467. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query58.tpl +0 -101
  468. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query59.tpl +0 -79
  469. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query6.tpl +0 -62
  470. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query60.tpl +0 -115
  471. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query61.tpl +0 -83
  472. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query62.tpl +0 -71
  473. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query63.tpl +0 -64
  474. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query64.tpl +0 -157
  475. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query65.tpl +0 -62
  476. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query66.tpl +0 -261
  477. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query67.tpl +0 -81
  478. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query68.tpl +0 -82
  479. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query69.tpl +0 -85
  480. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query7.tpl +0 -60
  481. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query70.tpl +0 -73
  482. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query71.tpl +0 -74
  483. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query72.tpl +0 -67
  484. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query73.tpl +0 -69
  485. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query74.tpl +0 -99
  486. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query75.tpl +0 -107
  487. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query76.tpl +0 -64
  488. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query77.tpl +0 -145
  489. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query78.tpl +0 -94
  490. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query79.tpl +0 -60
  491. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query8.tpl +0 -144
  492. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query80.tpl +0 -131
  493. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query81.tpl +0 -68
  494. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query82.tpl +0 -56
  495. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query83.tpl +0 -104
  496. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query84.tpl +0 -58
  497. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query85.tpl +0 -121
  498. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query86.tpl +0 -60
  499. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query87.tpl +0 -56
  500. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query88.tpl +0 -128
  501. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query89.tpl +0 -75
  502. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query9.tpl +0 -88
  503. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query90.tpl +0 -58
  504. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query91.tpl +0 -68
  505. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query92.tpl +0 -68
  506. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query93.tpl +0 -53
  507. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query94.tpl +0 -67
  508. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query95.tpl +0 -71
  509. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query96.tpl +0 -52
  510. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query97.tpl +0 -62
  511. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query98.tpl +0 -70
  512. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/query99.tpl +0 -69
  513. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/sqlserver.tpl +0 -37
  514. benchbox/_binaries/tpc-ds/linux-x86_64/query_templates/templates.lst +0 -99
  515. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/README +0 -4
  516. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/ansi.tpl +0 -38
  517. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/db2.tpl +0 -38
  518. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/netezza.tpl +0 -38
  519. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/oracle.tpl +0 -38
  520. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query1.tpl +0 -62
  521. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query10.tpl +0 -98
  522. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query11.tpl +0 -119
  523. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query12.tpl +0 -72
  524. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query13.tpl +0 -89
  525. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query14.tpl +0 -247
  526. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query15.tpl +0 -56
  527. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query16.tpl +0 -76
  528. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query17.tpl +0 -80
  529. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query18.tpl +0 -73
  530. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query19.tpl +0 -64
  531. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query2.tpl +0 -94
  532. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query20.tpl +0 -67
  533. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query21.tpl +0 -65
  534. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query22.tpl +0 -54
  535. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query23.tpl +0 -144
  536. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query24.tpl +0 -147
  537. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query25.tpl +0 -84
  538. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query26.tpl +0 -61
  539. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query27.tpl +0 -68
  540. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query28.tpl +0 -90
  541. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query29.tpl +0 -85
  542. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query3.tpl +0 -58
  543. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query30.tpl +0 -66
  544. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query31.tpl +0 -88
  545. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query32.tpl +0 -65
  546. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query33.tpl +0 -113
  547. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query34.tpl +0 -77
  548. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query35.tpl +0 -98
  549. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query36.tpl +0 -74
  550. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query37.tpl +0 -57
  551. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query38.tpl +0 -58
  552. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query39.tpl +0 -93
  553. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query4.tpl +0 -154
  554. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query40.tpl +0 -63
  555. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query41.tpl +0 -90
  556. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query42.tpl +0 -64
  557. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query43.tpl +0 -55
  558. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query44.tpl +0 -72
  559. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query45.tpl +0 -56
  560. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query46.tpl +0 -78
  561. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query47.tpl +0 -89
  562. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query48.tpl +0 -104
  563. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query49.tpl +0 -164
  564. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query5.tpl +0 -165
  565. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query50.tpl +0 -96
  566. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query51.tpl +0 -80
  567. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query52.tpl +0 -59
  568. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query53.tpl +0 -64
  569. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query54.tpl +0 -95
  570. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query55.tpl +0 -52
  571. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query56.tpl +0 -108
  572. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query57.tpl +0 -87
  573. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query58.tpl +0 -101
  574. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query59.tpl +0 -79
  575. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query6.tpl +0 -62
  576. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query60.tpl +0 -115
  577. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query61.tpl +0 -83
  578. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query62.tpl +0 -71
  579. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query63.tpl +0 -64
  580. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query64.tpl +0 -157
  581. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query65.tpl +0 -62
  582. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query66.tpl +0 -261
  583. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query67.tpl +0 -81
  584. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query68.tpl +0 -82
  585. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query69.tpl +0 -85
  586. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query7.tpl +0 -60
  587. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query70.tpl +0 -73
  588. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query71.tpl +0 -74
  589. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query72.tpl +0 -67
  590. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query73.tpl +0 -69
  591. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query74.tpl +0 -99
  592. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query75.tpl +0 -107
  593. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query76.tpl +0 -64
  594. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query77.tpl +0 -145
  595. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query78.tpl +0 -94
  596. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query79.tpl +0 -60
  597. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query8.tpl +0 -144
  598. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query80.tpl +0 -131
  599. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query81.tpl +0 -68
  600. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query82.tpl +0 -56
  601. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query83.tpl +0 -104
  602. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query84.tpl +0 -58
  603. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query85.tpl +0 -121
  604. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query86.tpl +0 -60
  605. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query87.tpl +0 -56
  606. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query88.tpl +0 -128
  607. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query89.tpl +0 -75
  608. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query9.tpl +0 -88
  609. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query90.tpl +0 -58
  610. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query91.tpl +0 -68
  611. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query92.tpl +0 -68
  612. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query93.tpl +0 -53
  613. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query94.tpl +0 -67
  614. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query95.tpl +0 -71
  615. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query96.tpl +0 -52
  616. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query97.tpl +0 -62
  617. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query98.tpl +0 -70
  618. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/query99.tpl +0 -69
  619. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/sqlserver.tpl +0 -37
  620. benchbox/_binaries/tpc-ds/windows-x86_64/query_templates/templates.lst +0 -99
  621. benchbox-0.1.0.dist-info/RECORD +0 -1192
  622. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/README +0 -0
  623. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/ansi.tpl +0 -0
  624. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/db2.tpl +0 -0
  625. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/netezza.tpl +0 -0
  626. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/oracle.tpl +0 -0
  627. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query1.tpl +0 -0
  628. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query10.tpl +0 -0
  629. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query11.tpl +0 -0
  630. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query12.tpl +0 -0
  631. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query13.tpl +0 -0
  632. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query14.tpl +0 -0
  633. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query15.tpl +0 -0
  634. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query16.tpl +0 -0
  635. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query17.tpl +0 -0
  636. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query18.tpl +0 -0
  637. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query19.tpl +0 -0
  638. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query2.tpl +0 -0
  639. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query20.tpl +0 -0
  640. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query21.tpl +0 -0
  641. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query22.tpl +0 -0
  642. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query23.tpl +0 -0
  643. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query24.tpl +0 -0
  644. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query25.tpl +0 -0
  645. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query26.tpl +0 -0
  646. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query27.tpl +0 -0
  647. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query28.tpl +0 -0
  648. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query29.tpl +0 -0
  649. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query3.tpl +0 -0
  650. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query30.tpl +0 -0
  651. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query31.tpl +0 -0
  652. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query32.tpl +0 -0
  653. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query33.tpl +0 -0
  654. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query34.tpl +0 -0
  655. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query35.tpl +0 -0
  656. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query36.tpl +0 -0
  657. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query37.tpl +0 -0
  658. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query38.tpl +0 -0
  659. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query39.tpl +0 -0
  660. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query4.tpl +0 -0
  661. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query40.tpl +0 -0
  662. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query41.tpl +0 -0
  663. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query42.tpl +0 -0
  664. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query43.tpl +0 -0
  665. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query44.tpl +0 -0
  666. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query45.tpl +0 -0
  667. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query46.tpl +0 -0
  668. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query47.tpl +0 -0
  669. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query48.tpl +0 -0
  670. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query49.tpl +0 -0
  671. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query5.tpl +0 -0
  672. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query50.tpl +0 -0
  673. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query51.tpl +0 -0
  674. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query52.tpl +0 -0
  675. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query53.tpl +0 -0
  676. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query54.tpl +0 -0
  677. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query55.tpl +0 -0
  678. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query56.tpl +0 -0
  679. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query57.tpl +0 -0
  680. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query58.tpl +0 -0
  681. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query59.tpl +0 -0
  682. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query6.tpl +0 -0
  683. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query60.tpl +0 -0
  684. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query61.tpl +0 -0
  685. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query62.tpl +0 -0
  686. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query63.tpl +0 -0
  687. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query64.tpl +0 -0
  688. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query65.tpl +0 -0
  689. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query66.tpl +0 -0
  690. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query67.tpl +0 -0
  691. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query68.tpl +0 -0
  692. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query69.tpl +0 -0
  693. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query7.tpl +0 -0
  694. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query70.tpl +0 -0
  695. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query71.tpl +0 -0
  696. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query73.tpl +0 -0
  697. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query74.tpl +0 -0
  698. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query75.tpl +0 -0
  699. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query76.tpl +0 -0
  700. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query77.tpl +0 -0
  701. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query78.tpl +0 -0
  702. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query79.tpl +0 -0
  703. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query8.tpl +0 -0
  704. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query80.tpl +0 -0
  705. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query81.tpl +0 -0
  706. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query82.tpl +0 -0
  707. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query83.tpl +0 -0
  708. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query84.tpl +0 -0
  709. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query85.tpl +0 -0
  710. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query86.tpl +0 -0
  711. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query87.tpl +0 -0
  712. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query88.tpl +0 -0
  713. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query89.tpl +0 -0
  714. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query9.tpl +0 -0
  715. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query90.tpl +0 -0
  716. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query91.tpl +0 -0
  717. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query92.tpl +0 -0
  718. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query93.tpl +0 -0
  719. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query94.tpl +0 -0
  720. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query95.tpl +0 -0
  721. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query96.tpl +0 -0
  722. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query97.tpl +0 -0
  723. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query98.tpl +0 -0
  724. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/query99.tpl +0 -0
  725. /benchbox/_binaries/tpc-ds/{darwin-arm64 → templates}/query_templates/templates.lst +0 -0
  726. {benchbox-0.1.0.dist-info → benchbox-0.1.1.dist-info}/entry_points.txt +0 -0
  727. {benchbox-0.1.0.dist-info → benchbox-0.1.1.dist-info}/licenses/LICENSE +0 -0
  728. {benchbox-0.1.0.dist-info → benchbox-0.1.1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  """Analytics tools for BenchBox MCP server.
2
2
 
3
- Provides tools for query plan analysis and regression detection.
3
+ Provides tools for result comparison, regression detection, and performance trends.
4
4
 
5
5
  Copyright 2026 Joe Harris / BenchBox Project
6
6
 
@@ -11,13 +11,18 @@ from __future__ import annotations
11
11
 
12
12
  import json
13
13
  import logging
14
+ import math
15
+ from datetime import datetime
14
16
  from pathlib import Path
15
17
  from typing import Any
16
18
 
17
19
  from mcp.server.fastmcp import FastMCP
18
20
  from mcp.types import ToolAnnotations
19
21
 
22
+ from benchbox.core.results.exporter import ResultExporter
23
+ from benchbox.core.results.query_normalizer import normalize_query_id
20
24
  from benchbox.mcp.errors import ErrorCode, make_error, make_not_found_error
25
+ from benchbox.utils.printing import get_quiet_console
21
26
 
22
27
  logger = logging.getLogger(__name__)
23
28
 
@@ -35,11 +40,62 @@ DEFAULT_RESULTS_DIR = Path("benchmark_runs/results")
35
40
 
36
41
 
37
42
  def register_analytics_tools(mcp: FastMCP) -> None:
38
- """Register analytics tools with the MCP server.
43
+ """Register analytics tools with the MCP server."""
39
44
 
40
- Args:
41
- mcp: The FastMCP server instance to register tools with.
42
- """
45
+ @mcp.tool(annotations=ANALYTICS_READONLY_ANNOTATIONS)
46
+ def analyze_results(
47
+ analysis: str = "compare",
48
+ file1: str | None = None,
49
+ file2: str | None = None,
50
+ platform: str | None = None,
51
+ benchmark: str | None = None,
52
+ threshold_percent: float = 10.0,
53
+ metric: str = "geometric_mean",
54
+ group_by: str = "platform",
55
+ limit: int = 10,
56
+ ) -> dict[str, Any]:
57
+ """Analyze benchmark results.
58
+
59
+ Args:
60
+ analysis: Analysis type: 'compare', 'regressions', 'trends', 'aggregate'
61
+ file1: Baseline result file (for 'compare')
62
+ file2: Comparison result file (for 'compare')
63
+ platform: Filter by platform name
64
+ benchmark: Filter by benchmark name
65
+ threshold_percent: Change threshold for regressions (default: 10%)
66
+ metric: Metric for trends: geometric_mean, p50, p95, p99, total_time
67
+ group_by: Grouping for aggregate: platform, benchmark, date
68
+ limit: Max runs to analyze (default: 10)
69
+
70
+ Returns:
71
+ Analysis results based on the selected type.
72
+ """
73
+ analysis_lower = analysis.lower()
74
+
75
+ if analysis_lower == "compare":
76
+ if not file1 or not file2:
77
+ return make_error(
78
+ ErrorCode.VALIDATION_ERROR,
79
+ "compare analysis requires file1 and file2 parameters",
80
+ suggestion="Provide both file1 and file2 for comparison",
81
+ )
82
+ return _compare_results_impl(file1, file2, threshold_percent)
83
+
84
+ elif analysis_lower == "regressions":
85
+ return _detect_regressions_impl(platform, benchmark, threshold_percent, limit)
86
+
87
+ elif analysis_lower == "trends":
88
+ return _get_performance_trends_impl(platform, benchmark, metric, limit)
89
+
90
+ elif analysis_lower == "aggregate":
91
+ return _aggregate_results_impl(platform, benchmark, group_by)
92
+
93
+ else:
94
+ return make_error(
95
+ ErrorCode.VALIDATION_ERROR,
96
+ f"Invalid analysis type: {analysis}",
97
+ details={"valid_types": ["compare", "regressions", "trends", "aggregate"]},
98
+ )
43
99
 
44
100
  @mcp.tool(annotations=ANALYTICS_READONLY_ANNOTATIONS)
45
101
  def get_query_plan(
@@ -49,22 +105,14 @@ def register_analytics_tools(mcp: FastMCP) -> None:
49
105
  ) -> dict[str, Any]:
50
106
  """Get query execution plan from benchmark results.
51
107
 
52
- Retrieves the query plan for a specific query from a benchmark run.
53
- Query plans must have been captured using --capture-plans during benchmark execution.
54
-
55
108
  Args:
56
- result_file: Name of the result file containing query plans
109
+ result_file: Result file containing query plans
57
110
  query_id: Query identifier (e.g., '1', 'Q1', 'q05')
58
- format: Output format ('tree', 'json', or 'summary')
111
+ format: Output format: 'tree', 'json', 'summary'
59
112
 
60
113
  Returns:
61
114
  Query plan in the requested format.
62
-
63
- Example:
64
- get_query_plan(result_file="run.json", query_id="5")
65
- get_query_plan(result_file="run.json", query_id="Q1", format="summary")
66
115
  """
67
- # Validate format
68
116
  valid_formats = ["tree", "json", "summary"]
69
117
  format_lower = format.lower()
70
118
  if format_lower not in valid_formats:
@@ -72,10 +120,8 @@ def register_analytics_tools(mcp: FastMCP) -> None:
72
120
  ErrorCode.VALIDATION_INVALID_FORMAT,
73
121
  f"Invalid format: {format}",
74
122
  details={"valid_formats": valid_formats},
75
- suggestion=f"Use one of: {', '.join(valid_formats)}",
76
123
  )
77
124
 
78
- # Load the results file
79
125
  results_dir = DEFAULT_RESULTS_DIR
80
126
  file_path = results_dir / result_file
81
127
 
@@ -88,74 +134,62 @@ def register_analytics_tools(mcp: FastMCP) -> None:
88
134
  ErrorCode.RESOURCE_NOT_FOUND,
89
135
  f"Result file not found: {result_file}",
90
136
  details={"requested_file": result_file},
91
- suggestion="Use list_recent_runs() to see available result files",
92
137
  )
93
138
 
94
139
  try:
95
140
  with open(file_path) as f:
96
141
  data = json.load(f)
97
142
 
98
- # Normalize query ID
99
- normalized_id = query_id.upper().lstrip("Q")
100
- search_ids = [query_id, normalized_id, f"Q{normalized_id}", f"q{normalized_id}"]
143
+ normalized_id = normalize_query_id(query_id)
101
144
 
102
- # Search for query execution across all phases
103
145
  query_exec = None
104
- found_phase = None
105
- for phase_name, phase_data in data.get("phases", {}).items():
106
- for query_result in phase_data.get("queries", []):
107
- qid = query_result.get("query_id", "")
108
- if qid in search_ids or str(qid) in search_ids:
109
- query_exec = query_result
110
- found_phase = phase_name
111
- break
112
- if query_exec:
146
+ for query_result in data.get("queries", []):
147
+ qid = query_result.get("id", "")
148
+ if normalize_query_id(qid) == normalized_id:
149
+ query_exec = query_result
113
150
  break
114
151
 
115
152
  if not query_exec:
116
- # List available query IDs
117
- available_ids = []
118
- for phase_data in data.get("phases", {}).values():
119
- for q in phase_data.get("queries", []):
120
- if "query_id" in q:
121
- available_ids.append(str(q["query_id"]))
122
-
123
- return make_not_found_error(
124
- "query",
125
- query_id,
126
- available=sorted(set(available_ids))[:20],
127
- )
153
+ available_ids = [str(q.get("id", "")) for q in data.get("queries", []) if q.get("id")]
154
+ return make_not_found_error("query", query_id, available=sorted(set(available_ids))[:20])
155
+
156
+ plans_path = file_path.with_suffix("").with_suffix(".plans.json")
157
+ if not plans_path.exists():
158
+ plans_path = Path(str(file_path).replace(".json", ".plans.json"))
159
+
160
+ if not plans_path.exists():
161
+ return {
162
+ "status": "no_plan",
163
+ "query_id": normalized_id,
164
+ "message": "No query plan captured for this query",
165
+ "suggestion": "Run benchmark with --capture-plans flag",
166
+ "query_info": {"runtime_ms": query_exec.get("ms"), "status": query_exec.get("status")},
167
+ }
168
+
169
+ with open(plans_path) as plans_handle:
170
+ plans_data = json.load(plans_handle)
128
171
 
129
- # Check if query plan was captured
130
- query_plan = query_exec.get("query_plan")
131
- if not query_plan:
172
+ query_plan_entry = plans_data.get("queries", {}).get(normalized_id)
173
+ if not query_plan_entry or "plan" not in query_plan_entry:
132
174
  return {
133
175
  "status": "no_plan",
134
- "query_id": query_id,
135
- "phase": found_phase,
176
+ "query_id": normalized_id,
136
177
  "message": "No query plan captured for this query",
137
- "suggestion": "Run benchmark with --capture-plans flag to capture query plans",
138
- "query_info": {
139
- "runtime_ms": query_exec.get("runtime_ms"),
140
- "status": query_exec.get("status"),
141
- },
178
+ "query_info": {"runtime_ms": query_exec.get("ms"), "status": query_exec.get("status")},
142
179
  }
143
180
 
144
- # Format the query plan
181
+ query_plan = query_plan_entry.get("plan")
145
182
  response: dict[str, Any] = {
146
183
  "status": "success",
147
- "query_id": query_id,
148
- "phase": found_phase,
149
- "runtime_ms": query_exec.get("runtime_ms"),
184
+ "query_id": normalized_id,
185
+ "runtime_ms": query_exec.get("ms"),
150
186
  }
151
187
 
152
188
  if format_lower == "json":
153
189
  response["plan"] = query_plan
154
190
  elif format_lower == "summary":
155
- # Extract summary statistics from plan
156
191
  response["summary"] = _extract_plan_summary(query_plan)
157
- else: # tree
158
- # Convert to readable tree format
192
+ else:
159
193
  response["plan_tree"] = _format_plan_tree(query_plan)
160
194
 
161
195
  return response
@@ -174,192 +208,489 @@ def register_analytics_tools(mcp: FastMCP) -> None:
174
208
  details={"exception_type": type(e).__name__},
175
209
  )
176
210
 
177
- @mcp.tool(annotations=ANALYTICS_READONLY_ANNOTATIONS)
178
- def detect_regressions(
179
- platform: str | None = None,
180
- benchmark: str | None = None,
181
- threshold_percent: float = 10.0,
182
- lookback_runs: int = 5,
183
- ) -> dict[str, Any]:
184
- """Automatically detect performance regressions across recent runs.
185
211
 
186
- Compares recent benchmark runs to identify queries that have regressed.
187
- Finds the two most recent comparable runs and analyzes differences.
212
+ def _compare_results_impl(file1: str, file2: str, threshold_percent: float) -> dict[str, Any]:
213
+ """Compare two benchmark runs."""
214
+ results_dir = DEFAULT_RESULTS_DIR
215
+ exporter = ResultExporter(anonymize=False, console=get_quiet_console())
216
+
217
+ def resolve_result_path(filename: str) -> Path | None:
218
+ path = results_dir / filename
219
+ if not path.exists() and not filename.endswith(".json"):
220
+ path = results_dir / (filename + ".json")
221
+ if not path.exists():
222
+ return None
223
+ return path
224
+
225
+ path1 = resolve_result_path(file1)
226
+ path2 = resolve_result_path(file2)
227
+
228
+ if path1 is None:
229
+ return make_error(
230
+ ErrorCode.RESOURCE_NOT_FOUND,
231
+ f"Baseline file not found: {file1}",
232
+ details={"file_type": "baseline", "requested_file": file1},
233
+ )
234
+ if path2 is None:
235
+ return make_error(
236
+ ErrorCode.RESOURCE_NOT_FOUND,
237
+ f"Comparison file not found: {file2}",
238
+ details={"file_type": "comparison", "requested_file": file2},
239
+ )
240
+
241
+ comparison = exporter.compare_results(path1, path2)
242
+ if "error" in comparison:
243
+ return make_error(
244
+ ErrorCode.INTERNAL_ERROR,
245
+ comparison.get("error", "Failed to compare results"),
246
+ details={
247
+ "baseline_loaded": comparison.get("baseline_loaded"),
248
+ "current_loaded": comparison.get("current_loaded"),
249
+ },
250
+ )
251
+
252
+ regressions: list[str] = []
253
+ improvements: list[str] = []
254
+ stable: list[str] = []
255
+
256
+ for entry in comparison.get("query_comparisons", []):
257
+ change_pct = entry.get("change_percent", 0)
258
+ if change_pct > threshold_percent:
259
+ regressions.append(entry.get("query_id"))
260
+ elif change_pct < -threshold_percent:
261
+ improvements.append(entry.get("query_id"))
262
+ else:
263
+ stable.append(entry.get("query_id"))
264
+
265
+ comparison["summary"] = {
266
+ "total_queries_compared": len(comparison.get("query_comparisons", [])),
267
+ "regressions": len(regressions),
268
+ "improvements": len(improvements),
269
+ "stable": len(stable),
270
+ "threshold_percent": threshold_percent,
271
+ }
272
+ comparison["regressions"] = [q for q in regressions if q]
273
+ comparison["improvements"] = [q for q in improvements if q]
274
+
275
+ return comparison
276
+
277
+
278
+ def _detect_regressions_impl(
279
+ platform: str | None,
280
+ benchmark: str | None,
281
+ threshold_percent: float,
282
+ lookback_runs: int,
283
+ ) -> dict[str, Any]:
284
+ """Detect performance regressions across recent runs."""
285
+ results_dir = DEFAULT_RESULTS_DIR
286
+
287
+ if not results_dir.exists():
288
+ return {"status": "no_data", "message": f"No results directory found at {results_dir}", "regressions": []}
289
+
290
+ result_files = [
291
+ path
292
+ for path in results_dir.glob("*.json")
293
+ if not path.name.endswith(".plans.json") and not path.name.endswith(".tuning.json")
294
+ ]
295
+ if len(result_files) < 2:
296
+ return {
297
+ "status": "insufficient_data",
298
+ "message": f"Need at least 2 benchmark runs for comparison, found {len(result_files)}",
299
+ "regressions": [],
300
+ }
188
301
 
189
- Args:
190
- platform: Filter by platform name (optional)
191
- benchmark: Filter by benchmark name (optional)
192
- threshold_percent: Percentage change threshold for regression (default: 10%)
193
- lookback_runs: Number of recent runs to consider (default: 5)
302
+ result_files = sorted(result_files, key=lambda p: p.stat().st_mtime, reverse=True)
194
303
 
195
- Returns:
196
- Regression analysis with affected queries and recommendations.
304
+ runs: list[dict[str, Any]] = []
305
+ for file_path in result_files[: lookback_runs * 2]:
306
+ try:
307
+ with open(file_path) as f:
308
+ data = json.load(f)
197
309
 
198
- Example:
199
- detect_regressions() # Check all recent runs
200
- detect_regressions(platform="duckdb", benchmark="tpch")
201
- detect_regressions(threshold_percent=5, lookback_runs=10)
202
- """
203
- results_dir = DEFAULT_RESULTS_DIR
310
+ run_platform = data.get("platform", {}).get("name", "unknown")
311
+ benchmark_block = data.get("benchmark", {}) if isinstance(data.get("benchmark"), dict) else {}
312
+ run_benchmark = benchmark_block.get("id", "unknown")
204
313
 
205
- if not results_dir.exists():
206
- return {
207
- "status": "no_data",
208
- "message": f"No results directory found at {results_dir}",
209
- "regressions": [],
210
- }
314
+ if platform and platform.lower() not in run_platform.lower():
315
+ continue
316
+ if benchmark and benchmark.lower() not in run_benchmark.lower():
317
+ continue
211
318
 
212
- # Find recent result files
213
- result_files = list(results_dir.glob("*.json"))
214
- if len(result_files) < 2:
215
- return {
216
- "status": "insufficient_data",
217
- "message": f"Need at least 2 benchmark runs for comparison, found {len(result_files)}",
218
- "regressions": [],
219
- }
319
+ runs.append(
320
+ {
321
+ "file": file_path.name,
322
+ "path": str(file_path),
323
+ "platform": run_platform,
324
+ "benchmark": run_benchmark,
325
+ "scale_factor": benchmark_block.get("scale_factor"),
326
+ "timestamp": data.get("run", {}).get("timestamp", file_path.stat().st_mtime),
327
+ "data": data,
328
+ }
329
+ )
220
330
 
221
- # Sort by modification time (newest first)
222
- result_files = sorted(result_files, key=lambda p: p.stat().st_mtime, reverse=True)
331
+ if len(runs) >= lookback_runs:
332
+ break
223
333
 
224
- # Load and filter results
225
- runs: list[dict[str, Any]] = []
226
- for file_path in result_files[: lookback_runs * 2]: # Check extra files for filtering
227
- try:
228
- with open(file_path) as f:
229
- data = json.load(f)
334
+ except Exception as e:
335
+ logger.warning(f"Could not parse result file {file_path}: {e}")
336
+ continue
230
337
 
231
- run_platform = data.get("platform", {}).get("type", "unknown")
232
- run_benchmark = data.get("benchmark", "unknown")
338
+ if len(runs) < 2:
339
+ return {
340
+ "status": "insufficient_data",
341
+ "message": f"Need at least 2 comparable runs, found {len(runs)} matching filters",
342
+ "filters_applied": {"platform": platform, "benchmark": benchmark},
343
+ "regressions": [],
344
+ }
233
345
 
234
- # Apply filters
235
- if platform and platform.lower() not in run_platform.lower():
236
- continue
237
- if benchmark and benchmark.lower() not in run_benchmark.lower():
238
- continue
346
+ newer_run = runs[0]
347
+ older_run = runs[1]
239
348
 
240
- runs.append(
349
+ def extract_timings(run_data: dict) -> dict[str, float]:
350
+ timings: dict[str, float] = {}
351
+ for query in run_data.get("queries", []):
352
+ if query.get("run_type") != "measurement":
353
+ continue
354
+ qid = str(query.get("id", ""))
355
+ runtime = query.get("ms")
356
+ if qid and runtime is not None:
357
+ timings[qid] = float(runtime)
358
+ return timings
359
+
360
+ older_timings = extract_timings(older_run["data"])
361
+ newer_timings = extract_timings(newer_run["data"])
362
+
363
+ regressions: list[dict[str, Any]] = []
364
+ improvements: list[dict[str, Any]] = []
365
+ stable: list[str] = []
366
+
367
+ all_queries = set(older_timings.keys()) | set(newer_timings.keys())
368
+ for qid in sorted(all_queries):
369
+ old_time = older_timings.get(qid)
370
+ new_time = newer_timings.get(qid)
371
+
372
+ if old_time is not None and new_time is not None and old_time > 0:
373
+ delta_ms = new_time - old_time
374
+ delta_pct = (delta_ms / old_time) * 100
375
+
376
+ if delta_pct > threshold_percent:
377
+ regressions.append(
378
+ {
379
+ "query_id": qid,
380
+ "baseline_ms": round(old_time, 2),
381
+ "current_ms": round(new_time, 2),
382
+ "delta_ms": round(delta_ms, 2),
383
+ "delta_percent": round(delta_pct, 1),
384
+ "severity": _classify_regression_severity(delta_pct),
385
+ }
386
+ )
387
+ elif delta_pct < -threshold_percent:
388
+ improvements.append(
241
389
  {
242
- "file": file_path.name,
243
- "path": str(file_path),
244
- "platform": run_platform,
245
- "benchmark": run_benchmark,
246
- "scale_factor": data.get("scale_factor"),
247
- "timestamp": data.get("timestamp", file_path.stat().st_mtime),
248
- "data": data,
390
+ "query_id": qid,
391
+ "baseline_ms": round(old_time, 2),
392
+ "current_ms": round(new_time, 2),
393
+ "delta_ms": round(delta_ms, 2),
394
+ "delta_percent": round(delta_pct, 1),
249
395
  }
250
396
  )
397
+ else:
398
+ stable.append(qid)
399
+
400
+ regressions.sort(key=lambda r: r["delta_percent"], reverse=True)
401
+
402
+ total_old = sum(older_timings.values())
403
+ total_new = sum(newer_timings.values())
404
+ total_delta_pct = ((total_new - total_old) / total_old * 100) if total_old > 0 else 0
405
+
406
+ return {
407
+ "status": "completed",
408
+ "comparison": {
409
+ "baseline": {
410
+ "file": older_run["file"],
411
+ "platform": older_run["platform"],
412
+ "benchmark": older_run["benchmark"],
413
+ "timestamp": older_run["timestamp"],
414
+ },
415
+ "current": {
416
+ "file": newer_run["file"],
417
+ "platform": newer_run["platform"],
418
+ "benchmark": newer_run["benchmark"],
419
+ "timestamp": newer_run["timestamp"],
420
+ },
421
+ },
422
+ "summary": {
423
+ "total_queries": len(all_queries),
424
+ "regressions": len(regressions),
425
+ "improvements": len(improvements),
426
+ "stable": len(stable),
427
+ "total_runtime_delta_percent": round(total_delta_pct, 1),
428
+ "threshold_percent": threshold_percent,
429
+ },
430
+ "regressions": regressions,
431
+ "improvements": improvements[:5],
432
+ }
251
433
 
252
- if len(runs) >= lookback_runs:
253
- break
254
434
 
255
- except Exception as e:
256
- logger.warning(f"Could not parse result file {file_path}: {e}")
435
+ def _get_performance_trends_impl(
436
+ platform: str | None,
437
+ benchmark: str | None,
438
+ metric: str,
439
+ limit: int,
440
+ ) -> dict[str, Any]:
441
+ """Get performance trends over multiple benchmark runs."""
442
+ valid_metrics = ["geometric_mean", "p50", "p95", "p99", "total_time"]
443
+ metric_lower = metric.lower()
444
+ if metric_lower not in valid_metrics:
445
+ return make_error(
446
+ ErrorCode.VALIDATION_ERROR,
447
+ f"Invalid metric: {metric}",
448
+ details={"valid_metrics": valid_metrics},
449
+ )
450
+
451
+ results_dir = DEFAULT_RESULTS_DIR
452
+ if not results_dir.exists():
453
+ return {"status": "no_data", "message": f"No results directory found at {results_dir}", "trends": []}
454
+
455
+ result_files = [
456
+ path
457
+ for path in results_dir.glob("*.json")
458
+ if not path.name.endswith(".plans.json") and not path.name.endswith(".tuning.json")
459
+ ]
460
+ result_files = sorted(result_files, key=lambda p: p.stat().st_mtime, reverse=True)
461
+
462
+ runs: list[dict[str, Any]] = []
463
+ for file_path in result_files:
464
+ if len(runs) >= limit:
465
+ break
466
+
467
+ try:
468
+ with open(file_path) as f:
469
+ data = json.load(f)
470
+
471
+ run_platform = data.get("platform", {}).get("name", "unknown")
472
+ benchmark_block = data.get("benchmark", {}) if isinstance(data.get("benchmark"), dict) else {}
473
+ run_benchmark = benchmark_block.get("id", "unknown")
474
+
475
+ if platform and platform.lower() not in run_platform.lower():
476
+ continue
477
+ if benchmark and benchmark.lower() not in run_benchmark.lower():
257
478
  continue
258
479
 
259
- if len(runs) < 2:
260
- return {
261
- "status": "insufficient_data",
262
- "message": f"Need at least 2 comparable runs, found {len(runs)} matching filters",
263
- "filters_applied": {
264
- "platform": platform,
265
- "benchmark": benchmark,
266
- },
267
- "regressions": [],
268
- }
480
+ timings: list[float] = []
481
+ for query in data.get("queries", []):
482
+ if query.get("run_type") != "measurement":
483
+ continue
484
+ runtime = query.get("ms")
485
+ if runtime is not None and runtime > 0:
486
+ timings.append(float(runtime))
487
+
488
+ if not timings:
489
+ continue
490
+
491
+ metric_value = _calculate_metric(timings, metric_lower)
492
+
493
+ timestamp = data.get("run", {}).get("timestamp")
494
+ if timestamp:
495
+ try:
496
+ if isinstance(timestamp, str):
497
+ ts = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
498
+ else:
499
+ ts = datetime.fromtimestamp(timestamp)
500
+ timestamp_str = ts.isoformat()
501
+ except Exception:
502
+ timestamp_str = str(timestamp)
503
+ else:
504
+ timestamp_str = datetime.fromtimestamp(file_path.stat().st_mtime).isoformat()
505
+
506
+ runs.append(
507
+ {
508
+ "file": file_path.name,
509
+ "platform": run_platform,
510
+ "benchmark": run_benchmark,
511
+ "scale_factor": benchmark_block.get("scale_factor"),
512
+ "timestamp": timestamp_str,
513
+ "query_count": len(timings),
514
+ "metric": metric_lower,
515
+ "value": round(metric_value, 2),
516
+ }
517
+ )
518
+
519
+ except Exception as e:
520
+ logger.warning(f"Could not parse result file {file_path}: {e}")
521
+ continue
522
+
523
+ if not runs:
524
+ return {
525
+ "status": "no_matching_data",
526
+ "message": "No benchmark runs match the specified filters",
527
+ "filters_applied": {"platform": platform, "benchmark": benchmark},
528
+ "trends": [],
529
+ }
530
+
531
+ runs.reverse()
532
+
533
+ if len(runs) >= 2:
534
+ first_value = runs[0]["value"]
535
+ last_value = runs[-1]["value"]
536
+ if first_value > 0:
537
+ trend_pct = ((last_value - first_value) / first_value) * 100
538
+ if trend_pct < -5:
539
+ trend_direction = "improving"
540
+ elif trend_pct > 5:
541
+ trend_direction = "degrading"
542
+ else:
543
+ trend_direction = "stable"
544
+ else:
545
+ trend_direction = "unknown"
546
+ trend_pct = 0
547
+ else:
548
+ trend_direction = "insufficient_data"
549
+ trend_pct = 0
550
+
551
+ return {
552
+ "status": "success",
553
+ "metric": metric_lower,
554
+ "filters_applied": {"platform": platform, "benchmark": benchmark, "limit": limit},
555
+ "summary": {
556
+ "run_count": len(runs),
557
+ "first_run": runs[0]["timestamp"] if runs else None,
558
+ "last_run": runs[-1]["timestamp"] if runs else None,
559
+ "trend_direction": trend_direction,
560
+ "trend_percent": round(trend_pct, 1),
561
+ },
562
+ "data_points": runs,
563
+ }
564
+
565
+
566
+ def _aggregate_results_impl(
567
+ platform: str | None,
568
+ benchmark: str | None,
569
+ group_by: str,
570
+ ) -> dict[str, Any]:
571
+ """Aggregate multiple benchmark results into summary statistics."""
572
+ valid_group_by = ["platform", "benchmark", "date"]
573
+ group_by_lower = group_by.lower()
574
+ if group_by_lower not in valid_group_by:
575
+ return make_error(
576
+ ErrorCode.VALIDATION_ERROR,
577
+ f"Invalid group_by: {group_by}",
578
+ details={"valid_options": valid_group_by},
579
+ )
580
+
581
+ results_dir = DEFAULT_RESULTS_DIR
582
+ if not results_dir.exists():
583
+ return {"status": "no_data", "message": f"No results directory found at {results_dir}", "aggregates": {}}
584
+
585
+ result_files = [
586
+ path
587
+ for path in results_dir.glob("*.json")
588
+ if not path.name.endswith(".plans.json") and not path.name.endswith(".tuning.json")
589
+ ]
590
+
591
+ groups: dict[str, list[dict[str, Any]]] = {}
592
+
593
+ for file_path in result_files:
594
+ try:
595
+ with open(file_path) as f:
596
+ data = json.load(f)
269
597
 
270
- # Compare the two most recent runs
271
- newer_run = runs[0]
272
- older_run = runs[1]
273
-
274
- # Extract query timings
275
- def extract_timings(run_data: dict) -> dict[str, float]:
276
- timings = {}
277
- for phase_data in run_data.get("phases", {}).values():
278
- for query in phase_data.get("queries", []):
279
- qid = str(query.get("query_id", ""))
280
- runtime = query.get("runtime_ms")
281
- if qid and runtime is not None:
282
- timings[qid] = float(runtime)
283
- return timings
284
-
285
- older_timings = extract_timings(older_run["data"])
286
- newer_timings = extract_timings(newer_run["data"])
287
-
288
- # Detect regressions
289
- regressions: list[dict[str, Any]] = []
290
- improvements: list[dict[str, Any]] = []
291
- stable: list[str] = []
292
-
293
- all_queries = set(older_timings.keys()) | set(newer_timings.keys())
294
- for qid in sorted(all_queries):
295
- old_time = older_timings.get(qid)
296
- new_time = newer_timings.get(qid)
297
-
298
- if old_time is not None and new_time is not None and old_time > 0:
299
- delta_ms = new_time - old_time
300
- delta_pct = (delta_ms / old_time) * 100
301
-
302
- if delta_pct > threshold_percent:
303
- regressions.append(
304
- {
305
- "query_id": qid,
306
- "baseline_ms": round(old_time, 2),
307
- "current_ms": round(new_time, 2),
308
- "delta_ms": round(delta_ms, 2),
309
- "delta_percent": round(delta_pct, 1),
310
- "severity": _classify_regression_severity(delta_pct),
311
- }
312
- )
313
- elif delta_pct < -threshold_percent:
314
- improvements.append(
315
- {
316
- "query_id": qid,
317
- "baseline_ms": round(old_time, 2),
318
- "current_ms": round(new_time, 2),
319
- "delta_ms": round(delta_ms, 2),
320
- "delta_percent": round(delta_pct, 1),
321
- }
322
- )
598
+ run_platform = data.get("platform", {}).get("name", "unknown")
599
+ benchmark_block = data.get("benchmark", {}) if isinstance(data.get("benchmark"), dict) else {}
600
+ run_benchmark = benchmark_block.get("id", "unknown")
601
+
602
+ if platform and platform.lower() not in run_platform.lower():
603
+ continue
604
+ if benchmark and benchmark.lower() not in run_benchmark.lower():
605
+ continue
606
+
607
+ if group_by_lower == "platform":
608
+ group_key = run_platform
609
+ elif group_by_lower == "benchmark":
610
+ group_key = run_benchmark
611
+ else:
612
+ timestamp = data.get("run", {}).get("timestamp", file_path.stat().st_mtime)
613
+ if isinstance(timestamp, str):
614
+ try:
615
+ ts = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
616
+ group_key = ts.strftime("%Y-%m-%d")
617
+ except Exception:
618
+ group_key = timestamp[:10] if len(timestamp) >= 10 else "unknown"
323
619
  else:
324
- stable.append(qid)
620
+ group_key = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d")
325
621
 
326
- # Sort regressions by severity
327
- regressions.sort(key=lambda r: r["delta_percent"], reverse=True)
622
+ timings: list[float] = []
623
+ for query in data.get("queries", []):
624
+ if query.get("run_type") != "measurement":
625
+ continue
626
+ runtime = query.get("ms")
627
+ if runtime is not None and runtime > 0:
628
+ timings.append(float(runtime))
328
629
 
329
- # Calculate total runtime delta
330
- total_old = sum(older_timings.values())
331
- total_new = sum(newer_timings.values())
332
- total_delta_pct = ((total_new - total_old) / total_old * 100) if total_old > 0 else 0
630
+ if not timings:
631
+ continue
632
+
633
+ if group_key not in groups:
634
+ groups[group_key] = []
635
+
636
+ groups[group_key].append(
637
+ {
638
+ "file": file_path.name,
639
+ "timings": timings,
640
+ "total_time": sum(timings),
641
+ "query_count": len(timings),
642
+ "scale_factor": benchmark_block.get("scale_factor"),
643
+ }
644
+ )
645
+
646
+ except Exception as e:
647
+ logger.warning(f"Could not parse result file {file_path}: {e}")
648
+ continue
333
649
 
650
+ if not groups:
334
651
  return {
335
- "status": "completed",
336
- "comparison": {
337
- "baseline": {
338
- "file": older_run["file"],
339
- "platform": older_run["platform"],
340
- "benchmark": older_run["benchmark"],
341
- "timestamp": older_run["timestamp"],
342
- },
343
- "current": {
344
- "file": newer_run["file"],
345
- "platform": newer_run["platform"],
346
- "benchmark": newer_run["benchmark"],
347
- "timestamp": newer_run["timestamp"],
348
- },
652
+ "status": "no_matching_data",
653
+ "message": "No benchmark runs match the specified filters",
654
+ "filters_applied": {"platform": platform, "benchmark": benchmark},
655
+ "aggregates": {},
656
+ }
657
+
658
+ aggregates: dict[str, dict[str, Any]] = {}
659
+ for group_key, runs in sorted(groups.items()):
660
+ all_timings = [t for run in runs for t in run["timings"]]
661
+ total_times = [run["total_time"] for run in runs]
662
+
663
+ aggregates[group_key] = {
664
+ "run_count": len(runs),
665
+ "total_queries": len(all_timings),
666
+ "query_stats": {
667
+ "mean_ms": round(sum(all_timings) / len(all_timings), 2) if all_timings else 0,
668
+ "std_ms": round(_std_dev(all_timings), 2) if len(all_timings) > 1 else 0,
669
+ "min_ms": round(min(all_timings), 2) if all_timings else 0,
670
+ "max_ms": round(max(all_timings), 2) if all_timings else 0,
671
+ "p50_ms": round(_percentile(all_timings, 50), 2) if all_timings else 0,
672
+ "p95_ms": round(_percentile(all_timings, 95), 2) if all_timings else 0,
349
673
  },
350
- "summary": {
351
- "total_queries": len(all_queries),
352
- "regressions": len(regressions),
353
- "improvements": len(improvements),
354
- "stable": len(stable),
355
- "total_runtime_delta_percent": round(total_delta_pct, 1),
356
- "threshold_percent": threshold_percent,
674
+ "run_stats": {
675
+ "mean_total_ms": round(sum(total_times) / len(total_times), 2) if total_times else 0,
676
+ "std_total_ms": round(_std_dev(total_times), 2) if len(total_times) > 1 else 0,
677
+ "min_total_ms": round(min(total_times), 2) if total_times else 0,
678
+ "max_total_ms": round(max(total_times), 2) if total_times else 0,
357
679
  },
358
- "regressions": regressions,
359
- "improvements": improvements[:5], # Top 5 improvements
360
- "recommendations": _generate_regression_recommendations(regressions, threshold_percent),
680
+ "files": [run["file"] for run in runs],
361
681
  }
362
682
 
683
+ return {
684
+ "status": "success",
685
+ "group_by": group_by_lower,
686
+ "filters_applied": {"platform": platform, "benchmark": benchmark},
687
+ "summary": {
688
+ "total_groups": len(aggregates),
689
+ "total_runs": sum(a["run_count"] for a in aggregates.values()),
690
+ },
691
+ "aggregates": aggregates,
692
+ }
693
+
363
694
 
364
695
  def _extract_plan_summary(plan: dict) -> dict[str, Any]:
365
696
  """Extract summary statistics from a query plan."""
@@ -404,12 +735,10 @@ def _format_plan_tree(plan: dict, indent: int = 0) -> str:
404
735
  op_type = plan.get("type") or plan.get("operator") or plan.get("name") or "Node"
405
736
  lines.append(f"{prefix}├── {op_type}")
406
737
 
407
- # Add key properties
408
738
  for key in ["table", "alias", "condition", "rows", "cost"]:
409
739
  if key in plan:
410
740
  lines.append(f"{prefix}│ {key}: {plan[key]}")
411
741
 
412
- # Recurse into children
413
742
  children = plan.get("children") or plan.get("inputs") or plan.get("plans") or []
414
743
  if isinstance(children, list):
415
744
  for child in children:
@@ -432,371 +761,12 @@ def _classify_regression_severity(delta_pct: float) -> str:
432
761
  return "low"
433
762
 
434
763
 
435
- def _generate_regression_recommendations(regressions: list[dict], threshold: float) -> list[str]:
436
- """Generate recommendations based on detected regressions."""
437
- recommendations = []
438
-
439
- if not regressions:
440
- recommendations.append("No regressions detected above threshold - performance is stable")
441
- return recommendations
442
-
443
- critical = [r for r in regressions if r["severity"] == "critical"]
444
- high = [r for r in regressions if r["severity"] == "high"]
445
-
446
- if critical:
447
- recommendations.append(f"CRITICAL: {len(critical)} queries regressed >100% - investigate immediately")
448
- recommendations.append(f"Most affected: {', '.join(r['query_id'] for r in critical[:3])}")
449
-
450
- if high:
451
- recommendations.append(f"HIGH: {len(high)} queries regressed 50-100% - review query plans")
452
-
453
- if len(regressions) > 5:
454
- recommendations.append("Multiple regressions detected - consider reviewing recent changes")
455
-
456
- recommendations.append("Use get_query_plan() to analyze specific query execution plans")
457
- recommendations.append("Compare results with compare_results() for detailed query-level analysis")
458
-
459
- return recommendations
460
-
461
-
462
- def register_historical_tools(mcp: FastMCP) -> None:
463
- """Register historical analysis tools with the MCP server.
464
-
465
- Args:
466
- mcp: The FastMCP server instance to register tools with.
467
- """
468
- from datetime import datetime
469
-
470
- @mcp.tool(annotations=ANALYTICS_READONLY_ANNOTATIONS)
471
- def get_performance_trends(
472
- platform: str | None = None,
473
- benchmark: str | None = None,
474
- metric: str = "geometric_mean",
475
- limit: int = 10,
476
- ) -> dict[str, Any]:
477
- """Get performance trends over multiple benchmark runs.
478
-
479
- Analyzes historical benchmark results to show performance trends over time.
480
- Useful for tracking improvements or regressions across releases.
481
-
482
- Args:
483
- platform: Filter by platform name (optional)
484
- benchmark: Filter by benchmark name (optional)
485
- metric: Performance metric ('geometric_mean', 'p50', 'p95', 'p99', 'total_time')
486
- limit: Maximum number of runs to analyze (default: 10)
487
-
488
- Returns:
489
- Time-series performance data for trend analysis.
490
-
491
- Example:
492
- get_performance_trends(platform="duckdb", benchmark="tpch")
493
- get_performance_trends(metric="p95", limit=20)
494
- """
495
- # Validate metric
496
- valid_metrics = ["geometric_mean", "p50", "p95", "p99", "total_time"]
497
- metric_lower = metric.lower()
498
- if metric_lower not in valid_metrics:
499
- return make_error(
500
- ErrorCode.VALIDATION_ERROR,
501
- f"Invalid metric: {metric}",
502
- details={"valid_metrics": valid_metrics},
503
- suggestion=f"Use one of: {', '.join(valid_metrics)}",
504
- )
505
-
506
- results_dir = DEFAULT_RESULTS_DIR
507
- if not results_dir.exists():
508
- return {
509
- "status": "no_data",
510
- "message": f"No results directory found at {results_dir}",
511
- "trends": [],
512
- }
513
-
514
- # Find and load result files
515
- result_files = list(results_dir.glob("*.json"))
516
- result_files = sorted(result_files, key=lambda p: p.stat().st_mtime, reverse=True)
517
-
518
- runs: list[dict[str, Any]] = []
519
- for file_path in result_files:
520
- if len(runs) >= limit:
521
- break
522
-
523
- try:
524
- with open(file_path) as f:
525
- data = json.load(f)
526
-
527
- run_platform = data.get("platform", {}).get("type", "unknown")
528
- run_benchmark = data.get("benchmark", "unknown")
529
-
530
- # Apply filters
531
- if platform and platform.lower() not in run_platform.lower():
532
- continue
533
- if benchmark and benchmark.lower() not in run_benchmark.lower():
534
- continue
535
-
536
- # Extract query timings
537
- timings: list[float] = []
538
- for phase_data in data.get("phases", {}).values():
539
- for query in phase_data.get("queries", []):
540
- runtime = query.get("runtime_ms")
541
- if runtime is not None and runtime > 0:
542
- timings.append(float(runtime))
543
-
544
- if not timings:
545
- continue
546
-
547
- # Calculate requested metric
548
- metric_value = _calculate_metric(timings, metric_lower)
549
-
550
- # Parse timestamp
551
- timestamp = data.get("timestamp")
552
- if timestamp:
553
- try:
554
- if isinstance(timestamp, str):
555
- ts = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
556
- else:
557
- ts = datetime.fromtimestamp(timestamp)
558
- timestamp_str = ts.isoformat()
559
- except Exception:
560
- timestamp_str = str(timestamp)
561
- else:
562
- timestamp_str = datetime.fromtimestamp(file_path.stat().st_mtime).isoformat()
563
-
564
- runs.append(
565
- {
566
- "file": file_path.name,
567
- "platform": run_platform,
568
- "benchmark": run_benchmark,
569
- "scale_factor": data.get("scale_factor"),
570
- "timestamp": timestamp_str,
571
- "query_count": len(timings),
572
- "metric": metric_lower,
573
- "value": round(metric_value, 2),
574
- }
575
- )
576
-
577
- except Exception as e:
578
- logger.warning(f"Could not parse result file {file_path}: {e}")
579
- continue
580
-
581
- if not runs:
582
- return {
583
- "status": "no_matching_data",
584
- "message": "No benchmark runs match the specified filters",
585
- "filters_applied": {
586
- "platform": platform,
587
- "benchmark": benchmark,
588
- },
589
- "trends": [],
590
- }
591
-
592
- # Reverse to show oldest first (chronological order)
593
- runs.reverse()
594
-
595
- # Calculate trend direction
596
- if len(runs) >= 2:
597
- first_value = runs[0]["value"]
598
- last_value = runs[-1]["value"]
599
- if first_value > 0:
600
- trend_pct = ((last_value - first_value) / first_value) * 100
601
- if trend_pct < -5:
602
- trend_direction = "improving"
603
- elif trend_pct > 5:
604
- trend_direction = "degrading"
605
- else:
606
- trend_direction = "stable"
607
- else:
608
- trend_direction = "unknown"
609
- trend_pct = 0
610
- else:
611
- trend_direction = "insufficient_data"
612
- trend_pct = 0
613
-
614
- return {
615
- "status": "success",
616
- "metric": metric_lower,
617
- "filters_applied": {
618
- "platform": platform,
619
- "benchmark": benchmark,
620
- "limit": limit,
621
- },
622
- "summary": {
623
- "run_count": len(runs),
624
- "first_run": runs[0]["timestamp"] if runs else None,
625
- "last_run": runs[-1]["timestamp"] if runs else None,
626
- "trend_direction": trend_direction,
627
- "trend_percent": round(trend_pct, 1),
628
- },
629
- "data_points": runs,
630
- }
631
-
632
- @mcp.tool(annotations=ANALYTICS_READONLY_ANNOTATIONS)
633
- def aggregate_results(
634
- platform: str | None = None,
635
- benchmark: str | None = None,
636
- group_by: str = "platform",
637
- ) -> dict[str, Any]:
638
- """Aggregate multiple benchmark results into summary statistics.
639
-
640
- Groups benchmark results by platform, benchmark, or date and calculates
641
- statistical summaries including mean, standard deviation, min, and max.
642
-
643
- Args:
644
- platform: Filter by platform name (optional)
645
- benchmark: Filter by benchmark name (optional)
646
- group_by: Grouping dimension ('platform', 'benchmark', or 'date')
647
-
648
- Returns:
649
- Statistical summaries grouped by the specified dimension.
650
-
651
- Example:
652
- aggregate_results() # Group by platform
653
- aggregate_results(group_by="benchmark")
654
- aggregate_results(platform="duckdb", group_by="date")
655
- """
656
- # Validate group_by
657
- valid_group_by = ["platform", "benchmark", "date"]
658
- group_by_lower = group_by.lower()
659
- if group_by_lower not in valid_group_by:
660
- return make_error(
661
- ErrorCode.VALIDATION_ERROR,
662
- f"Invalid group_by: {group_by}",
663
- details={"valid_options": valid_group_by},
664
- suggestion=f"Use one of: {', '.join(valid_group_by)}",
665
- )
666
-
667
- results_dir = DEFAULT_RESULTS_DIR
668
- if not results_dir.exists():
669
- return {
670
- "status": "no_data",
671
- "message": f"No results directory found at {results_dir}",
672
- "aggregates": {},
673
- }
674
-
675
- # Find and load result files
676
- result_files = list(results_dir.glob("*.json"))
677
-
678
- # Group data
679
- groups: dict[str, list[dict[str, Any]]] = {}
680
-
681
- for file_path in result_files:
682
- try:
683
- with open(file_path) as f:
684
- data = json.load(f)
685
-
686
- run_platform = data.get("platform", {}).get("type", "unknown")
687
- run_benchmark = data.get("benchmark", "unknown")
688
-
689
- # Apply filters
690
- if platform and platform.lower() not in run_platform.lower():
691
- continue
692
- if benchmark and benchmark.lower() not in run_benchmark.lower():
693
- continue
694
-
695
- # Determine group key
696
- if group_by_lower == "platform":
697
- group_key = run_platform
698
- elif group_by_lower == "benchmark":
699
- group_key = run_benchmark
700
- else: # date
701
- timestamp = data.get("timestamp", file_path.stat().st_mtime)
702
- if isinstance(timestamp, str):
703
- try:
704
- ts = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
705
- group_key = ts.strftime("%Y-%m-%d")
706
- except Exception:
707
- group_key = timestamp[:10] if len(timestamp) >= 10 else "unknown"
708
- else:
709
- group_key = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d")
710
-
711
- # Extract performance data
712
- timings: list[float] = []
713
- for phase_data in data.get("phases", {}).values():
714
- for query in phase_data.get("queries", []):
715
- runtime = query.get("runtime_ms")
716
- if runtime is not None and runtime > 0:
717
- timings.append(float(runtime))
718
-
719
- if not timings:
720
- continue
721
-
722
- if group_key not in groups:
723
- groups[group_key] = []
724
-
725
- groups[group_key].append(
726
- {
727
- "file": file_path.name,
728
- "timings": timings,
729
- "total_time": sum(timings),
730
- "query_count": len(timings),
731
- "scale_factor": data.get("scale_factor"),
732
- }
733
- )
734
-
735
- except Exception as e:
736
- logger.warning(f"Could not parse result file {file_path}: {e}")
737
- continue
738
-
739
- if not groups:
740
- return {
741
- "status": "no_matching_data",
742
- "message": "No benchmark runs match the specified filters",
743
- "filters_applied": {
744
- "platform": platform,
745
- "benchmark": benchmark,
746
- },
747
- "aggregates": {},
748
- }
749
-
750
- # Calculate aggregates for each group
751
- aggregates: dict[str, dict[str, Any]] = {}
752
- for group_key, runs in sorted(groups.items()):
753
- all_timings = [t for run in runs for t in run["timings"]]
754
- total_times = [run["total_time"] for run in runs]
755
-
756
- aggregates[group_key] = {
757
- "run_count": len(runs),
758
- "total_queries": len(all_timings),
759
- "query_stats": {
760
- "mean_ms": round(sum(all_timings) / len(all_timings), 2) if all_timings else 0,
761
- "std_ms": round(_std_dev(all_timings), 2) if len(all_timings) > 1 else 0,
762
- "min_ms": round(min(all_timings), 2) if all_timings else 0,
763
- "max_ms": round(max(all_timings), 2) if all_timings else 0,
764
- "p50_ms": round(_percentile(all_timings, 50), 2) if all_timings else 0,
765
- "p95_ms": round(_percentile(all_timings, 95), 2) if all_timings else 0,
766
- },
767
- "run_stats": {
768
- "mean_total_ms": round(sum(total_times) / len(total_times), 2) if total_times else 0,
769
- "std_total_ms": round(_std_dev(total_times), 2) if len(total_times) > 1 else 0,
770
- "min_total_ms": round(min(total_times), 2) if total_times else 0,
771
- "max_total_ms": round(max(total_times), 2) if total_times else 0,
772
- },
773
- "files": [run["file"] for run in runs],
774
- }
775
-
776
- return {
777
- "status": "success",
778
- "group_by": group_by_lower,
779
- "filters_applied": {
780
- "platform": platform,
781
- "benchmark": benchmark,
782
- },
783
- "summary": {
784
- "total_groups": len(aggregates),
785
- "total_runs": sum(a["run_count"] for a in aggregates.values()),
786
- },
787
- "aggregates": aggregates,
788
- }
789
-
790
-
791
764
  def _calculate_metric(timings: list[float], metric: str) -> float:
792
765
  """Calculate the specified performance metric from query timings."""
793
- import math
794
-
795
766
  if not timings:
796
767
  return 0
797
768
 
798
769
  if metric == "geometric_mean":
799
- # Geometric mean for performance data
800
770
  log_sum = sum(math.log(t) for t in timings if t > 0)
801
771
  return math.exp(log_sum / len(timings)) if timings else 0
802
772
  elif metric == "p50":
@@ -808,7 +778,7 @@ def _calculate_metric(timings: list[float], metric: str) -> float:
808
778
  elif metric == "total_time":
809
779
  return sum(timings)
810
780
  else:
811
- return sum(timings) / len(timings) # Default to mean
781
+ return sum(timings) / len(timings)
812
782
 
813
783
 
814
784
  def _percentile(data: list[float], p: float) -> float:
@@ -826,8 +796,6 @@ def _percentile(data: list[float], p: float) -> float:
826
796
 
827
797
  def _std_dev(data: list[float]) -> float:
828
798
  """Calculate standard deviation."""
829
- import math
830
-
831
799
  if len(data) < 2:
832
800
  return 0
833
801
  mean = sum(data) / len(data)