• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

codenotary / immudb / 24841644892

23 Apr 2026 02:44PM UTC coverage: 85.279% (-4.0%) from 89.306%
24841644892

push

gh-ci

web-flow
feat: v1.11.0 PostgreSQL compatibility and SQL feature expansion (#2090)

* Add structured audit logging with immutable audit trail

Introduces a new --audit-log flag that records all gRPC operations as
structured JSON events in immudb's tamper-proof KV store. Events are
stored under the audit: key prefix in systemdb, queryable via Scan and
verifiable via VerifiableGet. An async buffered writer ensures minimal
latency impact. Configurable event filtering (all/write/admin) via
--audit-log-events flag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add PostgreSQL ORM compatibility layer and verification functions

Extend the pgsql wire protocol with immudb verification functions
(immudb_state, immudb_verify_row, immudb_verify_tx, immudb_history,
immudb_tx) accessible via standard SQL SELECT statements.

Add pg_catalog resolvers (pg_attribute, pg_index, pg_constraint,
pg_type, pg_settings, pg_description) and information_schema
resolvers (tables, columns, schemata, key_column_usage) to support
ORM introspection from Django, SQLAlchemy, GORM, and ActiveRecord.

Add PostgreSQL compatibility functions: current_database,
current_schema, current_user, format_type, pg_encoding_to_char,
pg_get_expr, pg_get_constraintdef, obj_description, col_description,
has_table_privilege, has_schema_privilege, and others.

Add SHOW statement emulation for common ORM config queries and
schema-qualified name stripping for information_schema and public
schema references.

* Implement EXISTS and IN subquery support in SQL engine

Replace the previously stubbed ExistsBoolExp and InSubQueryExp
implementations with working non-correlated subquery execution.

EXISTS subqueries resolve the inner SELECT and check if any rows
are returned. IN subqueries resolve the inner SELECT, iterate the
result set, and compare each value against the outer expression.
Both support NOT variants (NOT EXISTS, NOT IN).

Correlated subqueries (referencing outer query columns) ar... (continued)

7254 of 10471 new or added lines in 124 files covered. (69.28%)

115 existing lines in 18 files now uncovered.

44599 of 52298 relevant lines covered (85.28%)

127676.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.55
/pkg/pgsql/server/rewrite/rewriter.go
1
/*
2
Copyright 2026 Codenotary Inc. All rights reserved.
3

4
SPDX-License-Identifier: BUSL-1.1
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    https://mariadb.com/bsl11/
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
// Package rewrite is the AST-based SQL rewriter that replaces the
18
// regex chain in pkg/pgsql/server/query_machine.go (removePGCatalogReferences +
19
// pgTypeReplacements). See docs/pg-compat-roadmap.md Part B for the
20
// programme; this is the B1 scaffold with 3 proof-of-concept rules.
21
//
22
// The rewriter is currently additive: Rewrite() parses SQL with
23
// github.com/auxten/postgresql-parser, walks the AST applying the
24
// registered Rules in order, then deparses back to SQL. On any parse
25
// failure it returns the input string unchanged along with the parse
26
// error so callers can fall back to the legacy regex chain.
27
package rewrite
28

29
import (
30
        "github.com/auxten/postgresql-parser/pkg/sql/parser"
31
        "github.com/auxten/postgresql-parser/pkg/sql/sem/tree"
32
)
33

34
// Rule is a single AST-level transformation. Name() is used for
35
// logging and for the (future) B2 dependency graph; Apply rewrites the
36
// statement in place OR returns a copy — semantics follow the auxten
37
// Visitor contract, which means "may mutate" in practice.
38
type Rule interface {
39
        Name() string
40
        // Apply transforms a single parsed statement. The statement may
41
        // be mutated in place; returning it is purely a convenience for
42
        // chaining. Implementations should use tree.Walk / tree.WalkExpr
43
        // to traverse; building Statement-level visitors from scratch is
44
        // error-prone.
45
        Apply(stmt tree.Statement) tree.Statement
46
}
47

48
// Rewriter applies an ordered slice of Rules to each input statement.
49
// Construction is via New(); callers register Rules with WithRule().
50
// The Rewrite() method is safe for concurrent use: it holds no
51
// mutable state across calls.
52
type Rewriter struct {
53
        rules []Rule
54
}
55

56
// New returns a Rewriter with no rules installed. Use WithRule(s) to
57
// populate it. The zero-rule Rewriter is a valid parse-and-redeparse
58
// pass, which is occasionally useful for normalising whitespace.
59
func New() *Rewriter {
52✔
60
        return &Rewriter{}
52✔
61
}
52✔
62

63
// WithRule appends a rule to the pipeline. Rules run in the order
64
// they were added. B2 may add topological-sort logic if rule
65
// dependencies become explicit, but B1 relies on fixed ordering from
66
// the call site.
67
func (r *Rewriter) WithRule(rule Rule) *Rewriter {
206✔
68
        r.rules = append(r.rules, rule)
206✔
69
        return r
206✔
70
}
206✔
71

72
// Rules returns the ordered rule list. Primarily for tests and
73
// diagnostic logging.
74
func (r *Rewriter) Rules() []Rule {
2✔
75
        out := make([]Rule, len(r.rules))
2✔
76
        copy(out, r.rules)
2✔
77
        return out
2✔
78
}
2✔
79

80
// Rewrite parses sql, applies every registered rule to every parsed
81
// statement, and emits a canonical PG-dialect string. When parsing
82
// fails, returns the input unchanged along with the parse error —
83
// callers (currently query_machine.go) use that signal to fall back
84
// to the legacy regex chain.
85
//
86
// A rule that returns nil from Apply signals "drop this statement
87
// entirely" — the Rewriter filters such results out of the emitted
88
// SQL. Useful for strip-whole-statement rules like the trailing-
89
// `COMMENT ON …` remover.
90
//
91
// Rewriting is deliberately a pure function of (sql, rules): no
92
// session state, no catalog lookups. Rules that need catalog
93
// information take it via constructor arguments, not via the
94
// Rewriter.
95
func (r *Rewriter) Rewrite(sql string) (string, error) {
121✔
96
        stmts, err := parser.Parse(sql)
121✔
97
        if err != nil {
125✔
98
                return sql, err
4✔
99
        }
4✔
100
        kept := stmts[:0]
117✔
101
        for i := range stmts {
238✔
102
                ast := stmts[i].AST
121✔
103
                for _, rule := range r.rules {
602✔
104
                        if ast == nil {
481✔
NEW
105
                                break
×
106
                        }
107
                        ast = rule.Apply(ast)
481✔
108
                }
109
                if ast == nil {
125✔
110
                        continue
4✔
111
                }
112
                stmts[i].AST = ast
117✔
113
                kept = append(kept, stmts[i])
117✔
114
        }
115
        return kept.String(), nil
117✔
116
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc