• 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

97.78
/pkg/pgsql/sys/pg_class.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 sys
18

19
import (
20
        "context"
21

22
        "github.com/codenotary/immudb/embedded/sql"
23
)
24

25
// Column names in pg_class. Kept in one place so pgClassColumns and
26
// the row builder can't drift.
27
const (
28
        pgClassOid                 = "oid"
29
        pgClassRelname             = "relname"
30
        pgClassRelnamespace        = "relnamespace"
31
        pgClassReltype             = "reltype"
32
        pgClassReloftype           = "reloftype"
33
        pgClassRelowner            = "relowner"
34
        pgClassRelam               = "relam"
35
        pgClassRelfilenode         = "relfilenode"
36
        pgClassReltablespace       = "reltablespace"
37
        pgClassRelpages            = "relpages"
38
        pgClassReltuples           = "reltuples"
39
        pgClassRelallvisible       = "relallvisible"
40
        pgClassReltoastrelid       = "reltoastrelid"
41
        pgClassRelhasindex         = "relhasindex"
42
        pgClassRelisshared         = "relisshared"
43
        pgClassRelpersistence      = "relpersistence"
44
        pgClassRelkind             = "relkind"
45
        pgClassRelnatts            = "relnatts"
46
        pgClassRelchecks           = "relchecks"
47
        pgClassRelhasrules         = "relhasrules"
48
        pgClassRelhastriggers      = "relhastriggers"
49
        pgClassRelhassubclass      = "relhassubclass"
50
        pgClassRelrowsecurity      = "relrowsecurity"
51
        pgClassRelforcerowsecurity = "relforcerowsecurity"
52
        pgClassRelispopulated      = "relispopulated"
53
        pgClassRelreplident        = "relreplident"
54
        pgClassRelispartition      = "relispartition"
55
        pgClassRelhasoids          = "relhasoids"
56
)
57

58
var pgClassColumns = []sql.SystemTableColumn{
59
        {Name: pgClassOid, Type: sql.IntegerType},
60
        {Name: pgClassRelname, Type: sql.VarcharType, MaxLen: 128},
61
        {Name: pgClassRelnamespace, Type: sql.IntegerType},
62
        {Name: pgClassReltype, Type: sql.IntegerType},
63
        {Name: pgClassReloftype, Type: sql.IntegerType},
64
        {Name: pgClassRelowner, Type: sql.IntegerType},
65
        {Name: pgClassRelam, Type: sql.IntegerType},
66
        {Name: pgClassRelfilenode, Type: sql.IntegerType},
67
        {Name: pgClassReltablespace, Type: sql.IntegerType},
68
        {Name: pgClassRelpages, Type: sql.IntegerType},
69
        {Name: pgClassReltuples, Type: sql.Float64Type},
70
        {Name: pgClassRelallvisible, Type: sql.IntegerType},
71
        {Name: pgClassReltoastrelid, Type: sql.IntegerType},
72
        {Name: pgClassRelhasindex, Type: sql.BooleanType},
73
        {Name: pgClassRelisshared, Type: sql.BooleanType},
74
        {Name: pgClassRelpersistence, Type: sql.VarcharType, MaxLen: 1},
75
        {Name: pgClassRelkind, Type: sql.VarcharType, MaxLen: 1},
76
        {Name: pgClassRelnatts, Type: sql.IntegerType},
77
        {Name: pgClassRelchecks, Type: sql.IntegerType},
78
        {Name: pgClassRelhasrules, Type: sql.BooleanType},
79
        {Name: pgClassRelhastriggers, Type: sql.BooleanType},
80
        {Name: pgClassRelhassubclass, Type: sql.BooleanType},
81
        {Name: pgClassRelrowsecurity, Type: sql.BooleanType},
82
        {Name: pgClassRelforcerowsecurity, Type: sql.BooleanType},
83
        {Name: pgClassRelispopulated, Type: sql.BooleanType},
84
        {Name: pgClassRelreplident, Type: sql.VarcharType, MaxLen: 1},
85
        {Name: pgClassRelispartition, Type: sql.BooleanType},
86
        {Name: pgClassRelhasoids, Type: sql.BooleanType},
87
}
88

89
// pg_class: one row per user table and one per user index.
90
// Views live in the engine's tableResolvers rather than the catalog;
91
// we don't expose them in pg_class yet because the engine doesn't let
92
// us enumerate them from inside a Scan without a more invasive change
93
// (deferred to a later phase).
94
//
95
// Every user object is reported under the 'public' namespace because
96
// immudb has no schema concept; that's what psql's \d expects as a
97
// default and it matches the handlePgTablesQuery canned handler.
98
func init() {
13✔
99
        sql.RegisterSystemTable(&sql.SystemTableDef{
13✔
100
                Name:     "pg_class",
13✔
101
                Columns:  pgClassColumns,
13✔
102
                PKColumn: pgClassOid,
13✔
103
                Scan: func(ctx context.Context, tx *sql.SQLTx) ([]*sql.Row, error) {
42✔
104
                        cat := tx.Catalog()
29✔
105
                        if cat == nil {
29✔
NEW
106
                                return nil, nil
×
NEW
107
                        }
×
108

109
                        tables := cat.GetTables()
29✔
110
                        // Each table contributes one row, plus one row per index on
29✔
111
                        // that table. Pre-size for the common case.
29✔
112
                        rows := make([]*sql.Row, 0, len(tables)*2)
29✔
113

29✔
114
                        for _, t := range tables {
60✔
115
                                rows = append(rows, rowPgClassForTable(t))
31✔
116
                                for _, idx := range t.GetIndexes() {
68✔
117
                                        rows = append(rows, rowPgClassForIndex(t, idx))
37✔
118
                                }
37✔
119
                        }
120
                        return rows, nil
29✔
121
                },
122
        })
123
}
124

125
func rowPgClassForTable(t *sql.Table) *sql.Row {
31✔
126
        cols := t.Cols()
31✔
127
        return &sql.Row{ValuesByPosition: []sql.TypedValue{
31✔
128
                sql.NewInteger(relOID("public", t.Name())),
31✔
129
                sql.NewVarchar(t.Name()),
31✔
130
                sql.NewInteger(OIDNamespacePublic),
31✔
131
                sql.NewInteger(0), // reltype — pg_type composite row; we don't synthesise these
31✔
132
                sql.NewInteger(0), // reloftype
31✔
133
                sql.NewInteger(10),
31✔
134
                sql.NewInteger(0), // relam — tables don't have an access method in PG
31✔
135
                sql.NewInteger(0), // relfilenode
31✔
136
                sql.NewInteger(0), // reltablespace (pg_default)
31✔
137
                sql.NewInteger(0), // relpages
31✔
138
                sql.NewFloat64(0), // reltuples — could be approximate; 0 is safe
31✔
139
                sql.NewInteger(0), // relallvisible
31✔
140
                sql.NewInteger(0), // reltoastrelid
31✔
141
                sql.NewBool(len(t.GetIndexes()) > 0),
31✔
142
                sql.NewBool(false), // relisshared
31✔
143
                sql.NewVarchar("p"),
31✔
144
                sql.NewVarchar("r"),
31✔
145
                sql.NewInteger(int64(len(cols))),
31✔
146
                sql.NewInteger(0), // relchecks — we have the data but enumerating needs a Table accessor we don't yet expose
31✔
147
                sql.NewBool(false),
31✔
148
                sql.NewBool(false),
31✔
149
                sql.NewBool(false),
31✔
150
                sql.NewBool(false),
31✔
151
                sql.NewBool(false),
31✔
152
                sql.NewBool(true),  // relispopulated — user tables always are
31✔
153
                sql.NewVarchar("d"),
31✔
154
                sql.NewBool(false),
31✔
155
                sql.NewBool(false),
31✔
156
        }}
31✔
157
}
31✔
158

159
func rowPgClassForIndex(t *sql.Table, idx *sql.Index) *sql.Row {
37✔
160
        // Index OID hashes on (table.name, index.name) so renaming either
37✔
161
        // side changes it — acceptable since clients don't cache index oids
37✔
162
        // across migrations.
37✔
163
        indexRelName := idx.Name()
37✔
164
        return &sql.Row{ValuesByPosition: []sql.TypedValue{
37✔
165
                sql.NewInteger(relOID("public", indexRelName)),
37✔
166
                sql.NewVarchar(indexRelName),
37✔
167
                sql.NewInteger(OIDNamespacePublic),
37✔
168
                sql.NewInteger(0),
37✔
169
                sql.NewInteger(0),
37✔
170
                sql.NewInteger(10),
37✔
171
                sql.NewInteger(OIDAccessMethodBtree),
37✔
172
                sql.NewInteger(0),
37✔
173
                sql.NewInteger(0),
37✔
174
                sql.NewInteger(0),
37✔
175
                sql.NewFloat64(0),
37✔
176
                sql.NewInteger(0),
37✔
177
                sql.NewInteger(0),
37✔
178
                sql.NewBool(false), // relhasindex — indexes don't have sub-indexes
37✔
179
                sql.NewBool(false),
37✔
180
                sql.NewVarchar("p"),
37✔
181
                sql.NewVarchar("i"), // relkind 'i' = index
37✔
182
                sql.NewInteger(int64(len(idx.Cols()))),
37✔
183
                sql.NewInteger(0),
37✔
184
                sql.NewBool(false),
37✔
185
                sql.NewBool(false),
37✔
186
                sql.NewBool(false),
37✔
187
                sql.NewBool(false),
37✔
188
                sql.NewBool(false),
37✔
189
                sql.NewBool(true),
37✔
190
                sql.NewVarchar("n"),
37✔
191
                sql.NewBool(false),
37✔
192
                sql.NewBool(false),
37✔
193
        }}
37✔
194
}
37✔
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