• 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

49.13
/embedded/sql/functions.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 (
20
        "crypto/md5"
21
        "encoding/hex"
22
        "fmt"
23
        "math"
24
        "regexp"
25
        "strings"
26
        "time"
27
        "unicode"
28

29
        "github.com/google/uuid"
30
)
31

32
const (
33
        CoalesceFnCall           string = "COALESCE"
34
        LengthFnCall             string = "LENGTH"
35
        SubstringFnCall          string = "SUBSTRING"
36
        ConcatFnCall             string = "CONCAT"
37
        LowerFnCall              string = "LOWER"
38
        UpperFnCall              string = "UPPER"
39
        TrimFnCall               string = "TRIM"
40
        NowFnCall                string = "NOW"
41
        UUIDFnCall               string = "RANDOM_UUID"
42
        DatabasesFnCall          string = "DATABASES"
43
        TablesFnCall             string = "TABLES"
44
        TableFnCall              string = "TABLE"
45
        UsersFnCall              string = "USERS"
46
        ColumnsFnCall            string = "COLUMNS"
47
        IndexesFnCall            string = "INDEXES"
48
        GrantsFnCall             string = "GRANTS"
49
        JSONTypeOfFnCall         string = "JSON_TYPEOF"
50
        PGGetUserByIDFnCall          string = "PG_GET_USERBYID"
51
        PgTableIsVisibleFnCall       string = "PG_TABLE_IS_VISIBLE"
52
        PgShobjDescriptionFnCall     string = "SHOBJ_DESCRIPTION"
53
        CurrentDatabaseFnCall        string = "CURRENT_DATABASE"
54
        CurrentSchemaFnCall          string = "CURRENT_SCHEMA"
55
        CurrentSchemasFnCall         string = "CURRENT_SCHEMAS"
56
        CurrentUserFnCall            string = "CURRENT_USER"
57
        FormatTypeFnCall             string = "FORMAT_TYPE"
58
        PgGetExprFnCall              string = "PG_GET_EXPR"
59
        PgGetConstraintDefFnCall     string = "PG_GET_CONSTRAINTDEF"
60
        PgGetIndexDefFnCall          string = "PG_GET_INDEXDEF"
61
        PgEncodingToCharFnCall       string = "PG_ENCODING_TO_CHAR"
62
        ObjDescriptionFnCall         string = "OBJ_DESCRIPTION"
63
        HasTablePrivilegeFnCall      string = "HAS_TABLE_PRIVILEGE"
64
        HasSchemaPrivilegeFnCall     string = "HAS_SCHEMA_PRIVILEGE"
65
        HasDatabasePrivilegeFnCall   string = "HAS_DATABASE_PRIVILEGE"
66
        HasFunctionPrivilegeFnCall   string = "HAS_FUNCTION_PRIVILEGE"
67
        ArrayUpperFnCall             string = "ARRAY_UPPER"
68
        ArrayToStringFnCall          string = "ARRAY_TO_STRING"
69
        QuoteIdentFnCall             string = "QUOTE_IDENT"
70
        PgTotalRelationSizeFnCall    string = "PG_TOTAL_RELATION_SIZE"
71
        PgRelationSizeFnCall         string = "PG_RELATION_SIZE"
72
        PgGetSerialSequenceFnCall    string = "PG_GET_SERIAL_SEQUENCE"
73
        ColDescriptionFnCall         string = "COL_DESCRIPTION"
74

75
        // Math functions
76
        AbsFnCall     string = "ABS"
77
        CeilFnCall    string = "CEIL"
78
        FloorFnCall   string = "FLOOR"
79
        RoundFnCall   string = "ROUND"
80
        PowerFnCall   string = "POWER"
81
        SqrtFnCall    string = "SQRT"
82
        ModFnCall     string = "MOD"
83
        SignFnCall    string = "SIGN"
84

85
        // String functions
86
        ReplaceFnCall  string = "REPLACE"
87
        ReverseFnCall  string = "REVERSE"
88
        LeftFnCall     string = "LEFT"
89
        RightFnCall    string = "RIGHT"
90
        RepeatFnCall   string = "REPEAT"
91
        PositionFnCall string = "POSITION"
92
        CharLengthFnCall string = "CHAR_LENGTH"
93
        OctetLengthFnCall string = "OCTET_LENGTH"
94

95
        // Conditional functions
96
        NullIfFnCall   string = "NULLIF"
97
        GreatestFnCall string = "GREATEST"
98
        LeastFnCall    string = "LEAST"
99

100
        // Additional string functions
101
        LpadFnCall      string = "LPAD"
102
        RpadFnCall      string = "RPAD"
103
        SplitPartFnCall string = "SPLIT_PART"
104
        InitcapFnCall   string = "INITCAP"
105
        ChrFnCall       string = "CHR"
106
        AsciiFnCall     string = "ASCII"
107
        MD5FnCall       string = "MD5"
108
        TranslateFnCall string = "TRANSLATE"
109

110
        // Date/time functions
111
        DateTruncFnCall  string = "DATE_TRUNC"
112
        ToCharFnCall     string = "TO_CHAR"
113
        DatePartFnCall   string = "DATE_PART"
114
        AgeFnCall        string = "AGE"
115
        ClockTimestampFnCall string = "CLOCK_TIMESTAMP"
116

117
        // Aliases
118
        SubstrFnCall        string = "SUBSTR"
119
        StrposFnCall        string = "STRPOS"
120
        ConcatWSFnCall      string = "CONCAT_WS"
121
        RegexpReplaceFnCall string = "REGEXP_REPLACE"
122

123
        // Sequence functions
124
        NextValFnCall string = "NEXTVAL"
125
        CurrValFnCall string = "CURRVAL"
126

127
        // Additional utility functions
128
        RandomFnCall      string = "RANDOM"
129
        GenRandomUUIDCall string = "GEN_RANDOM_UUID"
130
        ToNumberFnCall    string = "TO_NUMBER"
131
)
132

133
var builtinFunctions = map[string]Function{
134
        CoalesceFnCall:           &CoalesceFn{},
135
        LengthFnCall:             &LengthFn{},
136
        SubstringFnCall:          &SubstringFn{},
137
        ConcatFnCall:             &ConcatFn{},
138
        LowerFnCall:              &LowerUpperFnc{},
139
        UpperFnCall:              &LowerUpperFnc{isUpper: true},
140
        TrimFnCall:               &TrimFnc{},
141
        NowFnCall:                &NowFn{},
142
        UUIDFnCall:               &UUIDFn{},
143
        JSONTypeOfFnCall:         &JsonTypeOfFn{},
144
        PGGetUserByIDFnCall:          &pgGetUserByIDFunc{},
145
        PgTableIsVisibleFnCall:       &pgTableIsVisible{},
146
        PgShobjDescriptionFnCall:     &pgShobjDescription{},
147
        CurrentDatabaseFnCall:        &pgCurrentDatabase{},
148
        CurrentSchemaFnCall:          &pgCurrentSchema{},
149
        CurrentSchemasFnCall:         &pgCurrentSchemas{},
150
        CurrentUserFnCall:            &pgCurrentUser{},
151
        FormatTypeFnCall:             &pgFormatType{},
152
        PgGetExprFnCall:              &pgVarcharStub{name: PgGetExprFnCall, nParams: -1},
153
        PgGetConstraintDefFnCall:     &pgVarcharStub{name: PgGetConstraintDefFnCall, nParams: -1},
154
        PgGetIndexDefFnCall:          &pgVarcharStub{name: PgGetIndexDefFnCall, nParams: -1},
155
        PgEncodingToCharFnCall:       &pgEncodingToChar{},
156
        ObjDescriptionFnCall:         &pgVarcharStub{name: ObjDescriptionFnCall, nParams: -1},
157
        HasTablePrivilegeFnCall:      &pgBoolStub{name: HasTablePrivilegeFnCall, nParams: -1},
158
        HasSchemaPrivilegeFnCall:     &pgBoolStub{name: HasSchemaPrivilegeFnCall, nParams: -1},
159
        HasDatabasePrivilegeFnCall:   &pgBoolStub{name: HasDatabasePrivilegeFnCall, nParams: -1},
160
        HasFunctionPrivilegeFnCall:   &pgBoolStub{name: HasFunctionPrivilegeFnCall, nParams: -1},
161
        ArrayUpperFnCall:             &pgNullIntStub{name: ArrayUpperFnCall},
162
        ArrayToStringFnCall:          &pgArrayToString{},
163
        QuoteIdentFnCall:             &pgQuoteIdent{},
164
        PgTotalRelationSizeFnCall:    &pgZeroIntStub{name: PgTotalRelationSizeFnCall, nParams: -1},
165
        PgRelationSizeFnCall:         &pgZeroIntStub{name: PgRelationSizeFnCall, nParams: -1},
166
        PgGetSerialSequenceFnCall:    &pgVarcharStub{name: PgGetSerialSequenceFnCall, nParams: -1},
167
        ColDescriptionFnCall:         &pgVarcharStub{name: ColDescriptionFnCall, nParams: -1},
168

169
        // Math functions
170
        AbsFnCall:     &mathFn{name: AbsFnCall},
171
        CeilFnCall:    &mathFn{name: CeilFnCall},
172
        FloorFnCall:   &mathFn{name: FloorFnCall},
173
        RoundFnCall:   &mathFn{name: RoundFnCall},
174
        PowerFnCall:   &mathFn{name: PowerFnCall},
175
        SqrtFnCall:    &mathFn{name: SqrtFnCall},
176
        ModFnCall:     &mathFn{name: ModFnCall},
177
        SignFnCall:    &mathFn{name: SignFnCall},
178

179
        // String functions
180
        ReplaceFnCall:    &replaceFn{},
181
        ReverseFnCall:    &reverseFn{},
182
        LeftFnCall:       &leftRightFn{isRight: false},
183
        RightFnCall:      &leftRightFn{isRight: true},
184
        RepeatFnCall:     &repeatFn{},
185
        PositionFnCall:   &positionFn{},
186
        CharLengthFnCall: &LengthFn{},
187
        OctetLengthFnCall: &LengthFn{},
188

189
        // Conditional functions
190
        NullIfFnCall:   &nullIfFn{},
191
        GreatestFnCall: &greatestLeastFn{isGreatest: true},
192
        LeastFnCall:    &greatestLeastFn{isGreatest: false},
193

194
        // Additional string functions
195
        LpadFnCall:      &padFn{isRight: false},
196
        RpadFnCall:      &padFn{isRight: true},
197
        SplitPartFnCall: &splitPartFn{},
198
        InitcapFnCall:   &initcapFn{},
199
        ChrFnCall:       &chrFn{},
200
        AsciiFnCall:     &asciiFn{},
201
        MD5FnCall:       &md5Fn{},
202
        TranslateFnCall: &translateFn{},
203

204
        // Date/time functions
205
        DateTruncFnCall:      &dateTruncFn{},
206
        ToCharFnCall:         &toCharFn{},
207
        DatePartFnCall:       &datePartFn{},
208
        AgeFnCall:            &ageFn{},
209
        ClockTimestampFnCall: &NowFn{},
210

211
        // Aliases
212
        SubstrFnCall:        &SubstringFn{},
213
        StrposFnCall:        &positionFn{},
214
        ConcatWSFnCall:      &concatWSFn{},
215
        RegexpReplaceFnCall: &regexpReplaceFn{},
216
        NextValFnCall:       &nextValFn{},
217
        CurrValFnCall:       &currValFn{},
218

219
        // Utility functions
220
        RandomFnCall:      &randomFn{},
221
        GenRandomUUIDCall: &UUIDFn{},
222
        ToNumberFnCall:    &toNumberFn{},
223
}
224

225
// RegisteredFunctions returns a snapshot of all built-in functions
226
// keyed by their canonical upper-case name. Callers must not mutate
227
// the returned map. Used by the pg_catalog pg_proc system table to
228
// enumerate callable functions.
229
func RegisteredFunctions() map[string]Function {
3✔
230
        out := make(map[string]Function, len(builtinFunctions))
3✔
231
        for k, v := range builtinFunctions {
228✔
232
                out[k] = v
225✔
233
        }
225✔
234
        return out
3✔
235
}
236

237
type Function interface {
238
        RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error
239
        InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error)
240
        Apply(tx *SQLTx, params []TypedValue) (TypedValue, error)
241
}
242

243
type CoalesceFn struct{}
244

245
func (f *CoalesceFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
246
        return AnyType, nil
6✔
247
}
6✔
248

249
func (f *CoalesceFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
250
        return nil
×
251
}
×
252

253
func (f *CoalesceFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
8✔
254
        t := AnyType
8✔
255

8✔
256
        for _, p := range params {
28✔
257
                if !p.IsNull() {
30✔
258
                        if t == AnyType {
15✔
259
                                t = p.Type()
5✔
260
                        } else if p.Type() != t && !(IsNumericType(t) && IsNumericType(p.Type())) {
11✔
261
                                return nil, fmt.Errorf("coalesce: %w", ErrInvalidTypes)
1✔
262
                        }
1✔
263
                }
264
        }
265

266
        for _, p := range params {
21✔
267
                if !p.IsNull() {
18✔
268
                        return p, nil
4✔
269
                }
4✔
270
        }
271
        return NewNull(t), nil
3✔
272
}
273

274
// -------------------------------------
275
// String Functions
276
// -------------------------------------
277

278
type LengthFn struct{}
279

280
func (f *LengthFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
7✔
281
        return IntegerType, nil
7✔
282
}
7✔
283

284
func (f *LengthFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
285
        if t != IntegerType {
3✔
286
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
1✔
287
        }
1✔
288
        return nil
1✔
289
}
290

291
func (f *LengthFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
9✔
292
        if len(params) != 1 {
10✔
293
                return nil, fmt.Errorf("%w: '%s' function does expects one argument but %d were provided", ErrIllegalArguments, LengthFnCall, len(params))
1✔
294
        }
1✔
295

296
        v := params[0]
8✔
297
        if v.IsNull() {
9✔
298
                return &NullValue{t: IntegerType}, nil
1✔
299
        }
1✔
300

301
        if v.Type() != VarcharType {
8✔
302
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type %s", ErrIllegalArguments, LengthFnCall, VarcharType)
1✔
303
        }
1✔
304

305
        s, _ := v.RawValue().(string)
6✔
306
        return &Integer{val: int64(len(s))}, nil
6✔
307
}
308

309
type ConcatFn struct{}
310

311
func (f *ConcatFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
8✔
312
        return VarcharType, nil
8✔
313
}
8✔
314

315
func (f *ConcatFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
316
        if t != VarcharType {
3✔
317
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
318
        }
1✔
319
        return nil
1✔
320
}
321

322
func (f *ConcatFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
7✔
323
        if len(params) == 0 {
8✔
324
                return nil, fmt.Errorf("%w: '%s' function does expects at least one argument", ErrIllegalArguments, ConcatFnCall)
1✔
325
        }
1✔
326

327
        for _, v := range params {
26✔
328
                if v.Type() != AnyType && v.Type() != VarcharType {
21✔
329
                        return nil, fmt.Errorf("%w: '%s' function doesn't accept arguments of type %s", ErrIllegalArguments, ConcatFnCall, v.Type())
1✔
330
                }
1✔
331
        }
332

333
        var builder strings.Builder
5✔
334
        for _, v := range params {
22✔
335
                s, _ := v.RawValue().(string)
17✔
336
                builder.WriteString(s)
17✔
337
        }
17✔
338
        return &Varchar{val: builder.String()}, nil
5✔
339
}
340

341
type SubstringFn struct {
342
}
343

344
func (f *SubstringFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
345
        return VarcharType, nil
1✔
346
}
1✔
347

348
func (f *SubstringFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
349
        if t != VarcharType {
3✔
350
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
351
        }
1✔
352
        return nil
1✔
353
}
354

355
func (f *SubstringFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
9✔
356
        if len(params) != 3 {
10✔
357
                return nil, fmt.Errorf("%w: '%s' function does expects three argument but %d were provided", ErrIllegalArguments, SubstringFnCall, len(params))
1✔
358
        }
1✔
359

360
        v1, v2, v3 := params[0], params[1], params[2]
8✔
361

8✔
362
        if v1.IsNull() || v2.IsNull() || v3.IsNull() {
9✔
363
                return &NullValue{t: VarcharType}, nil
1✔
364
        }
1✔
365

366
        s, _ := v1.RawValue().(string)
7✔
367
        pos, _ := v2.RawValue().(int64)
7✔
368
        length, _ := v3.RawValue().(int64)
7✔
369

7✔
370
        if pos <= 0 {
8✔
371
                return nil, fmt.Errorf("%w: parameter 'position' must be greater than zero", ErrIllegalArguments)
1✔
372
        }
1✔
373

374
        if length < 0 {
7✔
375
                return nil, fmt.Errorf("%w: parameter 'length' cannot be negative", ErrIllegalArguments)
1✔
376
        }
1✔
377

378
        if pos-1 >= int64(len(s)) {
5✔
379
                return &Varchar{val: ""}, nil
×
380
        }
×
381

382
        end := pos - 1 + length
5✔
383
        if end > int64(len(s)) {
6✔
384
                end = int64(len(s))
1✔
385
        }
1✔
386
        return &Varchar{val: s[pos-1 : end]}, nil
5✔
387
}
388

389
type LowerUpperFnc struct {
390
        isUpper bool
391
}
392

393
func (f *LowerUpperFnc) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
17✔
394
        return VarcharType, nil
17✔
395
}
17✔
396

397
func (f *LowerUpperFnc) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
3✔
398
        if t != VarcharType {
4✔
399
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
400
        }
1✔
401
        return nil
2✔
402
}
403

404
func (f *LowerUpperFnc) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
13✔
405
        if len(params) != 1 {
14✔
406
                return nil, fmt.Errorf("%w: '%s' function does expects one argument but %d were provided", ErrIllegalArguments, f.name(), len(params))
1✔
407
        }
1✔
408

409
        v := params[0]
12✔
410
        if v.IsNull() {
14✔
411
                return &NullValue{t: VarcharType}, nil
2✔
412
        }
2✔
413

414
        if v.Type() != VarcharType {
11✔
415
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type %s", ErrIllegalArguments, f.name(), VarcharType)
1✔
416
        }
1✔
417

418
        s, _ := v.RawValue().(string)
9✔
419

9✔
420
        var res string
9✔
421
        if f.isUpper {
14✔
422
                res = strings.ToUpper(s)
5✔
423
        } else {
9✔
424
                res = strings.ToLower(s)
4✔
425
        }
4✔
426
        return &Varchar{val: res}, nil
9✔
427
}
428

429
func (f *LowerUpperFnc) name() string {
2✔
430
        if f.isUpper {
3✔
431
                return UpperFnCall
1✔
432
        }
1✔
433
        return LowerFnCall
1✔
434
}
435

436
type TrimFnc struct {
437
}
438

439
func (f *TrimFnc) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
440
        return VarcharType, nil
1✔
441
}
1✔
442

443
func (f *TrimFnc) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
444
        if t != VarcharType {
3✔
445
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
446
        }
1✔
447
        return nil
1✔
448
}
449

450
func (f *TrimFnc) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
5✔
451
        if len(params) != 1 {
6✔
452
                return nil, fmt.Errorf("%w: '%s' function does expects one argument but %d were provided", ErrIllegalArguments, TrimFnCall, len(params))
1✔
453
        }
1✔
454

455
        v := params[0]
4✔
456
        if v.IsNull() {
5✔
457
                return &NullValue{t: VarcharType}, nil
1✔
458
        }
1✔
459

460
        if v.Type() != VarcharType {
4✔
461
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type %s", ErrIllegalArguments, TrimFnCall, VarcharType)
1✔
462
        }
1✔
463

464
        s, _ := v.RawValue().(string)
2✔
465
        return &Varchar{val: strings.Trim(s, " \t\n\r\v\f")}, nil
2✔
466
}
467

468
// -------------------------------------
469
// Time Functions
470
// -------------------------------------
471

472
type NowFn struct{}
473

474
func (f *NowFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
18✔
475
        return TimestampType, nil
18✔
476
}
18✔
477

478
func (f *NowFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
4✔
479
        if t != TimestampType {
5✔
480
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, TimestampType, t)
1✔
481
        }
1✔
482
        return nil
3✔
483
}
484

485
func (f *NowFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
98✔
486
        if len(params) > 0 {
99✔
487
                return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, NowFnCall, len(params))
1✔
488
        }
1✔
489
        return &Timestamp{val: tx.Timestamp().Truncate(time.Microsecond).UTC()}, nil
97✔
490
}
491

492
// -------------------------------------
493
// JSON Functions
494
// -------------------------------------
495

496
type JsonTypeOfFn struct{}
497

498
func (f *JsonTypeOfFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
499
        return VarcharType, nil
1✔
500
}
1✔
501

502
func (f *JsonTypeOfFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
503
        if t != VarcharType {
3✔
504
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
505
        }
1✔
506
        return nil
1✔
507
}
508

509
func (f *JsonTypeOfFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
304✔
510
        if len(params) != 1 {
305✔
511
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, JSONTypeOfFnCall, 1, len(params))
1✔
512
        }
1✔
513

514
        v := params[0]
303✔
515
        if v.IsNull() {
304✔
516
                return NewNull(AnyType), nil
1✔
517
        }
1✔
518

519
        jsonVal, ok := v.(*JSON)
302✔
520
        if !ok {
303✔
521
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type JSON", ErrIllegalArguments, JSONTypeOfFnCall)
1✔
522
        }
1✔
523
        return NewVarchar(jsonVal.primitiveType()), nil
301✔
524
}
525

526
// -------------------------------------
527
// UUID Functions
528
// -------------------------------------
529

530
type UUIDFn struct{}
531

532
func (f *UUIDFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
4✔
533
        return UUIDType, nil
4✔
534
}
4✔
535

536
func (f *UUIDFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
537
        if t != UUIDType {
3✔
538
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, UUIDType, t)
1✔
539
        }
1✔
540
        return nil
1✔
541
}
542

543
func (f *UUIDFn) Apply(_ *SQLTx, params []TypedValue) (TypedValue, error) {
7✔
544
        if len(params) > 0 {
8✔
545
                return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, UUIDFnCall, len(params))
1✔
546
        }
1✔
547
        return &UUID{val: uuid.New()}, nil
6✔
548
}
549

550
// pg functions
551

552
type pgGetUserByIDFunc struct{}
553

554
func (f *pgGetUserByIDFunc) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
555
        if t != VarcharType {
3✔
556
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
1✔
557
        }
1✔
558
        return nil
1✔
559
}
560

561
func (f *pgGetUserByIDFunc) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
562
        return VarcharType, nil
1✔
563
}
1✔
564

565
func (f *pgGetUserByIDFunc) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
3✔
566
        if len(params) != 1 {
4✔
567
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, PGGetUserByIDFnCall, 1, len(params))
1✔
568
        }
1✔
569
        if params[0].IsNull() {
2✔
NEW
570
                return NewNull(VarcharType), nil
×
UNCOV
571
        }
×
572

573
        // psql, pgAdmin and Rails all call this with real role oids
574
        // (pg_database.datdba, pg_class.relowner, pg_namespace.nspowner),
575
        // which immudb doesn't track per-user. Return the admin username
576
        // as a stable stand-in — matches the single-role model we expose
577
        // in pg_roles. A nil tx (unit tests exercising Apply directly)
578
        // short-circuits to the "immudb" default.
579
        if tx == nil || tx.tx == nil {
3✔
580
                return NewVarchar("immudb"), nil
1✔
581
        }
1✔
582
        users, err := tx.ListUsers(tx.tx.Context())
1✔
583
        if err != nil || len(users) == 0 {
2✔
584
                return NewVarchar("immudb"), nil
1✔
585
        }
1✔
NEW
586
        if idx := findSysAdmin(users); idx >= 0 {
×
NEW
587
                return NewVarchar(users[idx].Username()), nil
×
588
        }
×
NEW
589
        return NewVarchar("immudb"), nil
×
590
}
591

592
func findSysAdmin(users []User) int {
×
593
        for i, u := range users {
×
594
                if u.Permission() == PermissionSysAdmin {
×
595
                        return i
×
596
                }
×
597
        }
598
        return -1
×
599
}
600

601
type pgTableIsVisible struct{}
602

603
func (f *pgTableIsVisible) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
604
        if t != BooleanType {
3✔
605
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
1✔
606
        }
1✔
607
        return nil
1✔
608
}
609

610
func (f *pgTableIsVisible) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
611
        return BooleanType, nil
1✔
612
}
1✔
613

614
func (f *pgTableIsVisible) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
615
        if len(params) != 1 {
5✔
616
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, PgTableIsVisibleFnCall, 1, len(params))
1✔
617
        }
1✔
618
        return NewBool(true), nil
3✔
619
}
620

621
type pgShobjDescription struct{}
622

623
func (f *pgShobjDescription) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
624
        if t != VarcharType {
3✔
625
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
626
        }
1✔
627
        return nil
1✔
628
}
629

630
func (f *pgShobjDescription) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
631
        return VarcharType, nil
1✔
632
}
1✔
633

634
func (f *pgShobjDescription) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
635
        if len(params) != 2 {
3✔
636
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, PgShobjDescriptionFnCall, 2, len(params))
1✔
637
        }
1✔
638
        return NewVarchar(""), nil
1✔
639
}
640

641
// -------------------------------------
642
// PostgreSQL Compatibility Functions
643
// -------------------------------------
644

645
// current_database() — returns "defaultdb" (immudb default database name)
646
type pgCurrentDatabase struct{}
647

648
func (f *pgCurrentDatabase) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
7✔
649
        return VarcharType, nil
7✔
650
}
7✔
651

NEW
652
func (f *pgCurrentDatabase) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
653
        if t != VarcharType {
×
NEW
654
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
655
        }
×
NEW
656
        return nil
×
657
}
658

659
func (f *pgCurrentDatabase) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
3✔
660
        if len(params) > 0 {
3✔
NEW
661
                return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, CurrentDatabaseFnCall, len(params))
×
NEW
662
        }
×
663
        return NewVarchar("defaultdb"), nil
3✔
664
}
665

666
// current_schema() — returns "public"
667
type pgCurrentSchema struct{}
668

669
func (f *pgCurrentSchema) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
10✔
670
        return VarcharType, nil
10✔
671
}
10✔
672

NEW
673
func (f *pgCurrentSchema) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
674
        if t != VarcharType {
×
NEW
675
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
676
        }
×
NEW
677
        return nil
×
678
}
679

680
func (f *pgCurrentSchema) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
681
        if len(params) > 0 {
4✔
NEW
682
                return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, CurrentSchemaFnCall, len(params))
×
NEW
683
        }
×
684
        return NewVarchar("public"), nil
4✔
685
}
686

687
// current_user — returns the logged-in username
688
type pgCurrentUser struct{}
689

NEW
690
func (f *pgCurrentUser) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
691
        return VarcharType, nil
×
NEW
692
}
×
693

NEW
694
func (f *pgCurrentUser) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
695
        if t != VarcharType {
×
NEW
696
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
697
        }
×
NEW
698
        return nil
×
699
}
700

NEW
701
func (f *pgCurrentUser) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
702
        if len(params) > 0 {
×
NEW
703
                return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, CurrentUserFnCall, len(params))
×
NEW
704
        }
×
705

NEW
706
        users, err := tx.ListUsers(tx.tx.Context())
×
NEW
707
        if err != nil {
×
NEW
708
                return NewVarchar("immudb"), nil
×
NEW
709
        }
×
710

NEW
711
        idx := findSysAdmin(users)
×
NEW
712
        if idx >= 0 {
×
NEW
713
                return NewVarchar(users[idx].Username()), nil
×
NEW
714
        }
×
NEW
715
        return NewVarchar("immudb"), nil
×
716
}
717

718
// format_type(oid, typmod) — maps type OID to type name
719
type pgFormatType struct{}
720

NEW
721
func (f *pgFormatType) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
722
        return VarcharType, nil
×
NEW
723
}
×
724

NEW
725
func (f *pgFormatType) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
726
        if t != VarcharType {
×
NEW
727
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
728
        }
×
NEW
729
        return nil
×
730
}
731

732
// oidToTypeName maps every PG type OID our wire layer advertises
733
// (see pkg/pgsql/sys/types.go pgTypeOIDForSQLType) to a human-
734
// readable type string. format_type uses this to render type
735
// labels in psql's `\d` output; every OID we might emit in
736
// pg_attribute.atttypid needs a row here or psql falls back to the
737
// `unknown (OID=N)` stringification.
738
//
739
// Keep in lockstep with pgTypeOIDForSQLType — if a new immudb type
740
// gets a PG OID there, add a matching row here.
741
var oidToTypeName = map[int64]string{
742
        16:   "boolean",                    // bool
743
        17:   "bytea",                      // bytea
744
        20:   "bigint",                     // int8
745
        21:   "smallint",                   // int2
746
        23:   "integer",                    // int4
747
        25:   "text",                       // text
748
        26:   "oid",                        // oid
749
        114:  "json",                       // json
750
        700:  "real",                       // float4
751
        701:  "double precision",           // float8
752
        1042: "character",                  // bpchar
753
        1043: "character varying",          // varchar — used by every immudb VARCHAR column
754
        1082: "date",                       // date
755
        1083: "time without time zone",     // time
756
        1114: "timestamp without time zone", // timestamp — immudb's TIMESTAMP type
757
        1184: "timestamp with time zone",   // timestamptz
758
        1186: "interval",                   // interval
759
        1700: "numeric",                    // numeric
760
        2950: "uuid",                       // uuid
761
        2276: "any",                        // any (pseudo-type)
762
        3802: "jsonb",                      // jsonb
763
}
764

765
// varcharTypeWithModifier renders a VARCHAR/CHAR type with its
766
// typmod-derived length, matching PG's format_type conventions:
767
//
768
//        format_type(1043, 128) → "character varying(124)"    (typmod = N+4)
769
//        format_type(1043, -1)  → "character varying"
770
//
771
// Real PG uses the "N+4" convention so 0 can signal "unsized".
772
// Our pg_attribute emits typmod = -1 for immudb types (we don't
773
// store PG-style typmods), so the sized form is only reached when
774
// a client-supplied literal typmod arrives.
775
func varcharTypeWithModifier(oid, typmod int64) string {
4✔
776
        base := oidToTypeName[oid]
4✔
777
        if typmod < 0 {
5✔
778
                return base
1✔
779
        }
1✔
780
        if typmod >= 4 {
6✔
781
                return fmt.Sprintf("%s(%d)", base, typmod-4)
3✔
782
        }
3✔
NEW
783
        return fmt.Sprintf("%s(%d)", base, typmod)
×
784
}
785

786
func (f *pgFormatType) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
15✔
787
        if len(params) != 2 {
15✔
NEW
788
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, FormatTypeFnCall, 2, len(params))
×
NEW
789
        }
×
790

791
        if params[0].IsNull() {
15✔
NEW
792
                return NewNull(VarcharType), nil
×
NEW
793
        }
×
794

795
        oid, ok := params[0].RawValue().(int64)
15✔
796
        if !ok {
15✔
NEW
797
                return NewVarchar("???"), nil
×
NEW
798
        }
×
799

800
        name, exists := oidToTypeName[oid]
15✔
801
        if !exists {
15✔
NEW
802
                return NewVarchar(fmt.Sprintf("unknown (OID=%d)", oid)), nil
×
NEW
803
        }
×
804
        // Only VARCHAR / CHAR carry a meaningful typmod. Every other
805
        // type ignores the second argument, matching PG behaviour.
806
        if oid == 1043 || oid == 1042 {
19✔
807
                if !params[1].IsNull() {
8✔
808
                        if typmod, ok := params[1].RawValue().(int64); ok {
8✔
809
                                return NewVarchar(varcharTypeWithModifier(oid, typmod)), nil
4✔
810
                        }
4✔
811
                }
812
        }
813
        return NewVarchar(name), nil
11✔
814
}
815

816
// pg_encoding_to_char(encoding_id) — returns encoding name
817
type pgEncodingToChar struct{}
818

NEW
819
func (f *pgEncodingToChar) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
820
        return VarcharType, nil
×
NEW
821
}
×
822

NEW
823
func (f *pgEncodingToChar) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
824
        if t != VarcharType {
×
NEW
825
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
826
        }
×
NEW
827
        return nil
×
828
}
829

830
func (f *pgEncodingToChar) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
1✔
831
        if len(params) != 1 {
1✔
NEW
832
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, PgEncodingToCharFnCall, 1, len(params))
×
NEW
833
        }
×
834
        return NewVarchar("UTF8"), nil
1✔
835
}
836

837
// pgVarcharStub — generic stub that returns empty string for any PG function.
838
// nParams=-1 means accept any number of parameters.
839
type pgVarcharStub struct {
840
        name    string
841
        nParams int
842
}
843

NEW
844
func (f *pgVarcharStub) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
845
        return VarcharType, nil
×
NEW
846
}
×
847

NEW
848
func (f *pgVarcharStub) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
849
        if t != VarcharType {
×
NEW
850
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
851
        }
×
NEW
852
        return nil
×
853
}
854

NEW
855
func (f *pgVarcharStub) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
856
        if f.nParams >= 0 && len(params) != f.nParams {
×
NEW
857
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, f.name, f.nParams, len(params))
×
NEW
858
        }
×
NEW
859
        return NewVarchar(""), nil
×
860
}
861

862
// pgBoolStub — generic stub that returns true for any PG privilege-check function.
863
// nParams=-1 means accept any number of parameters.
864
type pgBoolStub struct {
865
        name    string
866
        nParams int
867
}
868

NEW
869
func (f *pgBoolStub) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
870
        return BooleanType, nil
×
NEW
871
}
×
872

NEW
873
func (f *pgBoolStub) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
874
        if t != BooleanType {
×
NEW
875
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
×
NEW
876
        }
×
NEW
877
        return nil
×
878
}
879

880
func (f *pgBoolStub) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
881
        if f.nParams >= 0 && len(params) != f.nParams {
4✔
NEW
882
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, f.name, f.nParams, len(params))
×
NEW
883
        }
×
884
        return NewBool(true), nil
4✔
885
}
886

887
// pgNullIntStub — returns NULL integer (for array_upper etc.)
888
type pgNullIntStub struct {
889
        name string
890
}
891

NEW
892
func (f *pgNullIntStub) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
893
        return IntegerType, nil
×
NEW
894
}
×
895

NEW
896
func (f *pgNullIntStub) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
897
        if t != IntegerType {
×
NEW
898
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
×
NEW
899
        }
×
NEW
900
        return nil
×
901
}
902

NEW
903
func (f *pgNullIntStub) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
904
        return NewNull(IntegerType), nil
×
NEW
905
}
×
906

907
// pgZeroIntStub — returns integer 0, used for pg_*_size functions which
908
// psql calls from \d+ to render size columns. Returning 0 rather than
909
// NULL keeps psql's formatting happy (NULL→`—`, 0→`0 bytes`).
910
type pgZeroIntStub struct {
911
        name    string
912
        nParams int
913
}
914

NEW
915
func (f *pgZeroIntStub) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
916
        return IntegerType, nil
×
NEW
917
}
×
918

NEW
919
func (f *pgZeroIntStub) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
920
        if t != IntegerType {
×
NEW
921
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
×
NEW
922
        }
×
NEW
923
        return nil
×
924
}
925

926
func (f *pgZeroIntStub) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
927
        if f.nParams >= 0 && len(params) != f.nParams {
2✔
NEW
928
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, f.name, f.nParams, len(params))
×
NEW
929
        }
×
930
        return NewInteger(0), nil
2✔
931
}
932

933
// current_schemas(include_implicit bool) — returns the search path as a
934
// PG array literal. PG returns text[], but the SQL engine has no array
935
// type; we hand back a VARCHAR formatted as `{pg_catalog,public}` so
936
// that array_to_string can round-trip it and naive clients see something
937
// sensible. include_implicit=true prepends `pg_catalog` to match PG's
938
// documented behaviour.
939
type pgCurrentSchemas struct{}
940

NEW
941
func (f *pgCurrentSchemas) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
942
        return VarcharType, nil
×
NEW
943
}
×
944

NEW
945
func (f *pgCurrentSchemas) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
946
        if t != VarcharType {
×
NEW
947
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
948
        }
×
NEW
949
        return nil
×
950
}
951

952
func (f *pgCurrentSchemas) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
953
        if len(params) != 1 {
2✔
NEW
954
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, CurrentSchemasFnCall, 1, len(params))
×
NEW
955
        }
×
956
        include := false
2✔
957
        if !params[0].IsNull() {
4✔
958
                if b, ok := params[0].RawValue().(bool); ok {
4✔
959
                        include = b
2✔
960
                }
2✔
961
        }
962
        if include {
3✔
963
                return NewVarchar("{pg_catalog,public}"), nil
1✔
964
        }
1✔
965
        return NewVarchar("{public}"), nil
1✔
966
}
967

968
// quote_ident(name) — wraps an identifier in double quotes if it
969
// contains anything outside [a-z_][a-z0-9_]* or matches a short list of
970
// SQL reserved words. Embedded double quotes are doubled. A permissive
971
// implementation is fine here: psql and Rails only use the return value
972
// for display and DDL rendering, not to re-parse user input.
973
type pgQuoteIdent struct{}
974

NEW
975
func (f *pgQuoteIdent) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
976
        return VarcharType, nil
×
NEW
977
}
×
978

NEW
979
func (f *pgQuoteIdent) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
980
        if t != VarcharType {
×
NEW
981
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
982
        }
×
NEW
983
        return nil
×
984
}
985

986
var quoteIdentReservedWords = map[string]struct{}{
987
        "select": {}, "from": {}, "where": {}, "join": {}, "order": {},
988
        "group": {}, "by": {}, "insert": {}, "update": {}, "delete": {},
989
        "create": {}, "table": {}, "index": {}, "view": {}, "user": {},
990
        "database": {}, "schema": {}, "grant": {}, "revoke": {}, "as": {},
991
}
992

993
func quoteIdentNeedsQuoting(s string) bool {
5✔
994
        if s == "" {
5✔
NEW
995
                return true
×
NEW
996
        }
×
997
        if _, reserved := quoteIdentReservedWords[strings.ToLower(s)]; reserved {
6✔
998
                return true
1✔
999
        }
1✔
1000
        for i, r := range s {
17✔
1001
                if i == 0 {
17✔
1002
                        if !(r == '_' || (r >= 'a' && r <= 'z')) {
5✔
1003
                                return true
1✔
1004
                        }
1✔
1005
                        continue
3✔
1006
                }
1007
                if !(r == '_' || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9')) {
11✔
1008
                        return true
2✔
1009
                }
2✔
1010
        }
1011
        return false
1✔
1012
}
1013

1014
func (f *pgQuoteIdent) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
5✔
1015
        if len(params) != 1 {
5✔
NEW
1016
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, QuoteIdentFnCall, 1, len(params))
×
NEW
1017
        }
×
1018
        if params[0].IsNull() {
5✔
NEW
1019
                return NewNull(VarcharType), nil
×
NEW
1020
        }
×
1021
        s, _ := params[0].RawValue().(string)
5✔
1022
        if !quoteIdentNeedsQuoting(s) {
6✔
1023
                return NewVarchar(s), nil
1✔
1024
        }
1✔
1025
        return NewVarchar(`"` + strings.ReplaceAll(s, `"`, `""`) + `"`), nil
4✔
1026
}
1027

1028
// array_to_string(array_literal, delim[, null_repr]) — joins the
1029
// elements of a PG array literal (text form: `{a,b,c}`) with delim.
1030
// Real PG arrays aren't representable in the engine today, so this
1031
// function accepts the VARCHAR stand-in emitted by current_schemas and
1032
// any other source that follows the curly-brace text convention. When
1033
// the argument isn't in that shape we pass it through unchanged —
1034
// that's what psql's callers expect when the "array" only has one
1035
// element and the server happened to render it as a bare scalar.
1036
type pgArrayToString struct{}
1037

NEW
1038
func (f *pgArrayToString) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1039
        return VarcharType, nil
×
NEW
1040
}
×
1041

NEW
1042
func (f *pgArrayToString) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1043
        if t != VarcharType {
×
NEW
1044
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1045
        }
×
NEW
1046
        return nil
×
1047
}
1048

1049
func (f *pgArrayToString) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1050
        if len(params) < 2 || len(params) > 3 {
4✔
NEW
1051
                return nil, fmt.Errorf("%w: '%s' function expects 2 or 3 arguments but %d were provided", ErrIllegalArguments, ArrayToStringFnCall, len(params))
×
NEW
1052
        }
×
1053
        if params[0].IsNull() {
4✔
NEW
1054
                return NewNull(VarcharType), nil
×
NEW
1055
        }
×
1056
        raw, _ := params[0].RawValue().(string)
4✔
1057
        delim := ""
4✔
1058
        if !params[1].IsNull() {
8✔
1059
                delim, _ = params[1].RawValue().(string)
4✔
1060
        }
4✔
1061
        // Curly-brace PG array literal → strip the braces and re-join.
1062
        if len(raw) >= 2 && raw[0] == '{' && raw[len(raw)-1] == '}' {
7✔
1063
                inner := raw[1 : len(raw)-1]
3✔
1064
                if inner == "" {
4✔
1065
                        return NewVarchar(""), nil
1✔
1066
                }
1✔
1067
                parts := strings.Split(inner, ",")
2✔
1068
                return NewVarchar(strings.Join(parts, delim)), nil
2✔
1069
        }
1070
        return NewVarchar(raw), nil
1✔
1071
}
1072

1073
// -------------------------------------
1074
// Math Functions
1075
// -------------------------------------
1076

1077
type mathFn struct {
1078
        name string
1079
}
1080

1081
func (f *mathFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
11✔
1082
        return Float64Type, nil
11✔
1083
}
11✔
1084

NEW
1085
func (f *mathFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1086
        if t != Float64Type && t != IntegerType {
×
NEW
1087
                return fmt.Errorf("%w: %v can not be interpreted as numeric type", ErrInvalidTypes, t)
×
NEW
1088
        }
×
NEW
1089
        return nil
×
1090
}
1091

1092
func (f *mathFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
9✔
1093
        switch f.name {
9✔
1094
        case AbsFnCall:
4✔
1095
                if len(params) != 1 {
4✔
NEW
1096
                        return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, f.name)
×
NEW
1097
                }
×
1098
                return f.applyUnary(params[0], math.Abs)
4✔
1099
        case CeilFnCall:
2✔
1100
                if len(params) != 1 {
2✔
NEW
1101
                        return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, f.name)
×
NEW
1102
                }
×
1103
                return f.applyUnary(params[0], math.Ceil)
2✔
1104
        case FloorFnCall:
1✔
1105
                if len(params) != 1 {
1✔
NEW
1106
                        return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, f.name)
×
NEW
1107
                }
×
1108
                return f.applyUnary(params[0], math.Floor)
1✔
1109
        case RoundFnCall:
2✔
1110
                if len(params) != 1 {
2✔
NEW
1111
                        return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, f.name)
×
NEW
1112
                }
×
1113
                return f.applyUnary(params[0], math.Round)
2✔
NEW
1114
        case SqrtFnCall:
×
NEW
1115
                if len(params) != 1 {
×
NEW
1116
                        return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, f.name)
×
NEW
1117
                }
×
NEW
1118
                return f.applyUnary(params[0], math.Sqrt)
×
NEW
1119
        case SignFnCall:
×
NEW
1120
                if len(params) != 1 {
×
NEW
1121
                        return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, f.name)
×
NEW
1122
                }
×
NEW
1123
                return f.applyUnary(params[0], func(v float64) float64 {
×
NEW
1124
                        if v > 0 {
×
NEW
1125
                                return 1
×
NEW
1126
                        }
×
NEW
1127
                        if v < 0 {
×
NEW
1128
                                return -1
×
NEW
1129
                        }
×
NEW
1130
                        return 0
×
1131
                })
NEW
1132
        case PowerFnCall:
×
NEW
1133
                if len(params) != 2 {
×
NEW
1134
                        return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, f.name)
×
NEW
1135
                }
×
NEW
1136
                return f.applyBinary(params[0], params[1], math.Pow)
×
NEW
1137
        case ModFnCall:
×
NEW
1138
                if len(params) != 2 {
×
NEW
1139
                        return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, f.name)
×
NEW
1140
                }
×
NEW
1141
                return f.applyBinary(params[0], params[1], math.Mod)
×
NEW
1142
        default:
×
NEW
1143
                return nil, fmt.Errorf("%w: unknown math function '%s'", ErrIllegalArguments, f.name)
×
1144
        }
1145
}
1146

1147
func (f *mathFn) applyUnary(p TypedValue, fn func(float64) float64) (TypedValue, error) {
9✔
1148
        if p.IsNull() {
9✔
NEW
1149
                return NewNull(Float64Type), nil
×
NEW
1150
        }
×
1151

1152
        var v float64
9✔
1153
        switch raw := p.RawValue().(type) {
9✔
1154
        case int64:
4✔
1155
                v = float64(raw)
4✔
1156
        case float64:
5✔
1157
                v = raw
5✔
NEW
1158
        default:
×
NEW
1159
                return nil, fmt.Errorf("%w: '%s' expects a numeric argument", ErrIllegalArguments, f.name)
×
1160
        }
1161
        return NewFloat64(fn(v)), nil
9✔
1162
}
1163

NEW
1164
func (f *mathFn) applyBinary(a, b TypedValue, fn func(float64, float64) float64) (TypedValue, error) {
×
NEW
1165
        if a.IsNull() || b.IsNull() {
×
NEW
1166
                return NewNull(Float64Type), nil
×
NEW
1167
        }
×
1168

NEW
1169
        var va, vb float64
×
NEW
1170
        switch raw := a.RawValue().(type) {
×
NEW
1171
        case int64:
×
NEW
1172
                va = float64(raw)
×
NEW
1173
        case float64:
×
NEW
1174
                va = raw
×
NEW
1175
        default:
×
NEW
1176
                return nil, fmt.Errorf("%w: '%s' expects numeric arguments", ErrIllegalArguments, f.name)
×
1177
        }
NEW
1178
        switch raw := b.RawValue().(type) {
×
NEW
1179
        case int64:
×
NEW
1180
                vb = float64(raw)
×
NEW
1181
        case float64:
×
NEW
1182
                vb = raw
×
NEW
1183
        default:
×
NEW
1184
                return nil, fmt.Errorf("%w: '%s' expects numeric arguments", ErrIllegalArguments, f.name)
×
1185
        }
NEW
1186
        return NewFloat64(fn(va, vb)), nil
×
1187
}
1188

1189
// -------------------------------------
1190
// Additional String Functions
1191
// -------------------------------------
1192

1193
type replaceFn struct{}
1194

1195
func (f *replaceFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
1196
        return VarcharType, nil
6✔
1197
}
6✔
NEW
1198
func (f *replaceFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1199
        if t != VarcharType {
×
NEW
1200
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1201
        }
×
NEW
1202
        return nil
×
1203
}
1204
func (f *replaceFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
3✔
1205
        if len(params) != 3 {
3✔
NEW
1206
                return nil, fmt.Errorf("%w: '%s' expects 3 arguments", ErrIllegalArguments, ReplaceFnCall)
×
NEW
1207
        }
×
1208
        if params[0].IsNull() {
3✔
NEW
1209
                return NewNull(VarcharType), nil
×
NEW
1210
        }
×
1211
        s, _ := params[0].RawValue().(string)
3✔
1212
        old, _ := params[1].RawValue().(string)
3✔
1213
        new, _ := params[2].RawValue().(string)
3✔
1214
        return NewVarchar(strings.ReplaceAll(s, old, new)), nil
3✔
1215
}
1216

1217
type reverseFn struct{}
1218

1219
func (f *reverseFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
1220
        return VarcharType, nil
6✔
1221
}
6✔
NEW
1222
func (f *reverseFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1223
        if t != VarcharType {
×
NEW
1224
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1225
        }
×
NEW
1226
        return nil
×
1227
}
1228
func (f *reverseFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
3✔
1229
        if len(params) != 1 {
3✔
NEW
1230
                return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, ReverseFnCall)
×
NEW
1231
        }
×
1232
        if params[0].IsNull() {
3✔
NEW
1233
                return NewNull(VarcharType), nil
×
NEW
1234
        }
×
1235
        s, _ := params[0].RawValue().(string)
3✔
1236
        runes := []rune(s)
3✔
1237
        for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
9✔
1238
                runes[i], runes[j] = runes[j], runes[i]
6✔
1239
        }
6✔
1240
        return NewVarchar(string(runes)), nil
3✔
1241
}
1242

1243
type leftRightFn struct {
1244
        isRight bool
1245
}
1246

NEW
1247
func (f *leftRightFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1248
        return VarcharType, nil
×
NEW
1249
}
×
NEW
1250
func (f *leftRightFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1251
        if t != VarcharType {
×
NEW
1252
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1253
        }
×
NEW
1254
        return nil
×
1255
}
NEW
1256
func (f *leftRightFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
1257
        if len(params) != 2 {
×
NEW
1258
                return nil, fmt.Errorf("%w: function expects 2 arguments", ErrIllegalArguments)
×
NEW
1259
        }
×
NEW
1260
        if params[0].IsNull() || params[1].IsNull() {
×
NEW
1261
                return NewNull(VarcharType), nil
×
NEW
1262
        }
×
NEW
1263
        s, _ := params[0].RawValue().(string)
×
NEW
1264
        n, _ := params[1].RawValue().(int64)
×
NEW
1265
        if n < 0 {
×
NEW
1266
                n = 0
×
NEW
1267
        }
×
NEW
1268
        if int(n) > len(s) {
×
NEW
1269
                return NewVarchar(s), nil
×
NEW
1270
        }
×
NEW
1271
        if f.isRight {
×
NEW
1272
                return NewVarchar(s[len(s)-int(n):]), nil
×
NEW
1273
        }
×
NEW
1274
        return NewVarchar(s[:int(n)]), nil
×
1275
}
1276

1277
type repeatFn struct{}
1278

1279
func (f *repeatFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
3✔
1280
        return VarcharType, nil
3✔
1281
}
3✔
NEW
1282
func (f *repeatFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1283
        if t != VarcharType {
×
NEW
1284
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1285
        }
×
NEW
1286
        return nil
×
1287
}
1288
func (f *repeatFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
1289
        if len(params) != 2 {
2✔
NEW
1290
                return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, RepeatFnCall)
×
NEW
1291
        }
×
1292
        if params[0].IsNull() || params[1].IsNull() {
2✔
NEW
1293
                return NewNull(VarcharType), nil
×
NEW
1294
        }
×
1295
        s, _ := params[0].RawValue().(string)
2✔
1296
        n, _ := params[1].RawValue().(int64)
2✔
1297
        if n <= 0 {
2✔
NEW
1298
                return NewVarchar(""), nil
×
NEW
1299
        }
×
1300
        return NewVarchar(strings.Repeat(s, int(n))), nil
2✔
1301
}
1302

1303
type positionFn struct{}
1304

NEW
1305
func (f *positionFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1306
        return IntegerType, nil
×
NEW
1307
}
×
NEW
1308
func (f *positionFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1309
        if t != IntegerType {
×
NEW
1310
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
×
NEW
1311
        }
×
NEW
1312
        return nil
×
1313
}
1314
func (f *positionFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
1✔
1315
        if len(params) != 2 {
1✔
NEW
1316
                return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, PositionFnCall)
×
NEW
1317
        }
×
1318
        if params[0].IsNull() || params[1].IsNull() {
1✔
NEW
1319
                return NewNull(IntegerType), nil
×
NEW
1320
        }
×
1321
        substr, _ := params[0].RawValue().(string)
1✔
1322
        s, _ := params[1].RawValue().(string)
1✔
1323
        pos := strings.Index(s, substr)
1✔
1324
        if pos < 0 {
1✔
NEW
1325
                return NewInteger(0), nil
×
NEW
1326
        }
×
1327
        return NewInteger(int64(pos + 1)), nil // 1-based
1✔
1328
}
1329

1330
// -------------------------------------
1331
// Conditional Functions
1332
// -------------------------------------
1333

1334
type nullIfFn struct{}
1335

1336
func (f *nullIfFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
3✔
1337
        return AnyType, nil
3✔
1338
}
3✔
NEW
1339
func (f *nullIfFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1340
        return nil
×
NEW
1341
}
×
1342
func (f *nullIfFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
3✔
1343
        if len(params) != 2 {
3✔
NEW
1344
                return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, NullIfFnCall)
×
NEW
1345
        }
×
1346
        r, err := params[0].Compare(params[1])
3✔
1347
        if err != nil {
3✔
NEW
1348
                return params[0], nil
×
NEW
1349
        }
×
1350
        if r == 0 {
5✔
1351
                return NewNull(params[0].Type()), nil
2✔
1352
        }
2✔
1353
        return params[0], nil
1✔
1354
}
1355

1356
type greatestLeastFn struct {
1357
        isGreatest bool
1358
}
1359

1360
func (f *greatestLeastFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
8✔
1361
        return AnyType, nil
8✔
1362
}
8✔
NEW
1363
func (f *greatestLeastFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1364
        return nil
×
NEW
1365
}
×
1366
func (f *greatestLeastFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
6✔
1367
        if len(params) == 0 {
6✔
NEW
1368
                return nil, fmt.Errorf("%w: function expects at least 1 argument", ErrIllegalArguments)
×
NEW
1369
        }
×
1370
        result := params[0]
6✔
1371
        for _, p := range params[1:] {
18✔
1372
                if result.IsNull() {
12✔
NEW
1373
                        result = p
×
NEW
1374
                        continue
×
1375
                }
1376
                if p.IsNull() {
12✔
NEW
1377
                        continue
×
1378
                }
1379
                cmp, err := result.Compare(p)
12✔
1380
                if err != nil {
12✔
NEW
1381
                        continue
×
1382
                }
1383
                if (f.isGreatest && cmp < 0) || (!f.isGreatest && cmp > 0) {
16✔
1384
                        result = p
4✔
1385
                }
4✔
1386
        }
1387
        return result, nil
6✔
1388
}
1389

1390
// -------------------------------------
1391
// Additional String Functions
1392
// -------------------------------------
1393

1394
type padFn struct {
1395
        isRight bool
1396
}
1397

1398
func (f *padFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
1399
        return VarcharType, nil
6✔
1400
}
6✔
NEW
1401
func (f *padFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1402
        if t != VarcharType {
×
NEW
1403
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1404
        }
×
NEW
1405
        return nil
×
1406
}
1407
func (f *padFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
6✔
1408
        if len(params) < 2 || len(params) > 3 {
6✔
NEW
1409
                return nil, fmt.Errorf("%w: LPAD/RPAD expects 2-3 arguments", ErrIllegalArguments)
×
NEW
1410
        }
×
1411
        if params[0].IsNull() {
6✔
NEW
1412
                return NewNull(VarcharType), nil
×
NEW
1413
        }
×
1414
        s, _ := params[0].RawValue().(string)
6✔
1415
        length, _ := params[1].RawValue().(int64)
6✔
1416
        fill := " "
6✔
1417
        if len(params) == 3 {
12✔
1418
                fill, _ = params[2].RawValue().(string)
6✔
1419
        }
6✔
1420
        if fill == "" {
6✔
NEW
1421
                fill = " "
×
NEW
1422
        }
×
1423
        for int64(len(s)) < length {
24✔
1424
                if f.isRight {
24✔
1425
                        s = s + fill
6✔
1426
                } else {
18✔
1427
                        s = fill + s
12✔
1428
                }
12✔
1429
        }
1430
        if int64(len(s)) > length {
6✔
NEW
1431
                s = s[:length]
×
NEW
1432
        }
×
1433
        return NewVarchar(s), nil
6✔
1434
}
1435

1436
type splitPartFn struct{}
1437

1438
func (f *splitPartFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
4✔
1439
        return VarcharType, nil
4✔
1440
}
4✔
NEW
1441
func (f *splitPartFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1442
        if t != VarcharType {
×
NEW
1443
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1444
        }
×
NEW
1445
        return nil
×
1446
}
1447
func (f *splitPartFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1448
        if len(params) != 3 {
4✔
NEW
1449
                return nil, fmt.Errorf("%w: '%s' expects 3 arguments", ErrIllegalArguments, SplitPartFnCall)
×
NEW
1450
        }
×
1451
        if params[0].IsNull() {
4✔
NEW
1452
                return NewNull(VarcharType), nil
×
NEW
1453
        }
×
1454
        s, _ := params[0].RawValue().(string)
4✔
1455
        delim, _ := params[1].RawValue().(string)
4✔
1456
        n, _ := params[2].RawValue().(int64)
4✔
1457
        parts := strings.Split(s, delim)
4✔
1458
        if n < 1 || int(n) > len(parts) {
4✔
NEW
1459
                return NewVarchar(""), nil
×
NEW
1460
        }
×
1461
        return NewVarchar(parts[n-1]), nil
4✔
1462
}
1463

1464
type initcapFn struct{}
1465

1466
func (f *initcapFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
1467
        return VarcharType, nil
6✔
1468
}
6✔
NEW
1469
func (f *initcapFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1470
        if t != VarcharType {
×
NEW
1471
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1472
        }
×
NEW
1473
        return nil
×
1474
}
1475
func (f *initcapFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1476
        if len(params) != 1 {
4✔
NEW
1477
                return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, InitcapFnCall)
×
NEW
1478
        }
×
1479
        if params[0].IsNull() {
4✔
NEW
1480
                return NewNull(VarcharType), nil
×
NEW
1481
        }
×
1482
        s, _ := params[0].RawValue().(string)
4✔
1483
        runes := []rune(strings.ToLower(s))
4✔
1484
        inWord := false
4✔
1485
        for i, r := range runes {
48✔
1486
                if unicode.IsLetter(r) || unicode.IsDigit(r) {
84✔
1487
                        if !inWord {
48✔
1488
                                runes[i] = unicode.ToUpper(r)
8✔
1489
                                inWord = true
8✔
1490
                        }
8✔
1491
                } else {
4✔
1492
                        inWord = false
4✔
1493
                }
4✔
1494
        }
1495
        return NewVarchar(string(runes)), nil
4✔
1496
}
1497

1498
type chrFn struct{}
1499

1500
func (f *chrFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
4✔
1501
        return VarcharType, nil
4✔
1502
}
4✔
NEW
1503
func (f *chrFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1504
        if t != VarcharType {
×
NEW
1505
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1506
        }
×
NEW
1507
        return nil
×
1508
}
1509
func (f *chrFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1510
        if len(params) != 1 {
4✔
NEW
1511
                return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, ChrFnCall)
×
NEW
1512
        }
×
1513
        if params[0].IsNull() {
4✔
NEW
1514
                return NewNull(VarcharType), nil
×
NEW
1515
        }
×
1516
        code, _ := params[0].RawValue().(int64)
4✔
1517
        return NewVarchar(string(rune(code))), nil
4✔
1518
}
1519

1520
type asciiFn struct{}
1521

1522
func (f *asciiFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
4✔
1523
        return IntegerType, nil
4✔
1524
}
4✔
NEW
1525
func (f *asciiFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1526
        if t != IntegerType {
×
NEW
1527
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
×
NEW
1528
        }
×
NEW
1529
        return nil
×
1530
}
1531
func (f *asciiFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1532
        if len(params) != 1 {
4✔
NEW
1533
                return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, AsciiFnCall)
×
NEW
1534
        }
×
1535
        if params[0].IsNull() {
4✔
NEW
1536
                return NewNull(IntegerType), nil
×
NEW
1537
        }
×
1538
        s, _ := params[0].RawValue().(string)
4✔
1539
        if len(s) == 0 {
4✔
NEW
1540
                return NewInteger(0), nil
×
NEW
1541
        }
×
1542
        return NewInteger(int64(s[0])), nil
4✔
1543
}
1544

1545
type md5Fn struct{}
1546

1547
func (f *md5Fn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
1548
        return VarcharType, nil
6✔
1549
}
6✔
NEW
1550
func (f *md5Fn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1551
        if t != VarcharType {
×
NEW
1552
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1553
        }
×
NEW
1554
        return nil
×
1555
}
1556
func (f *md5Fn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1557
        if len(params) != 1 {
4✔
NEW
1558
                return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, MD5FnCall)
×
NEW
1559
        }
×
1560
        if params[0].IsNull() {
4✔
NEW
1561
                return NewNull(VarcharType), nil
×
NEW
1562
        }
×
1563
        s, _ := params[0].RawValue().(string)
4✔
1564
        hash := md5.Sum([]byte(s))
4✔
1565
        return NewVarchar(hex.EncodeToString(hash[:])), nil
4✔
1566
}
1567

1568
type translateFn struct{}
1569

NEW
1570
func (f *translateFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1571
        return VarcharType, nil
×
NEW
1572
}
×
NEW
1573
func (f *translateFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1574
        if t != VarcharType {
×
NEW
1575
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1576
        }
×
NEW
1577
        return nil
×
1578
}
1579
func (f *translateFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
1✔
1580
        if len(params) != 3 {
1✔
NEW
1581
                return nil, fmt.Errorf("%w: '%s' expects 3 arguments", ErrIllegalArguments, TranslateFnCall)
×
NEW
1582
        }
×
1583
        if params[0].IsNull() {
1✔
NEW
1584
                return NewNull(VarcharType), nil
×
NEW
1585
        }
×
1586
        s, _ := params[0].RawValue().(string)
1✔
1587
        from, _ := params[1].RawValue().(string)
1✔
1588
        to, _ := params[2].RawValue().(string)
1✔
1589
        fromRunes := []rune(from)
1✔
1590
        toRunes := []rune(to)
1✔
1591
        mapping := make(map[rune]rune)
1✔
1592
        for i, r := range fromRunes {
3✔
1593
                if i < len(toRunes) {
4✔
1594
                        mapping[r] = toRunes[i]
2✔
1595
                } else {
2✔
NEW
1596
                        mapping[r] = -1 // delete
×
NEW
1597
                }
×
1598
        }
1599
        var result []rune
1✔
1600
        for _, r := range s {
6✔
1601
                if repl, ok := mapping[r]; ok {
8✔
1602
                        if repl != -1 {
6✔
1603
                                result = append(result, repl)
3✔
1604
                        }
3✔
1605
                } else {
2✔
1606
                        result = append(result, r)
2✔
1607
                }
2✔
1608
        }
1609
        return NewVarchar(string(result)), nil
1✔
1610
}
1611

1612
// -------------------------------------
1613
// Date/Time Functions
1614
// -------------------------------------
1615

1616
type dateTruncFn struct{}
1617

NEW
1618
func (f *dateTruncFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1619
        return TimestampType, nil
×
NEW
1620
}
×
NEW
1621
func (f *dateTruncFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1622
        if t != TimestampType {
×
NEW
1623
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, TimestampType, t)
×
NEW
1624
        }
×
NEW
1625
        return nil
×
1626
}
NEW
1627
func (f *dateTruncFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
1628
        if len(params) != 2 {
×
NEW
1629
                return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, DateTruncFnCall)
×
NEW
1630
        }
×
NEW
1631
        if params[0].IsNull() || params[1].IsNull() {
×
NEW
1632
                return NewNull(TimestampType), nil
×
NEW
1633
        }
×
NEW
1634
        field, _ := params[0].RawValue().(string)
×
NEW
1635
        ts, ok := params[1].RawValue().(time.Time)
×
NEW
1636
        if !ok {
×
NEW
1637
                return NewNull(TimestampType), nil
×
NEW
1638
        }
×
NEW
1639
        ts = ts.UTC()
×
NEW
1640
        switch strings.ToLower(field) {
×
NEW
1641
        case "year":
×
NEW
1642
                ts = time.Date(ts.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
×
NEW
1643
        case "month":
×
NEW
1644
                ts = time.Date(ts.Year(), ts.Month(), 1, 0, 0, 0, 0, time.UTC)
×
NEW
1645
        case "day":
×
NEW
1646
                ts = time.Date(ts.Year(), ts.Month(), ts.Day(), 0, 0, 0, 0, time.UTC)
×
NEW
1647
        case "hour":
×
NEW
1648
                ts = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), 0, 0, 0, time.UTC)
×
NEW
1649
        case "minute":
×
NEW
1650
                ts = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Minute(), 0, 0, time.UTC)
×
NEW
1651
        case "second":
×
NEW
1652
                ts = time.Date(ts.Year(), ts.Month(), ts.Day(), ts.Hour(), ts.Minute(), ts.Second(), 0, time.UTC)
×
1653
        }
NEW
1654
        return &Timestamp{val: ts}, nil
×
1655
}
1656

1657
type toCharFn struct{}
1658

NEW
1659
func (f *toCharFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1660
        return VarcharType, nil
×
NEW
1661
}
×
NEW
1662
func (f *toCharFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1663
        if t != VarcharType {
×
NEW
1664
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1665
        }
×
NEW
1666
        return nil
×
1667
}
NEW
1668
func (f *toCharFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
1669
        if len(params) != 2 {
×
NEW
1670
                return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, ToCharFnCall)
×
NEW
1671
        }
×
NEW
1672
        if params[0].IsNull() {
×
NEW
1673
                return NewNull(VarcharType), nil
×
NEW
1674
        }
×
NEW
1675
        ts, ok := params[0].RawValue().(time.Time)
×
NEW
1676
        if !ok {
×
NEW
1677
                // For non-timestamp values, just return string representation
×
NEW
1678
                return NewVarchar(fmt.Sprintf("%v", params[0].RawValue())), nil
×
NEW
1679
        }
×
NEW
1680
        format, _ := params[1].RawValue().(string)
×
NEW
1681
        // Convert PG format to Go format
×
NEW
1682
        result := pgFormatToGo(format, ts)
×
NEW
1683
        return NewVarchar(result), nil
×
1684
}
1685

NEW
1686
func pgFormatToGo(pgFmt string, ts time.Time) string {
×
NEW
1687
        r := strings.NewReplacer(
×
NEW
1688
                "YYYY", fmt.Sprintf("%04d", ts.Year()),
×
NEW
1689
                "YY", fmt.Sprintf("%02d", ts.Year()%100),
×
NEW
1690
                "MM", fmt.Sprintf("%02d", ts.Month()),
×
NEW
1691
                "DD", fmt.Sprintf("%02d", ts.Day()),
×
NEW
1692
                "HH24", fmt.Sprintf("%02d", ts.Hour()),
×
NEW
1693
                "HH12", fmt.Sprintf("%02d", (ts.Hour()+11)%12+1),
×
NEW
1694
                "HH", fmt.Sprintf("%02d", ts.Hour()),
×
NEW
1695
                "MI", fmt.Sprintf("%02d", ts.Minute()),
×
NEW
1696
                "SS", fmt.Sprintf("%02d", ts.Second()),
×
NEW
1697
                "Month", ts.Month().String(),
×
NEW
1698
                "Day", ts.Weekday().String(),
×
NEW
1699
        )
×
NEW
1700
        return r.Replace(pgFmt)
×
NEW
1701
}
×
1702

1703
type datePartFn struct{}
1704

NEW
1705
func (f *datePartFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1706
        return Float64Type, nil
×
NEW
1707
}
×
NEW
1708
func (f *datePartFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1709
        if t != Float64Type && t != IntegerType {
×
NEW
1710
                return fmt.Errorf("%w: %v can not be interpreted as numeric type", ErrInvalidTypes, t)
×
NEW
1711
        }
×
NEW
1712
        return nil
×
1713
}
NEW
1714
func (f *datePartFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
1715
        if len(params) != 2 {
×
NEW
1716
                return nil, fmt.Errorf("%w: '%s' expects 2 arguments", ErrIllegalArguments, DatePartFnCall)
×
NEW
1717
        }
×
NEW
1718
        if params[0].IsNull() || params[1].IsNull() {
×
NEW
1719
                return NewNull(Float64Type), nil
×
NEW
1720
        }
×
NEW
1721
        field, _ := params[0].RawValue().(string)
×
NEW
1722
        ts, ok := params[1].RawValue().(time.Time)
×
NEW
1723
        if !ok {
×
NEW
1724
                return NewNull(Float64Type), nil
×
NEW
1725
        }
×
NEW
1726
        ts = ts.UTC()
×
NEW
1727
        var val float64
×
NEW
1728
        switch strings.ToLower(field) {
×
NEW
1729
        case "year":
×
NEW
1730
                val = float64(ts.Year())
×
NEW
1731
        case "month":
×
NEW
1732
                val = float64(ts.Month())
×
NEW
1733
        case "day":
×
NEW
1734
                val = float64(ts.Day())
×
NEW
1735
        case "hour":
×
NEW
1736
                val = float64(ts.Hour())
×
NEW
1737
        case "minute":
×
NEW
1738
                val = float64(ts.Minute())
×
NEW
1739
        case "second":
×
NEW
1740
                val = float64(ts.Second())
×
NEW
1741
        case "dow", "dayofweek":
×
NEW
1742
                val = float64(ts.Weekday())
×
NEW
1743
        case "doy", "dayofyear":
×
NEW
1744
                val = float64(ts.YearDay())
×
NEW
1745
        case "epoch":
×
NEW
1746
                val = float64(ts.Unix())
×
1747
        }
NEW
1748
        return NewFloat64(val), nil
×
1749
}
1750

1751
type ageFn struct{}
1752

NEW
1753
func (f *ageFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1754
        return VarcharType, nil
×
NEW
1755
}
×
NEW
1756
func (f *ageFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1757
        if t != VarcharType {
×
NEW
1758
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1759
        }
×
NEW
1760
        return nil
×
1761
}
1762
// concat_ws(separator, val1, val2, ...) — concatenate with separator
1763
type concatWSFn struct{}
1764

1765
func (f *concatWSFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
1766
        return VarcharType, nil
1✔
1767
}
1✔
NEW
1768
func (f *concatWSFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1769
        if t != VarcharType {
×
NEW
1770
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1771
        }
×
NEW
1772
        return nil
×
1773
}
1774
func (f *concatWSFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1775
        if len(params) < 2 {
4✔
NEW
1776
                return nil, fmt.Errorf("%w: '%s' expects at least 2 arguments", ErrIllegalArguments, ConcatWSFnCall)
×
NEW
1777
        }
×
1778
        if params[0].IsNull() {
4✔
NEW
1779
                return NewNull(VarcharType), nil
×
NEW
1780
        }
×
1781
        sep, _ := params[0].RawValue().(string)
4✔
1782
        var parts []string
4✔
1783
        for _, p := range params[1:] {
16✔
1784
                if !p.IsNull() {
24✔
1785
                        s, _ := p.RawValue().(string)
12✔
1786
                        parts = append(parts, s)
12✔
1787
                }
12✔
1788
        }
1789
        return NewVarchar(strings.Join(parts, sep)), nil
4✔
1790
}
1791

1792
// regexp_replace(source, pattern, replacement) — regex replacement
1793
type regexpReplaceFn struct{}
1794

1795
func (f *regexpReplaceFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
1796
        return VarcharType, nil
1✔
1797
}
1✔
NEW
1798
func (f *regexpReplaceFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1799
        if t != VarcharType {
×
NEW
1800
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
1801
        }
×
NEW
1802
        return nil
×
1803
}
1804
func (f *regexpReplaceFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
3✔
1805
        if len(params) < 3 {
3✔
NEW
1806
                return nil, fmt.Errorf("%w: '%s' expects at least 3 arguments", ErrIllegalArguments, RegexpReplaceFnCall)
×
NEW
1807
        }
×
1808
        if params[0].IsNull() {
3✔
NEW
1809
                return NewNull(VarcharType), nil
×
NEW
1810
        }
×
1811
        source, _ := params[0].RawValue().(string)
3✔
1812
        pattern, _ := params[1].RawValue().(string)
3✔
1813
        replacement, _ := params[2].RawValue().(string)
3✔
1814

3✔
1815
        re, err := regexp.Compile(pattern)
3✔
1816
        if err != nil {
3✔
NEW
1817
                return NewVarchar(source), nil
×
NEW
1818
        }
×
1819
        return NewVarchar(re.ReplaceAllString(source, replacement)), nil
3✔
1820
}
1821

1822
// random() — returns a random float between 0 and 1
1823
type randomFn struct{}
1824

1825
func (f *randomFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
3✔
1826
        return Float64Type, nil
3✔
1827
}
3✔
NEW
1828
func (f *randomFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1829
        return nil
×
NEW
1830
}
×
1831
func (f *randomFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
1832
        return NewFloat64(math.Float64frombits(uint64(time.Now().UnixNano()) ^ 0x5DEECE66D)), nil
2✔
1833
}
2✔
1834

1835
// to_number(text, format) — converts text to numeric
1836
type toNumberFn struct{}
1837

NEW
1838
func (f *toNumberFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
1839
        return Float64Type, nil
×
NEW
1840
}
×
NEW
1841
func (f *toNumberFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1842
        return nil
×
NEW
1843
}
×
NEW
1844
func (f *toNumberFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
1845
        if len(params) < 1 {
×
NEW
1846
                return nil, fmt.Errorf("%w: '%s' expects at least 1 argument", ErrIllegalArguments, ToNumberFnCall)
×
NEW
1847
        }
×
NEW
1848
        if params[0].IsNull() {
×
NEW
1849
                return NewNull(Float64Type), nil
×
NEW
1850
        }
×
NEW
1851
        s, ok := params[0].RawValue().(string)
×
NEW
1852
        if !ok {
×
NEW
1853
                return NewNull(Float64Type), nil
×
NEW
1854
        }
×
1855
        // Simple numeric parsing
NEW
1856
        s = strings.TrimSpace(s)
×
NEW
1857
        s = strings.ReplaceAll(s, ",", "")
×
NEW
1858
        var val float64
×
NEW
1859
        _, err := fmt.Sscanf(s, "%f", &val)
×
NEW
1860
        if err != nil {
×
NEW
1861
                return NewNull(Float64Type), nil
×
NEW
1862
        }
×
NEW
1863
        return NewFloat64(val), nil
×
1864
}
1865

1866
// nextval(sequence_name) — returns next value from sequence
1867
type nextValFn struct{}
1868

1869
func (f *nextValFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
9✔
1870
        return IntegerType, nil
9✔
1871
}
9✔
NEW
1872
func (f *nextValFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1873
        if t != IntegerType {
×
NEW
1874
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
×
NEW
1875
        }
×
NEW
1876
        return nil
×
1877
}
1878
func (f *nextValFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
11✔
1879
        if len(params) != 1 {
11✔
NEW
1880
                return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, NextValFnCall)
×
NEW
1881
        }
×
1882
        if params[0].IsNull() {
11✔
NEW
1883
                return NewNull(IntegerType), nil
×
NEW
1884
        }
×
1885
        name, ok := params[0].RawValue().(string)
11✔
1886
        if !ok {
11✔
NEW
1887
                return nil, fmt.Errorf("%w: '%s' expects a string argument", ErrIllegalArguments, NextValFnCall)
×
NEW
1888
        }
×
1889
        val, err := tx.engine.NextVal(name)
11✔
1890
        if err != nil {
12✔
1891
                return nil, err
1✔
1892
        }
1✔
1893

1894
        // Best-effort persistence — sequence counter is always updated in-memory.
1895
        // Persistence may fail in read-only transactions (SELECT NEXTVAL),
1896
        // but succeeds when called within DML or explicit transactions.
1897
        if seq, exists := tx.engine.sequences[name]; exists {
20✔
1898
                _ = persistSequence(tx, seq)
10✔
1899
        }
10✔
1900

1901
        return NewInteger(val), nil
10✔
1902
}
1903

1904
// currval(sequence_name) — returns current value of sequence
1905
type currValFn struct{}
1906

1907
func (f *currValFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
1908
        return IntegerType, nil
6✔
1909
}
6✔
NEW
1910
func (f *currValFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
1911
        if t != IntegerType {
×
NEW
1912
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
×
NEW
1913
        }
×
NEW
1914
        return nil
×
1915
}
1916
func (f *currValFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
1917
        if len(params) != 1 {
4✔
NEW
1918
                return nil, fmt.Errorf("%w: '%s' expects 1 argument", ErrIllegalArguments, CurrValFnCall)
×
NEW
1919
        }
×
1920
        if params[0].IsNull() {
4✔
NEW
1921
                return NewNull(IntegerType), nil
×
NEW
1922
        }
×
1923
        name, ok := params[0].RawValue().(string)
4✔
1924
        if !ok {
4✔
NEW
1925
                return nil, fmt.Errorf("%w: '%s' expects a string argument", ErrIllegalArguments, CurrValFnCall)
×
NEW
1926
        }
×
1927
        val, err := tx.engine.CurrVal(name)
4✔
1928
        if err != nil {
5✔
1929
                return nil, err
1✔
1930
        }
1✔
1931
        return NewInteger(val), nil
3✔
1932
}
1933

NEW
1934
func (f *ageFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
1935
        if len(params) < 1 || len(params) > 2 {
×
NEW
1936
                return nil, fmt.Errorf("%w: '%s' expects 1-2 arguments", ErrIllegalArguments, AgeFnCall)
×
NEW
1937
        }
×
NEW
1938
        if params[0].IsNull() {
×
NEW
1939
                return NewNull(VarcharType), nil
×
NEW
1940
        }
×
1941

NEW
1942
        var from, to time.Time
×
NEW
1943
        if len(params) == 2 {
×
NEW
1944
                var ok bool
×
NEW
1945
                from, ok = params[1].RawValue().(time.Time)
×
NEW
1946
                if !ok {
×
NEW
1947
                        return NewNull(VarcharType), nil
×
NEW
1948
                }
×
NEW
1949
                to, ok = params[0].RawValue().(time.Time)
×
NEW
1950
                if !ok {
×
NEW
1951
                        return NewNull(VarcharType), nil
×
NEW
1952
                }
×
NEW
1953
        } else {
×
NEW
1954
                var ok bool
×
NEW
1955
                from, ok = params[0].RawValue().(time.Time)
×
NEW
1956
                if !ok {
×
NEW
1957
                        return NewNull(VarcharType), nil
×
NEW
1958
                }
×
NEW
1959
                to = tx.Timestamp().UTC()
×
1960
        }
1961

NEW
1962
        diff := to.Sub(from)
×
NEW
1963
        days := int(diff.Hours() / 24)
×
NEW
1964
        years := days / 365
×
NEW
1965
        remainDays := days % 365
×
NEW
1966
        months := remainDays / 30
×
NEW
1967
        d := remainDays % 30
×
NEW
1968

×
NEW
1969
        return NewVarchar(fmt.Sprintf("%d years %d mons %d days", years, months, d)), nil
×
1970
}
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