Skip to content

Agent/SCIM postgresql query analyzer#1

Merged
udaychandra merged 6 commits into
mainfrom
agent/scim-postgresql-query-analyzer
Jul 10, 2026
Merged

Agent/SCIM postgresql query analyzer#1
udaychandra merged 6 commits into
mainfrom
agent/scim-postgresql-query-analyzer

Conversation

@udaychandra

Copy link
Copy Markdown
Contributor

No description provided.

Uday Chandra added 6 commits July 10, 2026 16:28
Extend scim-sql with ai.singlr.postgresql, a generic PostgreSQL
query-analysis API that parses complete SQL and reports structural
facts: statement kind and count, relations (physical/CTE/function,
with aliases), columns, functions, named parameters, policy-relevant
features, and a deterministic normalized form for hashing and audit.
It parses and describes SQL only - no execution, catalog resolution,
authorization, or policy.

The grammar is the ANTLR grammars-v4 PostgreSQL grammar vendored at
commit 76093c04af6a51f38a67d14f7e71ff0a9b4400da with one deliberate
extension: named parameters (:name) are first-class expression values
and can never be identifiers, aliases, or relations. Provenance,
verbatim upstream licenses, local modifications, and the upgrade path
are recorded in NOTICE.md and shipped in the jars under META-INF.

Analysis walks all nested scopes with progressive CTE scoping
(non-recursive CTE bodies do not see their own name; siblings see
earlier names; inner scopes shadow outer). Input is bounded by
length, token count, and nesting depth; exceptions carry only a
stable reason plus line/column and never echo SQL content.

Grammar warnings are pinned (two benign upstream warning-146 lexer
rules) and any new warning or error fails the build. An upstream
regression corpus, adversarial/hostile input tests, and module-export
tests protect behavior. Existing SCIM behavior and API are unchanged;
the artifact gains no runtime dependency beyond the existing ANTLR
runtime. Version bumped to 1.1.0-SNAPSHOT.
- Resolve CTE names only where PostgreSQL permits a CTE source, so
  INSERT, UPDATE, DELETE, and SELECT INTO targets stay PHYSICAL
- Fold identifiers and normalized SQL with ASCII-only lowercasing to
  match PostgreSQL's UTF-8 identifier folding
- Put all sibling CTE names in scope under WITH RECURSIVE
- Rework MERGE grammar as ordered WHEN clauses, accepting DO NOTHING,
  repeated WHEN clauses, and INSERT DEFAULT VALUES
- Reject psql meta-commands: the META lexer mode silently turned
  backslash commands into statement separators, so an allowed SELECT
  could smuggle \! or \copy past analysis; a backslash now lexes as
  ErrorCharacter and fails closed (corpus files updated accordingly)
- Reject Unicode-escaped identifiers (U&"...") at lex time: their
  effective name differs from their spelling, so name-based policies
  could be bypassed with an equivalent spelling
- Collect JOIN USING names as column references
- Report DROP TABLE / VIEW / MATERIALIZED VIEW / FOREIGN TABLE targets
  as physical relations
- Lex nested block comments iteratively with a depth counter: the
  recursive rule needed ~1s for 5 KB of 1250-deep nesting and overflowed
  the stack near 1500; now 6 ms at depth 20000
- Accept PostgreSQL newline string continuation ('a'\n'b'), matching
  scan.l semantics verified against PostgreSQL 16: line comments count
  as separating whitespace, block comments and dollar-quoted strings
  do not, same-line adjacency stays an error
- Reject identifiers longer than 63 UTF-8 bytes (post-unescape) so the
  analyzer never reports a name PostgreSQL would silently truncate to a
  different effective identifier
- Collect bare ON CONFLICT arbiter and CREATE INDEX columns via the
  colid alternative of index_elem
- Accept WITH ... MERGE: grammar allows a leading with_clause_, MERGE
  is a with-clause owner for CTE scoping, and the USING relation (but
  never the MERGE target) can resolve as a CTE source
- Split greedy :name lexing into COLON + name when the colon continues an
  expression, so compact JSON key:value and array slices (arr[lo:hi]) parse;
  arr[:name] deliberately binds to the named-parameter extension (documented)
- Parse PostgreSQL 14+ unquoted CREATE FUNCTION bodies (RETURN expr and
  BEGIN ATOMIC stmt; ... END); nested body statements do not affect the
  root statement count
- Report relations targeted through any_name: COMMENT ON TABLE/COLUMN/
  CONSTRAINT..ON/TRIGGER..ON, SECURITY LABEL ON TABLE/COLUMN, and
  DROP TRIGGER/RULE/POLICY .. ON
- Classify REASSIGN OWNED as DDL
- Keep normalizedSql single-line: string continuation joins with a space
  (collision-safe: same-line string adjacency is rejected by the parser)
- Refresh NOTICE.md local-modification provenance (also records the earlier
  iterative block-comment lexing change)
The vendored grammars-v4 grammar (verified at parity with upstream HEAD)
ships several defects and unported productions; each fix below follows
PostgreSQL's authoritative gram.y and is recorded in NOTICE.md:

- json_aggregate_func existed but was never referenced: wired into
  func_expr/func_expr_windowless with FILTER/OVER, returning clause made
  optional; aggregates now reported as functions
- MERGE: PG17 RETURNING clause and WHEN NOT MATCHED BY SOURCE/BY TARGET
- GROUP BY [ALL|DISTINCT] (PG14)
- CTE SEARCH and CYCLE clauses (PG14); fixed upstream BREADTH: 'BREATH'
  lexer typo that made SEARCH BREADTH FIRST unparseable
- IS [NOT] JSON [VALUE|ARRAY|OBJECT|SCALAR] predicate (PG16)
- JSON_TABLE table function (PG17), reported as a FUNCTION relation with
  alias like xmltable, which now also reports one
- XMLTABLE column PATH option (PATH is a lexer keyword here, so the
  generic identifier option could not match it)
- json_format_clause now uses the real FORMAT token; upstream's FORMAT_LA
  literal is Bison lookahead residue that never occurs in SQL text
- UNIQUE/PRIMARY KEY ... WITHOUT OVERLAPS (PG18)

Conformance battery over PG14-18 syntax went 18/30 to 30/30; all forms
pinned as tests. Grammar warnings remain pinned with no new entries.
@udaychandra udaychandra merged commit 3ca5599 into main Jul 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant