// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. package pgserver import "github.com/jackc/pgx/v5/pgproto3" // sqlStateFor maps a FiveSql2 error code (from FiveSqlDef.ch // SQL_ERR_*) to a PostgreSQL SQLSTATE 5-char identifier so // clients can dispatch error handlers in their native idiom. // // Codes that don't have a clean PG equivalent fall back to XX000 // (internal_error) — the universal "something went wrong" bucket. func sqlStateFor(code int) string { // FiveSqlDef.ch numeric mapping (kept in sync with the .ch file): // 1 SQL_ERR_SYNTAX → 42601 syntax_error // 2 SQL_ERR_TABLE → 42P01 undefined_table // 3 SQL_ERR_COLUMN → 42703 undefined_column // 4 SQL_ERR_TYPE → 42804 datatype_mismatch // 5 SQL_ERR_UNIQUE → 23505 unique_violation // 6 SQL_ERR_CHECK → 23514 check_violation // 7 SQL_ERR_FK → 23503 foreign_key_violation // 8 SQL_ERR_TXN → 25P02 in_failed_sql_transaction // 9 SQL_ERR_PERM → 42501 insufficient_privilege // 10 SQL_ERR_NOTFOUND → 02000 no_data switch code { case 1: return "42601" case 2: return "42P01" case 3: return "42703" case 4: return "42804" case 5: return "23505" case 6: return "23514" case 7: return "23503" case 8: return "25P02" case 9: return "42501" case 10: return "02000" default: return "XX000" } } // buildErrorResponse assembles a pgproto3.ErrorResponse from the // triplet FiveSql2 surfaces. Optional Query field carries the // offending SQL so error-aware clients (pgAdmin, DataGrip) can // highlight the source. func buildErrorResponse(sqlState, message, query string) *pgproto3.ErrorResponse { resp := &pgproto3.ErrorResponse{ Severity: "ERROR", Code: sqlState, Message: message, } if query != "" { // PG's "InternalQuery" field surfaces in psql with a // "QUERY:" line directly under the error message. resp.InternalQuery = query } return resp }