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

codenotary / immudb / 24841571249

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

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%)

119 existing lines in 18 files now uncovered.

44597 of 52298 relevant lines covered (85.27%)

127591.66 hits per line

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

79.37
/embedded/sql/count_row_reader.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 sql
18

19
import "context"
20

21
// countingRowReader handles bare COUNT(*) queries (SELECT COUNT(*) FROM tbl
22
// with no WHERE, JOINs, GROUP BY, or HAVING) without decoding column values.
23
// It wraps a rawRowReader and returns exactly one Row containing the count.
24
type countingRowReader struct {
25
        rawReader *rawRowReader
26
        // encSel is the encoded selector key expected by projectedRowReader, e.g.
27
        // "COUNT()(t.*)" for a table aliased as "t".
28
        encSel  string
29
        colDesc ColDescriptor
30
        done    bool
31
}
32

33
func newCountingRowReader(rawReader *rawRowReader, agg *AggColSelector) *countingRowReader {
40✔
34
        aggFn, table, col := agg.resolve(rawReader.tableAlias)
40✔
35
        encSel := EncodeSelector(aggFn, table, col)
40✔
36
        return &countingRowReader{
40✔
37
                rawReader: rawReader,
40✔
38
                encSel:    encSel,
40✔
39
                colDesc: ColDescriptor{
40✔
40
                        AggFn:  aggFn,
40✔
41
                        Table:  table,
40✔
42
                        Column: col,
40✔
43
                        Type:   IntegerType,
40✔
44
                },
40✔
45
        }
40✔
46
}
40✔
47

48
func (cr *countingRowReader) onClose(callback func()) {
28✔
49
        cr.rawReader.onClose(callback)
28✔
50
}
28✔
51

52
func (cr *countingRowReader) Tx() *SQLTx {
33✔
53
        return cr.rawReader.Tx()
33✔
54
}
33✔
55

56
func (cr *countingRowReader) TableAlias() string {
211✔
57
        return cr.rawReader.TableAlias()
211✔
58
}
211✔
59

60
func (cr *countingRowReader) Parameters() map[string]interface{} {
25✔
61
        return cr.rawReader.Parameters()
25✔
62
}
25✔
63

NEW
64
func (cr *countingRowReader) OrderBy() []ColDescriptor {
×
NEW
65
        return nil
×
NEW
66
}
×
67

NEW
68
func (cr *countingRowReader) ScanSpecs() *ScanSpecs {
×
NEW
69
        return cr.rawReader.ScanSpecs()
×
NEW
70
}
×
71

NEW
72
func (cr *countingRowReader) Columns(_ context.Context) ([]ColDescriptor, error) {
×
NEW
73
        return []ColDescriptor{cr.colDesc}, nil
×
NEW
74
}
×
75

76
// colsBySelector includes both the COUNT(*) aggregation descriptor and all
77
// raw table column descriptors so that projectedRowReader validation succeeds.
78
func (cr *countingRowReader) colsBySelector(ctx context.Context) (map[string]ColDescriptor, error) {
32✔
79
        colsBySel, err := cr.rawReader.colsBySelector(ctx)
32✔
80
        if err != nil {
32✔
NEW
81
                return nil, err
×
NEW
82
        }
×
83
        colsBySel[cr.encSel] = cr.colDesc
32✔
84
        return colsBySel, nil
32✔
85
}
86

87
func (cr *countingRowReader) InferParameters(ctx context.Context, params map[string]SQLValueType) error {
6✔
88
        return cr.rawReader.InferParameters(ctx, params)
6✔
89
}
6✔
90

91
// Read counts all matching index entries without decoding column values and
92
// returns a single Row. Subsequent calls return ErrNoMoreRows.
93
func (cr *countingRowReader) Read(ctx context.Context) (*Row, error) {
42✔
94
        if cr.done {
59✔
95
                return nil, ErrNoMoreRows
17✔
96
        }
17✔
97
        cr.done = true
25✔
98

25✔
99
        n, err := cr.rawReader.CountAll(ctx)
25✔
100
        if err != nil {
25✔
NEW
101
                return nil, err
×
NEW
102
        }
×
103

104
        val := &Integer{val: n}
25✔
105
        return &Row{
25✔
106
                ValuesByPosition: []TypedValue{val},
25✔
107
                ValuesBySelector: map[string]TypedValue{cr.encSel: val},
25✔
108
        }, nil
25✔
109
}
110

111
func (cr *countingRowReader) Close() error {
40✔
112
        return cr.rawReader.Close()
40✔
113
}
40✔
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