From c126c15eadc4c7482ff5cfcd8703e14765e7fa4c Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Wed, 20 May 2026 20:30:20 -0500 Subject: [PATCH] fix(query-runner): dialecto SQL correcto por tipo de BD en helpers DBA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Detecta isPostgres desde tipo_db.nombre al cambiar conexión - sqlHelpers: getter dinámico — chips distintos para PostgreSQL vs MySQL PostgreSQL: pg_database, information_schema, pg_stat_activity, pg_indexes MySQL: SHOW DATABASES/TABLES/USERS/PROCESSLIST/CREATE TABLE - generateDbHelper: genera SQL correcto por dialecto PostgreSQL: sin backticks, sin charset, sin @host, DO$$ para CREATE USER IF NOT EXISTS, GRANT ALL ON DATABASE + SCHEMA + DEFAULT PRIVILEGES MySQL: backticks, utf8mb4, 'user'@'host', FLUSH PRIVILEGES - Badge PostgreSQL/MySQL en header del generador DBA - Campo Host oculto en conexiones PostgreSQL Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- resources/views/query_runner.html | 100 +++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/resources/views/query_runner.html b/resources/views/query_runner.html index 5ed0631..42f7184 100644 --- a/resources/views/query_runner.html +++ b/resources/views/query_runner.html @@ -192,6 +192,8 @@ Generador DBA + PostgreSQL + MySQL CREATE · GRANT · DROP · Setup
@@ -224,7 +226,7 @@ class="w-full border rounded px-2 py-1 font-mono focus:outline-none focus:ring-1 focus:ring-[#8eb02f]" placeholder="usuario_app">
-
+
{ testOk: true, toast: { show: false, msg: '', type: 'ok' }, isMongo: false, + isPostgres: false, selectedCollection: '', collectionFields: [], loadingFields: false, @@ -450,16 +453,29 @@ document.addEventListener('alpine:init', () => { // SQL DBA helpers showDbHelper: false, dbHelper: { db: '', user: '', pass: '', host: '%', op: 'full_setup' }, - sqlHelpers: [ - { label: 'SHOW DATABASES', cmd: 'SHOW DATABASES;' }, - { label: 'SHOW TABLES', cmd: 'SHOW TABLES;' }, - { label: 'SHOW USERS', cmd: "SELECT User, Host, plugin FROM mysql.user ORDER BY User;" }, - { label: 'SHOW GRANTS (actual)',cmd: 'SHOW GRANTS FOR CURRENT_USER;' }, - { label: 'SHOW PROCESSLIST', cmd: 'SHOW FULL PROCESSLIST;' }, - { label: 'SHOW CREATE TABLE', cmd: 'SHOW CREATE TABLE nombre_tabla;' }, - { label: 'DESC tabla', cmd: 'DESCRIBE nombre_tabla;' }, - { label: 'ENGINE/CHARSET', cmd: "SELECT table_name, engine, table_collation FROM information_schema.tables WHERE table_schema = DATABASE();" }, - ], + get sqlHelpers() { + if (this.isPostgres) return [ + { label: 'SHOW DATABASES', cmd: 'SELECT datname FROM pg_database ORDER BY datname;' }, + { label: 'SHOW TABLES', cmd: "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_name;" }, + { label: 'SHOW USERS', cmd: "SELECT usename, usesuper, usecreatedb, usecreaterole FROM pg_catalog.pg_user ORDER BY usename;" }, + { label: 'SHOW GRANTS', cmd: "SELECT grantee, table_name, privilege_type FROM information_schema.role_table_grants WHERE table_schema = 'public' ORDER BY grantee, table_name;" }, + { label: 'SHOW CONNECTIONS', cmd: "SELECT pid, usename, application_name, state, query_start, LEFT(query,80) AS query FROM pg_stat_activity WHERE state IS NOT NULL;" }, + { label: 'DESC tabla', cmd: "SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name = 'nombre_tabla' ORDER BY ordinal_position;" }, + { label: 'SHOW INDEXES', cmd: "SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'nombre_tabla';" }, + { label: 'SIZE db', cmd: "SELECT pg_size_pretty(pg_database_size(current_database())) AS size;" }, + ]; + // MySQL / MariaDB + return [ + { label: 'SHOW DATABASES', cmd: 'SHOW DATABASES;' }, + { label: 'SHOW TABLES', cmd: 'SHOW TABLES;' }, + { label: 'SHOW USERS', cmd: "SELECT User, Host, plugin FROM mysql.user ORDER BY User;" }, + { label: 'SHOW GRANTS', cmd: 'SHOW GRANTS FOR CURRENT_USER;' }, + { label: 'SHOW PROCESSLIST', cmd: 'SHOW FULL PROCESSLIST;' }, + { label: 'SHOW CREATE TABLE', cmd: 'SHOW CREATE TABLE nombre_tabla;' }, + { label: 'DESC tabla', cmd: 'DESCRIBE nombre_tabla;' }, + { label: 'ENGINE/CHARSET', cmd: "SELECT table_name, engine, table_collation FROM information_schema.tables WHERE table_schema = DATABASE();" }, + ]; + }, mongoExamples: [ { label: 'find()', cmd: 'db.coleccion.find({})' }, { label: 'findOne()', cmd: 'db.coleccion.findOne({})' }, @@ -502,7 +518,9 @@ document.addEventListener('alpine:init', () => { this.collectionFields = []; if (!this.selectedConxId) return; const conx = this.conexiones.find(c => c.ID == this.selectedConxId); - this.isMongo = conx?.tipo_db?.nombre?.toLowerCase().includes('mongo') ?? false; + const dbType = conx?.tipo_db?.nombre?.toLowerCase() || ''; + this.isMongo = dbType.includes('mongo'); + this.isPostgres = dbType.includes('postgres'); try { const res = await axios.get('/app/query-runner/databases?conx_db_id=' + this.selectedConxId); this.databases = res.data.data || []; @@ -699,25 +717,47 @@ document.addEventListener('alpine:init', () => { const user = this.dbHelper.user || 'usuario_app'; const host = this.dbHelper.host || '%'; const pass = this.dbHelper.pass || 'Contraseña123!'; + let map; - const createDb = `CREATE DATABASE IF NOT EXISTS \`${db}\`\n CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`; - const createUser = `CREATE USER IF NOT EXISTS '${user}'@'${host}' IDENTIFIED BY '${pass}';`; - const grant = `GRANT ALL PRIVILEGES ON \`${db}\`.* TO '${user}'@'${host}';\nFLUSH PRIVILEGES;`; - const revoke = `REVOKE ALL PRIVILEGES ON \`${db}\`.* FROM '${user}'@'${host}';\nFLUSH PRIVILEGES;`; - const showGrants = `SHOW GRANTS FOR '${user}'@'${host}';`; - const dropUser = `DROP USER IF EXISTS '${user}'@'${host}';\nFLUSH PRIVILEGES;`; - const dropDb = `DROP DATABASE IF EXISTS \`${db}\`;`; - - const map = { - full_setup: `-- 1. Crear base de datos\n${createDb}\n\n-- 2. Crear usuario\n${createUser}\n\n-- 3. Dar permisos totales\n${grant}`, - create_db: createDb, - create_user: createUser, - grant: grant, - revoke: revoke, - show_grants: showGrants, - drop_user: dropUser, - drop_db: dropDb, - }; + if (this.isPostgres) { + // ── PostgreSQL ────────────────────────────────────────────── + const createDb = `CREATE DATABASE "${db}"\n WITH ENCODING 'UTF8'\n LC_COLLATE = 'en_US.UTF-8'\n LC_CTYPE = 'en_US.UTF-8'\n TEMPLATE = template0;`; + const createUser = `DO $$\nBEGIN\n IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '${user}') THEN\n CREATE USER "${user}" WITH PASSWORD '${pass}';\n END IF;\nEND\n$$;`; + const grant = `GRANT ALL PRIVILEGES ON DATABASE "${db}" TO "${user}";\nGRANT ALL ON SCHEMA public TO "${user}";\nALTER DEFAULT PRIVILEGES IN SCHEMA public\n GRANT ALL ON TABLES TO "${user}";\nALTER DEFAULT PRIVILEGES IN SCHEMA public\n GRANT ALL ON SEQUENCES TO "${user}";`; + const revoke = `REVOKE ALL PRIVILEGES ON DATABASE "${db}" FROM "${user}";\nREVOKE ALL ON SCHEMA public FROM "${user}";`; + const showGrants = `SELECT grantee, privilege_type, table_name\nFROM information_schema.role_table_grants\nWHERE grantee = '${user}'\nORDER BY table_name;`; + const dropUser = `DROP USER IF EXISTS "${user}";`; + const dropDb = `DROP DATABASE IF EXISTS "${db}";`; + map = { + full_setup: `-- 1. Crear base de datos\n${createDb}\n\n-- 2. Crear usuario (si no existe)\n${createUser}\n\n-- 3. Dar permisos totales\n${grant}`, + create_db: createDb, + create_user: createUser, + grant: grant, + revoke: revoke, + show_grants: showGrants, + drop_user: dropUser, + drop_db: dropDb, + }; + } else { + // ── MySQL / MariaDB ───────────────────────────────────────── + const createDb = `CREATE DATABASE IF NOT EXISTS \`${db}\`\n CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;`; + const createUser = `CREATE USER IF NOT EXISTS '${user}'@'${host}' IDENTIFIED BY '${pass}';`; + const grant = `GRANT ALL PRIVILEGES ON \`${db}\`.* TO '${user}'@'${host}';\nFLUSH PRIVILEGES;`; + const revoke = `REVOKE ALL PRIVILEGES ON \`${db}\`.* FROM '${user}'@'${host}';\nFLUSH PRIVILEGES;`; + const showGrants = `SHOW GRANTS FOR '${user}'@'${host}';`; + const dropUser = `DROP USER IF EXISTS '${user}'@'${host}';\nFLUSH PRIVILEGES;`; + const dropDb = `DROP DATABASE IF EXISTS \`${db}\`;`; + map = { + full_setup: `-- 1. Crear base de datos\n${createDb}\n\n-- 2. Crear usuario\n${createUser}\n\n-- 3. Dar permisos totales\n${grant}`, + create_db: createDb, + create_user: createUser, + grant: grant, + revoke: revoke, + show_grants: showGrants, + drop_user: dropUser, + drop_db: dropDb, + }; + } this.sqlText = map[this.dbHelper.op] || ''; document.getElementById('sql-editor')?.focus();