Skip to content

Commit 035ee42

Browse files
claudeantarr
authored andcommitted
PG UX polish: dialect-aware AI prompts, button visibility, label cleanup
Four issues surfaced in actual PG dashboard use: 1. EXPLAIN false-positive on Rails query annotations SQL like `SELECT COUNT(*) FROM "taggings" /*action='table_sizes', ...*/` was rejected as "truncated" because the closing `*/` ends in `/` and tripped the trailing-operator check. looks_complete? now strips block comments before inspecting the trailing token. 2. AI assistant generates MySQL backticks on a PG database `Suggestion`, `RewriteQuery`, `Optimization`, `IndexAdvisor`, `IndexPlanner`, `MigrationRisk`, `SchemaReview`, `WorkloadDigest`, and `PatternGrouper` all hardcoded "MySQL" in their system prompts; Suggestion also told the model to "use backticks for table and column names." On PG this produced unparseable SQL. New Ai::DialectHints module exposes name_for(conn) and identifier_quoting_rule(conn). Every prompt now interpolates the dialect name; Suggestion's quoting rule swaps to double quotes on PG. IndexPlanner's prompt also specifies dialect-appropriate DROP INDEX syntax. 3. MySQL-only AI buttons visible on PG dashboard "Why is it slow?", "Anomaly Detection", "Variable Review", "Connection Advisor", "InnoDB Health" all require MySQL-only data sources. The buttons were rendered, clicking them returned a friendly "MySQL/MariaDB-only" error — but the noise was the user experience. capability?(:mysql_only_ai) now returns false on PG, and the Server tab gates those five buttons on it. The controller- side friendly-error guard stays as a defensive backstop. 4. Misleading server labels on PG - "InnoDB Buffer Pool" card → renamed "Buffer Cache" (works for both InnoDB and shared_buffers). - PG ServerOverview was reporting tmp_disk_pct = 100% whenever temp_files > 0, flagging a red badge on every dashboard. PG's temp_files is a single count with no in-memory denominator, so it now reports 0% and shows N / N for the count. - Was mapping xact_rollback to "Aborted Clients" which is a different concept; PG's connections block now reports 0 for aborted_clients/aborted_connects until a proper PG-side mapping exists. https://claude.ai/code/session_01Xy96nK3Ron2NqukBiSgtzE
1 parent 0dd2625 commit 035ee42

18 files changed

Lines changed: 164 additions & 33 deletions

app/controllers/concerns/mysql_genius/shared_view_helpers.rb

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,32 @@ def render_partial(name)
4545
view_context.render(partial: "mysql_genius/queries/#{name}")
4646
end
4747

48-
# Capability flag for shared templates. The Rails adapter always
49-
# reports every capability as present because it owns all routes
50-
# (including the Redis-backed slow_queries / anomaly_detection /
51-
# root_cause features).
52-
def capability?(_name)
53-
true
48+
# Capability flag for shared templates. Used to hide AI feature buttons
49+
# whose underlying service has no equivalent on the connected dialect
50+
# (e.g. InnoDB Health, Variable Review, Connection Advisor, Root Cause
51+
# Analysis, and Anomaly Detection all read MySQL-specific server state
52+
# via SHOW commands / performance_schema).
53+
#
54+
# All other capabilities default to true — the Rails adapter owns every
55+
# route, including Redis-backed slow_queries.
56+
def capability?(name)
57+
case name
58+
when :mysql_only_ai
59+
!connected_to_postgresql?
60+
else
61+
true
62+
end
63+
end
64+
65+
private
66+
67+
def connected_to_postgresql?
68+
MysqlGenius::Core::Connection::ActiveRecordAdapter
69+
.new(ActiveRecord::Base.connection)
70+
.server_version
71+
.postgresql?
72+
rescue StandardError
73+
false
5474
end
5575
end
5676
end

lib/mysql_genius/core.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def views_path
4242
require "mysql_genius/core/connection/fake_adapter"
4343
require "mysql_genius/core/ai/config"
4444
require "mysql_genius/core/ai/client"
45+
require "mysql_genius/core/ai/dialect_hints"
4546
require "mysql_genius/core/ai/suggestion"
4647
require "mysql_genius/core/ai/optimization"
4748
require "mysql_genius/core/ai/schema_context_builder"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
module MysqlGenius
4+
module Core
5+
module Ai
6+
# Snippets injected into AI system prompts so the model generates SQL in
7+
# the right dialect. Without these, prompts hardcode "MySQL" and tell
8+
# the model to use backticks — which produces broken SQL on PostgreSQL
9+
# (PG uses double quotes for identifiers and has no backtick syntax).
10+
module DialectHints
11+
extend self
12+
13+
# Display name suitable for "You are a SQL assistant for a #{name_for}
14+
# database." prompts.
15+
def name_for(connection)
16+
case connection.server_version.dialect
17+
when :postgresql then "PostgreSQL"
18+
else "MySQL/MariaDB"
19+
end
20+
end
21+
22+
# Identifier-quoting rule string for inclusion in a numbered Rules
23+
# list in a prompt. PG uses double quotes; MySQL/MariaDB uses
24+
# backticks.
25+
def identifier_quoting_rule(connection)
26+
if connection.server_version.postgresql?
27+
%(Use double quotes ("col_name") for case-sensitive identifiers; otherwise leave them bare.)
28+
else
29+
"Use backticks (`col_name`) for table and column names."
30+
end
31+
end
32+
end
33+
end
34+
end
35+
end

lib/mysql_genius/core/ai/index_advisor.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def call(sql, explain_rows)
2626

2727
def system_prompt
2828
<<~PROMPT
29-
You are a MySQL index advisor. Given a query, its EXPLAIN output, and current index/cardinality information, suggest optimal indexes. Consider:
29+
You are a #{DialectHints.name_for(@connection)} index advisor. Given a query, its EXPLAIN output, and current index/cardinality information, suggest optimal indexes. Consider:
3030
- Composite index column ordering (most selective first, or matching query order)
3131
- Covering indexes to avoid table lookups
3232
- Partial indexes for long string columns

lib/mysql_genius/core/ai/index_planner.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ def user_prompt(schema, unused, duplicates, index_map)
7575

7676
def system_prompt
7777
<<~PROMPT
78-
You are a MySQL index consolidation planner. Given schema information, unused indexes, duplicate indexes, and current index listings, produce a consolidated optimization plan. For each recommendation:
79-
- DROP redundant or unused indexes (with exact ALTER TABLE ... DROP INDEX statements)
78+
You are a #{DialectHints.name_for(@connection)} index consolidation planner. Given schema information, unused indexes, duplicate indexes, and current index listings, produce a consolidated optimization plan. For each recommendation:
79+
- DROP redundant or unused indexes using #{DialectHints.name_for(@connection)} syntax (e.g. `ALTER TABLE t DROP INDEX i;` on MySQL/MariaDB, `DROP INDEX "i";` on PostgreSQL)
8080
- MERGE overlapping indexes into composites where beneficial
8181
- KEEP indexes that are actively used and well-structured
8282
- ADD new composite indexes where query patterns suggest benefit
8383
- Provide rationale for each change and estimated impact on read/write performance
8484
#{@config.domain_context}
85-
Respond with JSON: {"plan": "markdown with specific ALTER TABLE / DROP INDEX / CREATE INDEX statements, rationale for each change, and estimated impact"}
85+
Respond with JSON: {"plan": "markdown with dialect-appropriate DROP INDEX / CREATE INDEX statements, rationale for each change, and estimated impact"}
8686
PROMPT
8787
end
8888
end

lib/mysql_genius/core/ai/migration_risk.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def extract_table_names(migration_sql)
3333

3434
def system_prompt
3535
<<~PROMPT
36-
You are a MySQL migration risk assessor. Given a Rails migration or DDL, evaluate:
36+
You are a #{DialectHints.name_for(@connection)} migration risk assessor. Given a Rails migration or DDL, evaluate:
3737
1. Will this lock the table? For how long given the row count?
3838
2. Is this safe to run during traffic, or does it need a maintenance window?
3939
3. Should pt-online-schema-change or gh-ost be used instead?

lib/mysql_genius/core/ai/optimization.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def call(sql, explain_rows, allowed_tables)
3636

3737
def system_prompt(schema_description)
3838
<<~PROMPT
39-
You are a MySQL query optimization expert. Given a SQL query and its EXPLAIN output, analyze the query execution plan and provide actionable optimization suggestions.
39+
You are a #{DialectHints.name_for(@connection)} query optimization expert. Given a SQL query and its EXPLAIN output, analyze the query execution plan and provide actionable optimization suggestions.
4040
4141
Available schema:
4242
#{schema_description}

lib/mysql_genius/core/ai/pattern_grouper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def extract_tables(stats)
5050

5151
def system_prompt
5252
prompt = <<~PROMPT
53-
You are a MySQL performance analyst specializing in root-cause analysis.
53+
You are a #{DialectHints.name_for(@connection)} performance analyst specializing in root-cause analysis.
5454
PROMPT
5555

5656
if @config.domain_context && !@config.domain_context.empty?

lib/mysql_genius/core/ai/rewrite_query.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def call(sql)
2727

2828
def system_prompt(schema)
2929
<<~PROMPT
30-
You are a MySQL query rewrite expert. Analyze the SQL for anti-patterns and suggest a rewritten version. Look for:
30+
You are a #{DialectHints.name_for(@connection)} query rewrite expert. Analyze the SQL for anti-patterns and suggest a rewritten version. Look for:
3131
- SELECT * when specific columns would suffice
3232
- Correlated subqueries that could be JOINs
3333
- OR conditions preventing index use (suggest UNION ALL)

lib/mysql_genius/core/ai/schema_review.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def call(table)
2727

2828
def system_prompt
2929
<<~PROMPT
30-
You are a MySQL schema reviewer. Analyze the following schema and identify anti-patterns and improvement opportunities. Look for:
30+
You are a #{DialectHints.name_for(@connection)} schema reviewer. Analyze the following schema and identify anti-patterns and improvement opportunities. Look for:
3131
- Inappropriate column types (VARCHAR(255) for short values, TEXT where VARCHAR suffices, INT for booleans)
3232
- Missing indexes on foreign key columns or frequently filtered columns
3333
- Missing NOT NULL constraints where NULLs are unlikely

0 commit comments

Comments
 (0)