Skip to content

2.1: lock analysis, query shape, tokens, operation summary, PL/pgSQL query parsing - #26

Merged
mysticmind merged 1 commit into
mainfrom
capabilities-2.1-third
Oct 9, 2026
Merged

mysticmind merged 1 commit into
mainfrom
capabilities-2.1-third

Conversation

@mysticmind

Copy link
Copy Markdown
Owner

The third set of general-purpose capabilities, still under 2.1.0. All additive.

Locks

tree.GetLocks() (also on a RawStmt) returns the table locks each statement takes on the tables it names, one entry per table and statement with the strongest mode. LockMode has ConflictsWith, BlocksReads and BlocksWrites.

The rules come from PostgreSQL itself, not from memory:

  • ALTER TABLE: ported from AlterTableGetLockLevel in PostgreSQL 18's tablecmds.c, sub-command by sub-command, with the strongest one deciding.
  • Storage options (ALTER TABLE ... SET (...)): the per-option lock levels from reloptions.c (9 options need ACCESS EXCLUSIVE, 31 need SHARE UPDATE EXCLUSIVE).
  • Everything else: the "Table-Level Lock Modes" documentation, including the conflict table.

Covered: SELECT (with and without FOR UPDATE and similar), INSERT, UPDATE, DELETE, MERGE, COPY, EXPLAIN, TRUNCATE, LOCK, CREATE INDEX, CREATE TRIGGER, CREATE STATISTICS, ALTER TABLE, DROP TABLE and similar, VACUUM, ANALYZE, CLUSTER, REINDEX TABLE, REFRESH MATERIALIZED VIEW, COMMENT ON TABLE or COLUMN, and the table a new foreign key points to.

Not covered, and stated in the docs: locks on a table reached through a view, an index name (DROP INDEX, REINDEX INDEX, ALTER INDEX), a partition or an inheritance child, locks taken by triggers and functions, and row-level locks. Those need the catalog.

Query shape

  • ColumnReference.Clause: SelectList, From, JoinCondition, Where, GroupBy, Having, OrderBy, Returning, Set or Other, relative to the nearest enclosing statement. Columns in Where and JoinCondition are the ones that filter rows, which is the input for index advice.
  • select.GetOutputColumns(): the result columns of a SELECT with the names PostgreSQL gives them (a port of FigureColnameInternal from parse_target.c), * flagged as such, the first branch for set operations, and column1, column2 for VALUES.

Text

  • Parser.Tokenize: tokens classified as Keyword, Identifier, StringLiteral, NumericLiteral, Parameter, Operator, Punctuation or Comment, with offsets into the string. Works on SQL that does not parse.
  • Parser.OperationSummary: the operation and the tables it touches, such as SELECT customers orders, with no literals, parameters or columns. This is the form OpenTelemetry's db.query.summary asks for; it is cut at a word boundary to a maximum length (255 by default).

PL/pgSQL

PlpgsqlNode.ParseQuery() and PlpgsqlFunction.ParseQueries() parse the SQL inside a function body, each piece in the mode PL/pgSQL uses for it (query, expression or assignment), so GetReferences, GetLocks and the rest work on function bodies too.

A fix to merged code

GetReferences reported the targets of FOR UPDATE OF x as tables. They name items of the FROM clause, so they are no longer returned. Found by the lock tests.

Verification

  • 95 new test cases in InsightTests; 482 pass on .NET 8, 9 and 10 locally.
  • The package smoke test covers each addition, and a local Native AOT publish ran them with no trim or AOT warnings.
  • README sections added, with example output that was run.

Limits

  • OperationSummary names: the six planned statement kinds and 14 common DDL forms get a full name (CREATE INDEX, DROP TABLE); other statements get their first keyword (GRANT, VACUUM).
  • Output column names cover the expression kinds in the tests; XML functions and some JSON constructors fall back to ?column?.
  • REINDEX TABLE is reported as SHARE on the table, following the REINDEX documentation (it blocks writes, not reads), where the general lock-mode page lists REINDEX under ACCESS EXCLUSIVE, which applies to the index.

…L query parsing

- GetLocks: the table locks a statement takes and what they block,
  following PostgreSQL's documented lock rules and, for ALTER TABLE,
  AlterTableGetLockLevel and the storage option table of PostgreSQL 18
- Column references carry their clause; GetOutputColumns names a
  SELECT's result columns as PostgreSQL does (a port of FigureColname)
- Parser.Tokenize classifies tokens for display
- Parser.OperationSummary gives the low-cardinality form OpenTelemetry's
  db.query.summary asks for
- PlpgsqlNode.ParseQuery and PlpgsqlFunction.ParseQueries parse the SQL
  inside a function body in the mode PL/pgSQL uses for it
- GetReferences no longer reports the targets of FOR UPDATE OF as tables
@mysticmind
mysticmind merged commit 7c278c7 into main Oct 9, 2026
25 checks passed
@mysticmind
mysticmind deleted the capabilities-2.1-third branch October 9, 2026 15:26
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