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

codenotary / immudb / 9367064922

04 Jun 2024 12:27PM UTC coverage: 89.43% (-0.02%) from 89.451%
9367064922

push

gh-ci

ostafen
Add support for JSON type

Signed-off-by: Stefano Scafiti <stefano.scafiti96@gmail.com>

521 of 575 new or added lines in 14 files covered. (90.61%)

12 existing lines in 5 files now uncovered.

35172 of 39329 relevant lines covered (89.43%)

160547.56 hits per line

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

84.85
/embedded/sql/stmt.go
1
/*
2
Copyright 2024 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
        "bytes"
21
        "context"
22
        "encoding/binary"
23
        "encoding/hex"
24
        "errors"
25
        "fmt"
26
        "math"
27
        "regexp"
28
        "strconv"
29
        "strings"
30
        "time"
31

32
        "github.com/codenotary/immudb/embedded/store"
33
        "github.com/google/uuid"
34
)
35

36
const (
37
        catalogPrefix       = "CTL."
38
        catalogTablePrefix  = "CTL.TABLE."  // (key=CTL.TABLE.{1}{tableID}, value={tableNAME})
39
        catalogColumnPrefix = "CTL.COLUMN." // (key=CTL.COLUMN.{1}{tableID}{colID}{colTYPE}, value={(auto_incremental | nullable){maxLen}{colNAME}})
40
        catalogIndexPrefix  = "CTL.INDEX."  // (key=CTL.INDEX.{1}{tableID}{indexID}, value={unique {colID1}(ASC|DESC)...{colIDN}(ASC|DESC)})
41

42
        RowPrefix    = "R." // (key=R.{1}{tableID}{0}({null}({pkVal}{padding}{pkValLen})?)+, value={count (colID valLen val)+})
43
        MappedPrefix = "M." // (key=M.{tableID}{indexID}({null}({val}{padding}{valLen})?)*({pkVal}{padding}{pkValLen})+, value={count (colID valLen val)+})
44
)
45

46
const (
47
        DatabaseID = uint32(1) // deprecated but left to maintain backwards compatibility
48
        PKIndexID  = uint32(0)
49
)
50

51
const (
52
        nullableFlag      byte = 1 << iota
53
        autoIncrementFlag byte = 1 << iota
54
)
55

56
const (
57
        revCol        = "_rev"
58
        txMetadataCol = "_tx_metadata"
59
)
60

61
var reservedColumns = map[string]struct{}{
62
        revCol:        {},
63
        txMetadataCol: {},
64
}
65

66
func isReservedCol(col string) bool {
12,384✔
67
        _, ok := reservedColumns[col]
12,384✔
68
        return ok
12,384✔
69
}
12,384✔
70

71
type SQLValueType = string
72

73
const (
74
        IntegerType   SQLValueType = "INTEGER"
75
        BooleanType   SQLValueType = "BOOLEAN"
76
        VarcharType   SQLValueType = "VARCHAR"
77
        UUIDType      SQLValueType = "UUID"
78
        BLOBType      SQLValueType = "BLOB"
79
        Float64Type   SQLValueType = "FLOAT"
80
        TimestampType SQLValueType = "TIMESTAMP"
81
        AnyType       SQLValueType = "ANY"
82
        JSONType      SQLValueType = "JSON"
83
)
84

85
func IsNumericType(t SQLValueType) bool {
217✔
86
        return t == IntegerType || t == Float64Type
217✔
87
}
217✔
88

89
type Permission = string
90

91
const (
92
        PermissionReadOnly  Permission = "READ"
93
        PermissionReadWrite Permission = "READWRITE"
94
        PermissionAdmin     Permission = "ADMIN"
95
)
96

97
type AggregateFn = string
98

99
const (
100
        COUNT AggregateFn = "COUNT"
101
        SUM   AggregateFn = "SUM"
102
        MAX   AggregateFn = "MAX"
103
        MIN   AggregateFn = "MIN"
104
        AVG   AggregateFn = "AVG"
105
)
106

107
type CmpOperator = int
108

109
const (
110
        EQ CmpOperator = iota
111
        NE
112
        LT
113
        LE
114
        GT
115
        GE
116
)
117

118
type LogicOperator = int
119

120
const (
121
        AND LogicOperator = iota
122
        OR
123
)
124

125
type NumOperator = int
126

127
const (
128
        ADDOP NumOperator = iota
129
        SUBSOP
130
        DIVOP
131
        MULTOP
132
)
133

134
type JoinType = int
135

136
const (
137
        InnerJoin JoinType = iota
138
        LeftJoin
139
        RightJoin
140
)
141

142
const (
143
        NowFnCall        string = "NOW"
144
        UUIDFnCall       string = "RANDOM_UUID"
145
        DatabasesFnCall  string = "DATABASES"
146
        TablesFnCall     string = "TABLES"
147
        TableFnCall      string = "TABLE"
148
        UsersFnCall      string = "USERS"
149
        ColumnsFnCall    string = "COLUMNS"
150
        IndexesFnCall    string = "INDEXES"
151
        JSONTypeOfFnCall string = "JSON_TYPEOF"
152
)
153

154
type SQLStmt interface {
155
        execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error)
156
        inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error
157
}
158

159
type BeginTransactionStmt struct {
160
}
161

162
func (stmt *BeginTransactionStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
3✔
163
        return nil
3✔
164
}
3✔
165

166
func (stmt *BeginTransactionStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
60✔
167
        if tx.IsExplicitCloseRequired() {
61✔
168
                return nil, ErrNestedTxNotSupported
1✔
169
        }
1✔
170

171
        err := tx.RequireExplicitClose()
59✔
172
        if err == nil {
117✔
173
                // current tx can be reused as no changes were already made
58✔
174
                return tx, nil
58✔
175
        }
58✔
176

177
        // commit current transaction and start a fresh one
178

179
        err = tx.Commit(ctx)
1✔
180
        if err != nil {
1✔
181
                return nil, err
×
182
        }
×
183

184
        return tx.engine.NewTx(ctx, tx.opts.WithExplicitClose(true))
1✔
185
}
186

187
type CommitStmt struct {
188
}
189

190
func (stmt *CommitStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
191
        return nil
1✔
192
}
1✔
193

194
func (stmt *CommitStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
159✔
195
        if !tx.IsExplicitCloseRequired() {
160✔
196
                return nil, ErrNoOngoingTx
1✔
197
        }
1✔
198

199
        return nil, tx.Commit(ctx)
158✔
200
}
201

202
type RollbackStmt struct {
203
}
204

205
func (stmt *RollbackStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
206
        return nil
1✔
207
}
1✔
208

209
func (stmt *RollbackStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
4✔
210
        if !tx.IsExplicitCloseRequired() {
5✔
211
                return nil, ErrNoOngoingTx
1✔
212
        }
1✔
213

214
        return nil, tx.Cancel()
3✔
215
}
216

217
type CreateDatabaseStmt struct {
218
        DB          string
219
        ifNotExists bool
220
}
221

222
func (stmt *CreateDatabaseStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
4✔
223
        return nil
4✔
224
}
4✔
225

226
func (stmt *CreateDatabaseStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
15✔
227
        if tx.IsExplicitCloseRequired() {
16✔
228
                return nil, fmt.Errorf("%w: database creation can not be done within a transaction", ErrNonTransactionalStmt)
1✔
229
        }
1✔
230

231
        if tx.engine.multidbHandler == nil {
16✔
232
                return nil, ErrUnspecifiedMultiDBHandler
2✔
233
        }
2✔
234

235
        return nil, tx.engine.multidbHandler.CreateDatabase(ctx, stmt.DB, stmt.ifNotExists)
12✔
236
}
237

238
type UseDatabaseStmt struct {
239
        DB string
240
}
241

242
func (stmt *UseDatabaseStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
243
        return nil
1✔
244
}
1✔
245

246
func (stmt *UseDatabaseStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
9✔
247
        if tx.IsExplicitCloseRequired() {
10✔
248
                return nil, fmt.Errorf("%w: database selection can NOT be executed within a transaction block", ErrNonTransactionalStmt)
1✔
249
        }
1✔
250

251
        if tx.engine.multidbHandler == nil {
9✔
252
                return nil, ErrUnspecifiedMultiDBHandler
1✔
253
        }
1✔
254

255
        return tx, tx.engine.multidbHandler.UseDatabase(ctx, stmt.DB)
7✔
256
}
257

258
type UseSnapshotStmt struct {
259
        period period
260
}
261

262
func (stmt *UseSnapshotStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
263
        return nil
1✔
264
}
1✔
265

266
func (stmt *UseSnapshotStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
1✔
267
        return nil, ErrNoSupported
1✔
268
}
1✔
269

270
type CreateUserStmt struct {
271
        username   string
272
        password   string
273
        permission Permission
274
}
275

276
func (stmt *CreateUserStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
277
        return nil
1✔
278
}
1✔
279

280
func (stmt *CreateUserStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
6✔
281
        if tx.IsExplicitCloseRequired() {
7✔
282
                return nil, fmt.Errorf("%w: user creation can not be done within a transaction", ErrNonTransactionalStmt)
1✔
283
        }
1✔
284

285
        if tx.engine.multidbHandler == nil {
6✔
286
                return nil, ErrUnspecifiedMultiDBHandler
1✔
287
        }
1✔
288

289
        return nil, tx.engine.multidbHandler.CreateUser(ctx, stmt.username, stmt.password, stmt.permission)
4✔
290
}
291

292
type AlterUserStmt struct {
293
        username   string
294
        password   string
295
        permission Permission
296
}
297

298
func (stmt *AlterUserStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
299
        return nil
1✔
300
}
1✔
301

302
func (stmt *AlterUserStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
5✔
303
        if tx.IsExplicitCloseRequired() {
6✔
304
                return nil, fmt.Errorf("%w: user modification can not be done within a transaction", ErrNonTransactionalStmt)
1✔
305
        }
1✔
306

307
        if tx.engine.multidbHandler == nil {
5✔
308
                return nil, ErrUnspecifiedMultiDBHandler
1✔
309
        }
1✔
310

311
        return nil, tx.engine.multidbHandler.AlterUser(ctx, stmt.username, stmt.password, stmt.permission)
3✔
312
}
313

314
type DropUserStmt struct {
315
        username string
316
}
317

318
func (stmt *DropUserStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
319
        return nil
1✔
320
}
1✔
321

322
func (stmt *DropUserStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
3✔
323
        if tx.IsExplicitCloseRequired() {
4✔
324
                return nil, fmt.Errorf("%w: user deletion can not be done within a transaction", ErrNonTransactionalStmt)
1✔
325
        }
1✔
326

327
        if tx.engine.multidbHandler == nil {
3✔
328
                return nil, ErrUnspecifiedMultiDBHandler
1✔
329
        }
1✔
330

331
        return nil, tx.engine.multidbHandler.DropUser(ctx, stmt.username)
1✔
332
}
333

334
type CreateTableStmt struct {
335
        table       string
336
        ifNotExists bool
337
        colsSpec    []*ColSpec
338
        pkColNames  []string
339
}
340

341
func NewCreateTableStmt(table string, ifNotExists bool, colsSpec []*ColSpec, pkColNames []string) *CreateTableStmt {
38✔
342
        return &CreateTableStmt{table: table, ifNotExists: ifNotExists, colsSpec: colsSpec, pkColNames: pkColNames}
38✔
343
}
38✔
344

345
func (stmt *CreateTableStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
4✔
346
        return nil
4✔
347
}
4✔
348

349
func (stmt *CreateTableStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
217✔
350
        if stmt.ifNotExists && tx.catalog.ExistTable(stmt.table) {
218✔
351
                return tx, nil
1✔
352
        }
1✔
353

354
        colSpecs := make(map[uint32]*ColSpec, len(stmt.colsSpec))
216✔
355
        for i, cs := range stmt.colsSpec {
894✔
356
                colSpecs[uint32(i)+1] = cs
678✔
357
        }
678✔
358

359
        table, err := tx.catalog.newTable(stmt.table, colSpecs, uint32(len(colSpecs)))
216✔
360
        if err != nil {
222✔
361
                return nil, err
6✔
362
        }
6✔
363

364
        createIndexStmt := &CreateIndexStmt{unique: true, table: table.name, cols: stmt.pkColNames}
210✔
365
        _, err = createIndexStmt.execAt(ctx, tx, params)
210✔
366
        if err != nil {
215✔
367
                return nil, err
5✔
368
        }
5✔
369

370
        for _, col := range table.cols {
866✔
371
                if col.autoIncrement {
734✔
372
                        if len(table.primaryIndex.cols) > 1 || col.id != table.primaryIndex.cols[0].id {
74✔
373
                                return nil, ErrLimitedAutoIncrement
1✔
374
                        }
1✔
375
                }
376

377
                err := persistColumn(tx, col)
660✔
378
                if err != nil {
660✔
379
                        return nil, err
×
380
                }
×
381
        }
382

383
        mappedKey := MapKey(tx.sqlPrefix(), catalogTablePrefix, EncodeID(DatabaseID), EncodeID(table.id))
204✔
384

204✔
385
        err = tx.set(mappedKey, nil, []byte(table.name))
204✔
386
        if err != nil {
204✔
387
                return nil, err
×
388
        }
×
389

390
        tx.mutatedCatalog = true
204✔
391

204✔
392
        return tx, nil
204✔
393
}
394

395
func persistColumn(tx *SQLTx, col *Column) error {
680✔
396
        //{auto_incremental | nullable}{maxLen}{colNAME})
680✔
397
        v := make([]byte, 1+4+len(col.colName))
680✔
398

680✔
399
        if col.autoIncrement {
752✔
400
                v[0] = v[0] | autoIncrementFlag
72✔
401
        }
72✔
402

403
        if col.notNull {
725✔
404
                v[0] = v[0] | nullableFlag
45✔
405
        }
45✔
406

407
        binary.BigEndian.PutUint32(v[1:], uint32(col.MaxLen()))
680✔
408

680✔
409
        copy(v[5:], []byte(col.Name()))
680✔
410

680✔
411
        mappedKey := MapKey(
680✔
412
                tx.sqlPrefix(),
680✔
413
                catalogColumnPrefix,
680✔
414
                EncodeID(DatabaseID),
680✔
415
                EncodeID(col.table.id),
680✔
416
                EncodeID(col.id),
680✔
417
                []byte(col.colType),
680✔
418
        )
680✔
419

680✔
420
        return tx.set(mappedKey, nil, v)
680✔
421
}
422

423
type ColSpec struct {
424
        colName       string
425
        colType       SQLValueType
426
        maxLen        int
427
        autoIncrement bool
428
        notNull       bool
429
}
430

431
func NewColSpec(name string, colType SQLValueType, maxLen int, autoIncrement bool, notNull bool) *ColSpec {
188✔
432
        return &ColSpec{
188✔
433
                colName:       name,
188✔
434
                colType:       colType,
188✔
435
                maxLen:        maxLen,
188✔
436
                autoIncrement: autoIncrement,
188✔
437
                notNull:       notNull,
188✔
438
        }
188✔
439
}
188✔
440

441
type CreateIndexStmt struct {
442
        unique      bool
443
        ifNotExists bool
444
        table       string
445
        cols        []string
446
}
447

448
func NewCreateIndexStmt(table string, cols []string, isUnique bool) *CreateIndexStmt {
72✔
449
        return &CreateIndexStmt{unique: isUnique, table: table, cols: cols}
72✔
450
}
72✔
451

452
func (stmt *CreateIndexStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
453
        return nil
1✔
454
}
1✔
455

456
func (stmt *CreateIndexStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
361✔
457
        if len(stmt.cols) < 1 {
362✔
458
                return nil, ErrIllegalArguments
1✔
459
        }
1✔
460

461
        if len(stmt.cols) > MaxNumberOfColumnsInIndex {
361✔
462
                return nil, ErrMaxNumberOfColumnsInIndexExceeded
1✔
463
        }
1✔
464

465
        table, err := tx.catalog.GetTableByName(stmt.table)
359✔
466
        if err != nil {
361✔
467
                return nil, err
2✔
468
        }
2✔
469

470
        colIDs := make([]uint32, len(stmt.cols))
357✔
471

357✔
472
        indexKeyLen := 0
357✔
473

357✔
474
        for i, colName := range stmt.cols {
741✔
475
                col, err := table.GetColumnByName(colName)
384✔
476
                if err != nil {
389✔
477
                        return nil, err
5✔
478
                }
5✔
479

480
                if col.Type() == JSONType {
381✔
481
                        return nil, ErrCannotIndexJson
2✔
482
                }
2✔
483

484
                if variableSizedType(col.colType) && !tx.engine.lazyIndexConstraintValidation && (col.MaxLen() == 0 || col.MaxLen() > MaxKeyLen) {
379✔
485
                        return nil, fmt.Errorf("%w: can not create index using column '%s'. Max key length for variable columns is %d", ErrLimitedKeyType, col.colName, MaxKeyLen)
2✔
486
                }
2✔
487

488
                indexKeyLen += col.MaxLen()
375✔
489

375✔
490
                colIDs[i] = col.id
375✔
491
        }
492

493
        if !tx.engine.lazyIndexConstraintValidation && indexKeyLen > MaxKeyLen {
348✔
494
                return nil, fmt.Errorf("%w: can not create index using columns '%v'. Max key length is %d", ErrLimitedKeyType, stmt.cols, MaxKeyLen)
×
495
        }
×
496

497
        if stmt.unique && table.primaryIndex != nil {
368✔
498
                // check table is empty
20✔
499
                pkPrefix := MapKey(tx.sqlPrefix(), MappedPrefix, EncodeID(table.id), EncodeID(table.primaryIndex.id))
20✔
500
                _, _, err := tx.getWithPrefix(ctx, pkPrefix, nil)
20✔
501
                if errors.Is(err, store.ErrIndexNotFound) {
20✔
502
                        return nil, ErrTableDoesNotExist
×
503
                }
×
504
                if err == nil {
21✔
505
                        return nil, ErrLimitedIndexCreation
1✔
506
                } else if !errors.Is(err, store.ErrKeyNotFound) {
20✔
507
                        return nil, err
×
508
                }
×
509
        }
510

511
        index, err := table.newIndex(stmt.unique, colIDs)
347✔
512
        if errors.Is(err, ErrIndexAlreadyExists) && stmt.ifNotExists {
349✔
513
                return tx, nil
2✔
514
        }
2✔
515
        if err != nil {
349✔
516
                return nil, err
4✔
517
        }
4✔
518

519
        // v={unique {colID1}(ASC|DESC)...{colIDN}(ASC|DESC)}
520
        // TODO: currently only ASC order is supported
521
        colSpecLen := EncIDLen + 1
341✔
522

341✔
523
        encodedValues := make([]byte, 1+len(index.cols)*colSpecLen)
341✔
524

341✔
525
        if index.IsUnique() {
564✔
526
                encodedValues[0] = 1
223✔
527
        }
223✔
528

529
        for i, col := range index.cols {
709✔
530
                copy(encodedValues[1+i*colSpecLen:], EncodeID(col.id))
368✔
531
        }
368✔
532

533
        mappedKey := MapKey(tx.sqlPrefix(), catalogIndexPrefix, EncodeID(DatabaseID), EncodeID(table.id), EncodeID(index.id))
341✔
534

341✔
535
        err = tx.set(mappedKey, nil, encodedValues)
341✔
536
        if err != nil {
341✔
537
                return nil, err
×
538
        }
×
539

540
        tx.mutatedCatalog = true
341✔
541

341✔
542
        return tx, nil
341✔
543
}
544

545
type AddColumnStmt struct {
546
        table   string
547
        colSpec *ColSpec
548
}
549

550
func NewAddColumnStmt(table string, colSpec *ColSpec) *AddColumnStmt {
6✔
551
        return &AddColumnStmt{table: table, colSpec: colSpec}
6✔
552
}
6✔
553

554
func (stmt *AddColumnStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
555
        return nil
1✔
556
}
1✔
557

558
func (stmt *AddColumnStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
19✔
559
        table, err := tx.catalog.GetTableByName(stmt.table)
19✔
560
        if err != nil {
20✔
561
                return nil, err
1✔
562
        }
1✔
563

564
        col, err := table.newColumn(stmt.colSpec)
18✔
565
        if err != nil {
24✔
566
                return nil, err
6✔
567
        }
6✔
568

569
        err = persistColumn(tx, col)
12✔
570
        if err != nil {
12✔
571
                return nil, err
×
572
        }
×
573

574
        tx.mutatedCatalog = true
12✔
575

12✔
576
        return tx, nil
12✔
577
}
578

579
type RenameTableStmt struct {
580
        oldName string
581
        newName string
582
}
583

584
func (stmt *RenameTableStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
585
        return nil
1✔
586
}
1✔
587

588
func (stmt *RenameTableStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
6✔
589
        table, err := tx.catalog.renameTable(stmt.oldName, stmt.newName)
6✔
590
        if err != nil {
10✔
591
                return nil, err
4✔
592
        }
4✔
593

594
        // update table name
595
        mappedKey := MapKey(
2✔
596
                tx.sqlPrefix(),
2✔
597
                catalogTablePrefix,
2✔
598
                EncodeID(DatabaseID),
2✔
599
                EncodeID(table.id),
2✔
600
        )
2✔
601
        err = tx.set(mappedKey, nil, []byte(stmt.newName))
2✔
602
        if err != nil {
2✔
603
                return nil, err
×
604
        }
×
605

606
        tx.mutatedCatalog = true
2✔
607

2✔
608
        return tx, nil
2✔
609
}
610

611
type RenameColumnStmt struct {
612
        table   string
613
        oldName string
614
        newName string
615
}
616

617
func NewRenameColumnStmt(table, oldName, newName string) *RenameColumnStmt {
3✔
618
        return &RenameColumnStmt{table: table, oldName: oldName, newName: newName}
3✔
619
}
3✔
620

621
func (stmt *RenameColumnStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
622
        return nil
1✔
623
}
1✔
624

625
func (stmt *RenameColumnStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
10✔
626
        table, err := tx.catalog.GetTableByName(stmt.table)
10✔
627
        if err != nil {
11✔
628
                return nil, err
1✔
629
        }
1✔
630

631
        col, err := table.renameColumn(stmt.oldName, stmt.newName)
9✔
632
        if err != nil {
12✔
633
                return nil, err
3✔
634
        }
3✔
635

636
        err = persistColumn(tx, col)
6✔
637
        if err != nil {
6✔
638
                return nil, err
×
639
        }
×
640

641
        tx.mutatedCatalog = true
6✔
642

6✔
643
        return tx, nil
6✔
644
}
645

646
type DropColumnStmt struct {
647
        table   string
648
        colName string
649
}
650

651
func NewDropColumnStmt(table, colName string) *DropColumnStmt {
8✔
652
        return &DropColumnStmt{table: table, colName: colName}
8✔
653
}
8✔
654

655
func (stmt *DropColumnStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
656
        return nil
1✔
657
}
1✔
658

659
func (stmt *DropColumnStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
17✔
660
        table, err := tx.catalog.GetTableByName(stmt.table)
17✔
661
        if err != nil {
19✔
662
                return nil, err
2✔
663
        }
2✔
664

665
        col, err := table.GetColumnByName(stmt.colName)
15✔
666
        if err != nil {
19✔
667
                return nil, err
4✔
668
        }
4✔
669

670
        err = table.deleteColumn(col)
11✔
671
        if err != nil {
15✔
672
                return nil, err
4✔
673
        }
4✔
674

675
        err = persistColumnDeletion(ctx, tx, col)
7✔
676
        if err != nil {
7✔
677
                return nil, err
×
678
        }
×
679

680
        tx.mutatedCatalog = true
7✔
681

7✔
682
        return tx, nil
7✔
683
}
684

685
func persistColumnDeletion(ctx context.Context, tx *SQLTx, col *Column) error {
8✔
686
        mappedKey := MapKey(
8✔
687
                tx.sqlPrefix(),
8✔
688
                catalogColumnPrefix,
8✔
689
                EncodeID(DatabaseID),
8✔
690
                EncodeID(col.table.id),
8✔
691
                EncodeID(col.id),
8✔
692
                []byte(col.colType),
8✔
693
        )
8✔
694

8✔
695
        return tx.delete(ctx, mappedKey)
8✔
696
}
8✔
697

698
type UpsertIntoStmt struct {
699
        isInsert   bool
700
        tableRef   *tableRef
701
        cols       []string
702
        rows       []*RowSpec
703
        onConflict *OnConflictDo
704
}
705

706
func NewUpserIntoStmt(table string, cols []string, rows []*RowSpec, isInsert bool, onConflict *OnConflictDo) *UpsertIntoStmt {
120✔
707
        return &UpsertIntoStmt{
120✔
708
                isInsert:   isInsert,
120✔
709
                tableRef:   NewTableRef(table, ""),
120✔
710
                cols:       cols,
120✔
711
                rows:       rows,
120✔
712
                onConflict: onConflict,
120✔
713
        }
120✔
714
}
120✔
715

716
type RowSpec struct {
717
        Values []ValueExp
718
}
719

720
func NewRowSpec(values []ValueExp) *RowSpec {
129✔
721
        return &RowSpec{
129✔
722
                Values: values,
129✔
723
        }
129✔
724
}
129✔
725

726
type OnConflictDo struct {
727
}
728

729
func (stmt *UpsertIntoStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
11✔
730
        for _, row := range stmt.rows {
23✔
731
                if len(stmt.cols) != len(row.Values) {
13✔
732
                        return ErrInvalidNumberOfValues
1✔
733
                }
1✔
734

735
                for i, val := range row.Values {
36✔
736
                        table, err := stmt.tableRef.referencedTable(tx)
25✔
737
                        if err != nil {
26✔
738
                                return err
1✔
739
                        }
1✔
740

741
                        col, err := table.GetColumnByName(stmt.cols[i])
24✔
742
                        if err != nil {
25✔
743
                                return err
1✔
744
                        }
1✔
745

746
                        err = val.requiresType(col.colType, make(map[string]ColDescriptor), params, table.name)
23✔
747
                        if err != nil {
25✔
748
                                return err
2✔
749
                        }
2✔
750
                }
751
        }
752

753
        return nil
6✔
754
}
755

756
func (stmt *UpsertIntoStmt) validate(table *Table) (map[uint32]int, error) {
1,885✔
757
        selPosByColID := make(map[uint32]int, len(stmt.cols))
1,885✔
758

1,885✔
759
        for i, c := range stmt.cols {
8,025✔
760
                col, err := table.GetColumnByName(c)
6,140✔
761
                if err != nil {
6,142✔
762
                        return nil, err
2✔
763
                }
2✔
764

765
                _, duplicated := selPosByColID[col.id]
6,138✔
766
                if duplicated {
6,139✔
767
                        return nil, fmt.Errorf("%w (%s)", ErrDuplicatedColumn, col.colName)
1✔
768
                }
1✔
769

770
                selPosByColID[col.id] = i
6,137✔
771
        }
772

773
        return selPosByColID, nil
1,882✔
774
}
775

776
func (stmt *UpsertIntoStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
1,888✔
777
        table, err := stmt.tableRef.referencedTable(tx)
1,888✔
778
        if err != nil {
1,891✔
779
                return nil, err
3✔
780
        }
3✔
781

782
        selPosByColID, err := stmt.validate(table)
1,885✔
783
        if err != nil {
1,888✔
784
                return nil, err
3✔
785
        }
3✔
786

787
        for _, row := range stmt.rows {
3,852✔
788
                if len(row.Values) != len(stmt.cols) {
1,972✔
789
                        return nil, ErrInvalidNumberOfValues
2✔
790
                }
2✔
791

792
                valuesByColID := make(map[uint32]TypedValue)
1,968✔
793

1,968✔
794
                var pkMustExist bool
1,968✔
795

1,968✔
796
                for colID, col := range table.colsByID {
9,109✔
797
                        colPos, specified := selPosByColID[colID]
7,141✔
798
                        if !specified {
7,977✔
799
                                // TODO: Default values
836✔
800
                                if col.notNull && !col.autoIncrement {
837✔
801
                                        return nil, fmt.Errorf("%w (%s)", ErrNotNullableColumnCannotBeNull, col.colName)
1✔
802
                                }
1✔
803

804
                                // inject auto-incremental pk value
805
                                if stmt.isInsert && col.autoIncrement {
1,591✔
806
                                        // current implementation assumes only PK can be set as autoincremental
756✔
807
                                        table.maxPK++
756✔
808

756✔
809
                                        pkCol := table.primaryIndex.cols[0]
756✔
810
                                        valuesByColID[pkCol.id] = &Integer{val: table.maxPK}
756✔
811

756✔
812
                                        if _, ok := tx.firstInsertedPKs[table.name]; !ok {
1,419✔
813
                                                tx.firstInsertedPKs[table.name] = table.maxPK
663✔
814
                                        }
663✔
815
                                        tx.lastInsertedPKs[table.name] = table.maxPK
756✔
816
                                }
817

818
                                continue
835✔
819
                        }
820

821
                        // value was specified
822
                        cVal := row.Values[colPos]
6,305✔
823

6,305✔
824
                        val, err := cVal.substitute(params)
6,305✔
825
                        if err != nil {
6,308✔
826
                                return nil, err
3✔
827
                        }
3✔
828

829
                        rval, err := val.reduce(tx, nil, table.name)
6,302✔
830
                        if err != nil {
6,309✔
831
                                return nil, err
7✔
832
                        }
7✔
833

834
                        if rval.IsNull() {
6,376✔
835
                                if col.notNull || col.autoIncrement {
81✔
836
                                        return nil, fmt.Errorf("%w (%s)", ErrNotNullableColumnCannotBeNull, col.colName)
×
837
                                }
×
838

839
                                continue
81✔
840
                        }
841

842
                        if col.autoIncrement {
6,233✔
843
                                // validate specified value
19✔
844
                                nl, isNumber := rval.RawValue().(int64)
19✔
845
                                if !isNumber {
19✔
846
                                        return nil, fmt.Errorf("%w (expecting numeric value)", ErrInvalidValue)
×
847
                                }
×
848

849
                                pkMustExist = nl <= table.maxPK
19✔
850

19✔
851
                                if _, ok := tx.firstInsertedPKs[table.name]; !ok {
38✔
852
                                        tx.firstInsertedPKs[table.name] = nl
19✔
853
                                }
19✔
854
                                tx.lastInsertedPKs[table.name] = nl
19✔
855
                        }
856

857
                        valuesByColID[colID] = rval
6,214✔
858
                }
859

860
                pkEncVals, err := encodedKey(table.primaryIndex, valuesByColID)
1,957✔
861
                if err != nil {
1,962✔
862
                        return nil, err
5✔
863
                }
5✔
864

865
                // pk entry
866
                mappedPKey := MapKey(tx.sqlPrefix(), MappedPrefix, EncodeID(table.id), EncodeID(table.primaryIndex.id), pkEncVals, pkEncVals)
1,952✔
867
                if len(mappedPKey) > MaxKeyLen {
1,952✔
868
                        return nil, ErrMaxKeyLengthExceeded
×
869
                }
×
870

871
                _, err = tx.get(ctx, mappedPKey)
1,952✔
872
                if err != nil && !errors.Is(err, store.ErrKeyNotFound) {
1,952✔
873
                        return nil, err
×
874
                }
×
875

876
                if errors.Is(err, store.ErrKeyNotFound) && pkMustExist {
1,954✔
877
                        return nil, fmt.Errorf("%w: specified value must be greater than current one", ErrInvalidValue)
2✔
878
                }
2✔
879

880
                if stmt.isInsert {
3,719✔
881
                        if err == nil && stmt.onConflict == nil {
1,773✔
882
                                return nil, store.ErrKeyAlreadyExists
4✔
883
                        }
4✔
884

885
                        if err == nil && stmt.onConflict != nil {
1,768✔
886
                                // TODO: conflict resolution may be extended. Currently only supports "ON CONFLICT DO NOTHING"
3✔
887
                                continue
3✔
888
                        }
889
                }
890

891
                err = tx.doUpsert(ctx, pkEncVals, valuesByColID, table, !stmt.isInsert)
1,943✔
892
                if err != nil {
1,956✔
893
                        return nil, err
13✔
894
                }
13✔
895
        }
896

897
        return tx, nil
1,845✔
898
}
899

900
func (tx *SQLTx) encodeRowValue(valuesByColID map[uint32]TypedValue, table *Table) ([]byte, error) {
2,126✔
901
        valbuf := bytes.Buffer{}
2,126✔
902

2,126✔
903
        // null values are not serialized
2,126✔
904
        encodedVals := 0
2,126✔
905
        for _, v := range valuesByColID {
9,521✔
906
                if !v.IsNull() {
14,772✔
907
                        encodedVals++
7,377✔
908
                }
7,377✔
909
        }
910

911
        b := make([]byte, EncLenLen)
2,126✔
912
        binary.BigEndian.PutUint32(b, uint32(encodedVals))
2,126✔
913

2,126✔
914
        _, err := valbuf.Write(b)
2,126✔
915
        if err != nil {
2,126✔
916
                return nil, err
×
917
        }
×
918

919
        for _, col := range table.cols {
9,657✔
920
                rval, specified := valuesByColID[col.id]
7,531✔
921
                if !specified || rval.IsNull() {
7,691✔
922
                        continue
160✔
923
                }
924

925
                b := make([]byte, EncIDLen)
7,371✔
926
                binary.BigEndian.PutUint32(b, uint32(col.id))
7,371✔
927

7,371✔
928
                _, err = valbuf.Write(b)
7,371✔
929
                if err != nil {
7,371✔
930
                        return nil, fmt.Errorf("%w: table: %s, column: %s", err, table.name, col.colName)
×
931
                }
×
932

933
                encVal, err := EncodeValue(rval, col.colType, col.MaxLen())
7,371✔
934
                if err != nil {
7,379✔
935
                        return nil, fmt.Errorf("%w: table: %s, column: %s", err, table.name, col.colName)
8✔
936
                }
8✔
937

938
                _, err = valbuf.Write(encVal)
7,363✔
939
                if err != nil {
7,363✔
940
                        return nil, fmt.Errorf("%w: table: %s, column: %s", err, table.name, col.colName)
×
941
                }
×
942
        }
943

944
        return valbuf.Bytes(), nil
2,118✔
945
}
946

947
func (tx *SQLTx) doUpsert(ctx context.Context, pkEncVals []byte, valuesByColID map[uint32]TypedValue, table *Table, reuseIndex bool) error {
1,969✔
948
        var reusableIndexEntries map[uint32]struct{}
1,969✔
949

1,969✔
950
        if reuseIndex && len(table.indexes) > 1 {
2,026✔
951
                currPKRow, err := tx.fetchPKRow(ctx, table, valuesByColID)
57✔
952
                if err == nil {
93✔
953
                        currValuesByColID := make(map[uint32]TypedValue, len(currPKRow.ValuesBySelector))
36✔
954

36✔
955
                        for _, col := range table.cols {
161✔
956
                                encSel := EncodeSelector("", table.name, col.colName)
125✔
957
                                currValuesByColID[col.id] = currPKRow.ValuesBySelector[encSel]
125✔
958
                        }
125✔
959

960
                        reusableIndexEntries, err = tx.deprecateIndexEntries(pkEncVals, currValuesByColID, valuesByColID, table)
36✔
961
                        if err != nil {
36✔
962
                                return err
×
963
                        }
×
964
                } else if !errors.Is(err, ErrNoMoreRows) {
21✔
965
                        return err
×
966
                }
×
967
        }
968

969
        rowKey := MapKey(tx.sqlPrefix(), RowPrefix, EncodeID(DatabaseID), EncodeID(table.id), EncodeID(PKIndexID), pkEncVals)
1,969✔
970

1,969✔
971
        encodedRowValue, err := tx.encodeRowValue(valuesByColID, table)
1,969✔
972
        if err != nil {
1,977✔
973
                return err
8✔
974
        }
8✔
975

976
        err = tx.set(rowKey, nil, encodedRowValue)
1,961✔
977
        if err != nil {
1,961✔
978
                return err
×
979
        }
×
980

981
        // create in-memory and validate entries for secondary indexes
982
        for _, index := range table.indexes {
4,805✔
983
                if index.IsPrimary() {
4,805✔
984
                        continue
1,961✔
985
                }
986

987
                if reusableIndexEntries != nil {
960✔
988
                        _, reusable := reusableIndexEntries[index.id]
77✔
989
                        if reusable {
127✔
990
                                continue
50✔
991
                        }
992
                }
993

994
                encodedValues := make([][]byte, 2+len(index.cols))
833✔
995
                encodedValues[0] = EncodeID(table.id)
833✔
996
                encodedValues[1] = EncodeID(index.id)
833✔
997

833✔
998
                indexKeyLen := 0
833✔
999

833✔
1000
                for i, col := range index.cols {
1,729✔
1001
                        rval, specified := valuesByColID[col.id]
896✔
1002
                        if !specified {
945✔
1003
                                rval = &NullValue{t: col.colType}
49✔
1004
                        }
49✔
1005

1006
                        encVal, n, err := EncodeValueAsKey(rval, col.colType, col.MaxLen())
896✔
1007
                        if err != nil {
896✔
1008
                                return fmt.Errorf("%w: index on '%s' and column '%s'", err, index.Name(), col.colName)
×
1009
                        }
×
1010

1011
                        if n > MaxKeyLen {
896✔
1012
                                return fmt.Errorf("%w: can not index entry for column '%s'. Max key length for variable columns is %d", ErrLimitedKeyType, col.colName, MaxKeyLen)
×
1013
                        }
×
1014

1015
                        indexKeyLen += n
896✔
1016

896✔
1017
                        encodedValues[i+2] = encVal
896✔
1018
                }
1019

1020
                if indexKeyLen > MaxKeyLen {
833✔
1021
                        return fmt.Errorf("%w: can not index entry using columns '%v'. Max key length is %d", ErrLimitedKeyType, index.cols, MaxKeyLen)
×
1022
                }
×
1023

1024
                smkey := MapKey(tx.sqlPrefix(), MappedPrefix, encodedValues...)
833✔
1025

833✔
1026
                // no other equivalent entry should be already indexed
833✔
1027
                if index.IsUnique() {
910✔
1028
                        _, valRef, err := tx.getWithPrefix(ctx, smkey, nil)
77✔
1029
                        if err == nil && (valRef.KVMetadata() == nil || !valRef.KVMetadata().Deleted()) {
82✔
1030
                                return store.ErrKeyAlreadyExists
5✔
1031
                        } else if !errors.Is(err, store.ErrKeyNotFound) {
77✔
1032
                                return err
×
1033
                        }
×
1034
                }
1035

1036
                err = tx.setTransient(smkey, nil, encodedRowValue) // only-indexable
828✔
1037
                if err != nil {
828✔
1038
                        return err
×
1039
                }
×
1040
        }
1041

1042
        tx.updatedRows++
1,956✔
1043

1,956✔
1044
        return nil
1,956✔
1045
}
1046

1047
func encodedKey(index *Index, valuesByColID map[uint32]TypedValue) ([]byte, error) {
12,887✔
1048
        valbuf := bytes.Buffer{}
12,887✔
1049

12,887✔
1050
        indexKeyLen := 0
12,887✔
1051

12,887✔
1052
        for _, col := range index.cols {
25,786✔
1053
                rval, specified := valuesByColID[col.id]
12,899✔
1054
                if !specified || rval.IsNull() {
12,902✔
1055
                        return nil, ErrPKCanNotBeNull
3✔
1056
                }
3✔
1057

1058
                encVal, n, err := EncodeValueAsKey(rval, col.colType, col.MaxLen())
12,896✔
1059
                if err != nil {
12,898✔
1060
                        return nil, fmt.Errorf("%w: index of table '%s' and column '%s'", err, index.table.name, col.colName)
2✔
1061
                }
2✔
1062

1063
                if n > MaxKeyLen {
12,894✔
1064
                        return nil, fmt.Errorf("%w: invalid key entry for column '%s'. Max key length for variable columns is %d", ErrLimitedKeyType, col.colName, MaxKeyLen)
×
1065
                }
×
1066

1067
                indexKeyLen += n
12,894✔
1068

12,894✔
1069
                _, err = valbuf.Write(encVal)
12,894✔
1070
                if err != nil {
12,894✔
1071
                        return nil, err
×
1072
                }
×
1073
        }
1074

1075
        if indexKeyLen > MaxKeyLen {
12,882✔
1076
                return nil, fmt.Errorf("%w: invalid key entry using columns '%v'. Max key length is %d", ErrLimitedKeyType, index.cols, MaxKeyLen)
×
1077
        }
×
1078

1079
        return valbuf.Bytes(), nil
12,882✔
1080
}
1081

1082
func (tx *SQLTx) fetchPKRow(ctx context.Context, table *Table, valuesByColID map[uint32]TypedValue) (*Row, error) {
57✔
1083
        pkRanges := make(map[uint32]*typedValueRange, len(table.primaryIndex.cols))
57✔
1084

57✔
1085
        for _, pkCol := range table.primaryIndex.cols {
114✔
1086
                pkVal := valuesByColID[pkCol.id]
57✔
1087

57✔
1088
                pkRanges[pkCol.id] = &typedValueRange{
57✔
1089
                        lRange: &typedValueSemiRange{val: pkVal, inclusive: true},
57✔
1090
                        hRange: &typedValueSemiRange{val: pkVal, inclusive: true},
57✔
1091
                }
57✔
1092
        }
57✔
1093

1094
        scanSpecs := &ScanSpecs{
57✔
1095
                Index:         table.primaryIndex,
57✔
1096
                rangesByColID: pkRanges,
57✔
1097
        }
57✔
1098

57✔
1099
        r, err := newRawRowReader(tx, nil, table, period{}, table.name, scanSpecs)
57✔
1100
        if err != nil {
57✔
1101
                return nil, err
×
1102
        }
×
1103

1104
        defer func() {
114✔
1105
                r.Close()
57✔
1106
        }()
57✔
1107

1108
        return r.Read(ctx)
57✔
1109
}
1110

1111
// deprecateIndexEntries mark previous index entries as deleted
1112
func (tx *SQLTx) deprecateIndexEntries(
1113
        pkEncVals []byte,
1114
        currValuesByColID, newValuesByColID map[uint32]TypedValue,
1115
        table *Table) (reusableIndexEntries map[uint32]struct{}, err error) {
36✔
1116

36✔
1117
        encodedRowValue, err := tx.encodeRowValue(currValuesByColID, table)
36✔
1118
        if err != nil {
36✔
1119
                return nil, err
×
1120
        }
×
1121

1122
        reusableIndexEntries = make(map[uint32]struct{})
36✔
1123

36✔
1124
        for _, index := range table.indexes {
149✔
1125
                if index.IsPrimary() {
149✔
1126
                        continue
36✔
1127
                }
1128

1129
                encodedValues := make([][]byte, 2+len(index.cols)+1)
77✔
1130
                encodedValues[0] = EncodeID(table.id)
77✔
1131
                encodedValues[1] = EncodeID(index.id)
77✔
1132
                encodedValues[len(encodedValues)-1] = pkEncVals
77✔
1133

77✔
1134
                // existent index entry is deleted only if it differs from existent one
77✔
1135
                sameIndexKey := true
77✔
1136

77✔
1137
                for i, col := range index.cols {
159✔
1138
                        currVal, specified := currValuesByColID[col.id]
82✔
1139
                        if !specified {
82✔
1140
                                currVal = &NullValue{t: col.colType}
×
1141
                        }
×
1142

1143
                        newVal, specified := newValuesByColID[col.id]
82✔
1144
                        if !specified {
86✔
1145
                                newVal = &NullValue{t: col.colType}
4✔
1146
                        }
4✔
1147

1148
                        r, err := currVal.Compare(newVal)
82✔
1149
                        if err != nil {
82✔
1150
                                return nil, err
×
1151
                        }
×
1152

1153
                        sameIndexKey = sameIndexKey && r == 0
82✔
1154

82✔
1155
                        encVal, _, _ := EncodeValueAsKey(currVal, col.colType, col.MaxLen())
82✔
1156

82✔
1157
                        encodedValues[i+3] = encVal
82✔
1158
                }
1159

1160
                // mark existent index entry as deleted
1161
                if sameIndexKey {
127✔
1162
                        reusableIndexEntries[index.id] = struct{}{}
50✔
1163
                } else {
77✔
1164
                        md := store.NewKVMetadata()
27✔
1165

27✔
1166
                        md.AsDeleted(true)
27✔
1167

27✔
1168
                        err = tx.set(MapKey(tx.sqlPrefix(), MappedPrefix, encodedValues...), md, encodedRowValue)
27✔
1169
                        if err != nil {
27✔
1170
                                return nil, err
×
1171
                        }
×
1172
                }
1173
        }
1174

1175
        return reusableIndexEntries, nil
36✔
1176
}
1177

1178
type UpdateStmt struct {
1179
        tableRef *tableRef
1180
        where    ValueExp
1181
        updates  []*colUpdate
1182
        indexOn  []string
1183
        limit    ValueExp
1184
        offset   ValueExp
1185
}
1186

1187
type colUpdate struct {
1188
        col string
1189
        op  CmpOperator
1190
        val ValueExp
1191
}
1192

1193
func (stmt *UpdateStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
1194
        selectStmt := &SelectStmt{
1✔
1195
                ds:    stmt.tableRef,
1✔
1196
                where: stmt.where,
1✔
1197
        }
1✔
1198

1✔
1199
        err := selectStmt.inferParameters(ctx, tx, params)
1✔
1200
        if err != nil {
1✔
1201
                return err
×
1202
        }
×
1203

1204
        table, err := stmt.tableRef.referencedTable(tx)
1✔
1205
        if err != nil {
1✔
1206
                return err
×
1207
        }
×
1208

1209
        for _, update := range stmt.updates {
2✔
1210
                col, err := table.GetColumnByName(update.col)
1✔
1211
                if err != nil {
1✔
1212
                        return err
×
1213
                }
×
1214

1215
                err = update.val.requiresType(col.colType, make(map[string]ColDescriptor), params, table.name)
1✔
1216
                if err != nil {
1✔
1217
                        return err
×
1218
                }
×
1219
        }
1220

1221
        return nil
1✔
1222
}
1223

1224
func (stmt *UpdateStmt) validate(table *Table) error {
17✔
1225
        colIDs := make(map[uint32]struct{}, len(stmt.updates))
17✔
1226

17✔
1227
        for _, update := range stmt.updates {
34✔
1228
                if update.op != EQ {
17✔
1229
                        return ErrIllegalArguments
×
1230
                }
×
1231

1232
                col, err := table.GetColumnByName(update.col)
17✔
1233
                if err != nil {
18✔
1234
                        return err
1✔
1235
                }
1✔
1236

1237
                if table.PrimaryIndex().IncludesCol(col.id) {
16✔
1238
                        return ErrPKCanNotBeUpdated
×
1239
                }
×
1240

1241
                _, duplicated := colIDs[col.id]
16✔
1242
                if duplicated {
16✔
1243
                        return ErrDuplicatedColumn
×
1244
                }
×
1245

1246
                colIDs[col.id] = struct{}{}
16✔
1247
        }
1248

1249
        return nil
16✔
1250
}
1251

1252
func (stmt *UpdateStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
18✔
1253
        selectStmt := &SelectStmt{
18✔
1254
                ds:      stmt.tableRef,
18✔
1255
                where:   stmt.where,
18✔
1256
                indexOn: stmt.indexOn,
18✔
1257
                limit:   stmt.limit,
18✔
1258
                offset:  stmt.offset,
18✔
1259
        }
18✔
1260

18✔
1261
        rowReader, err := selectStmt.Resolve(ctx, tx, params, nil)
18✔
1262
        if err != nil {
19✔
1263
                return nil, err
1✔
1264
        }
1✔
1265
        defer rowReader.Close()
17✔
1266

17✔
1267
        table := rowReader.ScanSpecs().Index.table
17✔
1268

17✔
1269
        err = stmt.validate(table)
17✔
1270
        if err != nil {
18✔
1271
                return nil, err
1✔
1272
        }
1✔
1273

1274
        cols, err := rowReader.colsBySelector(ctx)
16✔
1275
        if err != nil {
16✔
1276
                return nil, err
×
1277
        }
×
1278

1279
        for {
58✔
1280
                row, err := rowReader.Read(ctx)
42✔
1281
                if errors.Is(err, ErrNoMoreRows) {
57✔
1282
                        break
15✔
1283
                } else if err != nil {
28✔
1284
                        return nil, err
1✔
1285
                }
1✔
1286

1287
                valuesByColID := make(map[uint32]TypedValue, len(row.ValuesBySelector))
26✔
1288

26✔
1289
                for _, col := range table.cols {
87✔
1290
                        encSel := EncodeSelector("", table.name, col.colName)
61✔
1291
                        valuesByColID[col.id] = row.ValuesBySelector[encSel]
61✔
1292
                }
61✔
1293

1294
                for _, update := range stmt.updates {
52✔
1295
                        col, err := table.GetColumnByName(update.col)
26✔
1296
                        if err != nil {
26✔
1297
                                return nil, err
×
1298
                        }
×
1299

1300
                        sval, err := update.val.substitute(params)
26✔
1301
                        if err != nil {
26✔
1302
                                return nil, err
×
1303
                        }
×
1304

1305
                        rval, err := sval.reduce(tx, row, table.name)
26✔
1306
                        if err != nil {
26✔
1307
                                return nil, err
×
1308
                        }
×
1309

1310
                        err = rval.requiresType(col.colType, cols, nil, table.name)
26✔
1311
                        if err != nil {
26✔
1312
                                return nil, err
×
1313
                        }
×
1314

1315
                        valuesByColID[col.id] = rval
26✔
1316
                }
1317

1318
                pkEncVals, err := encodedKey(table.primaryIndex, valuesByColID)
26✔
1319
                if err != nil {
26✔
1320
                        return nil, err
×
1321
                }
×
1322

1323
                // primary index entry
1324
                mkey := MapKey(tx.sqlPrefix(), MappedPrefix, EncodeID(table.id), EncodeID(table.primaryIndex.id), pkEncVals, pkEncVals)
26✔
1325

26✔
1326
                // mkey must exist
26✔
1327
                _, err = tx.get(ctx, mkey)
26✔
1328
                if err != nil {
26✔
1329
                        return nil, err
×
1330
                }
×
1331

1332
                err = tx.doUpsert(ctx, pkEncVals, valuesByColID, table, true)
26✔
1333
                if err != nil {
26✔
1334
                        return nil, err
×
1335
                }
×
1336
        }
1337

1338
        return tx, nil
15✔
1339
}
1340

1341
type DeleteFromStmt struct {
1342
        tableRef *tableRef
1343
        where    ValueExp
1344
        indexOn  []string
1345
        orderBy  []*OrdCol
1346
        limit    ValueExp
1347
        offset   ValueExp
1348
}
1349

1350
func NewDeleteFromStmt(table string, where ValueExp, orderBy []*OrdCol, limit ValueExp) *DeleteFromStmt {
4✔
1351
        return &DeleteFromStmt{
4✔
1352
                tableRef: NewTableRef(table, ""),
4✔
1353
                where:    where,
4✔
1354
                orderBy:  orderBy,
4✔
1355
                limit:    limit,
4✔
1356
        }
4✔
1357
}
4✔
1358

1359
func (stmt *DeleteFromStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
1360
        selectStmt := &SelectStmt{
1✔
1361
                ds:      stmt.tableRef,
1✔
1362
                where:   stmt.where,
1✔
1363
                orderBy: stmt.orderBy,
1✔
1364
        }
1✔
1365
        return selectStmt.inferParameters(ctx, tx, params)
1✔
1366
}
1✔
1367

1368
func (stmt *DeleteFromStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
15✔
1369
        selectStmt := &SelectStmt{
15✔
1370
                ds:      stmt.tableRef,
15✔
1371
                where:   stmt.where,
15✔
1372
                indexOn: stmt.indexOn,
15✔
1373
                orderBy: stmt.orderBy,
15✔
1374
                limit:   stmt.limit,
15✔
1375
                offset:  stmt.offset,
15✔
1376
        }
15✔
1377

15✔
1378
        rowReader, err := selectStmt.Resolve(ctx, tx, params, nil)
15✔
1379
        if err != nil {
17✔
1380
                return nil, err
2✔
1381
        }
2✔
1382
        defer rowReader.Close()
13✔
1383

13✔
1384
        table := rowReader.ScanSpecs().Index.table
13✔
1385

13✔
1386
        for {
147✔
1387
                row, err := rowReader.Read(ctx)
134✔
1388
                if errors.Is(err, ErrNoMoreRows) {
146✔
1389
                        break
12✔
1390
                }
1391
                if err != nil {
123✔
1392
                        return nil, err
1✔
1393
                }
1✔
1394

1395
                valuesByColID := make(map[uint32]TypedValue, len(row.ValuesBySelector))
121✔
1396

121✔
1397
                for _, col := range table.cols {
406✔
1398
                        encSel := EncodeSelector("", table.name, col.colName)
285✔
1399
                        valuesByColID[col.id] = row.ValuesBySelector[encSel]
285✔
1400
                }
285✔
1401

1402
                pkEncVals, err := encodedKey(table.primaryIndex, valuesByColID)
121✔
1403
                if err != nil {
121✔
1404
                        return nil, err
×
1405
                }
×
1406

1407
                err = tx.deleteIndexEntries(pkEncVals, valuesByColID, table)
121✔
1408
                if err != nil {
121✔
1409
                        return nil, err
×
1410
                }
×
1411

1412
                tx.updatedRows++
121✔
1413
        }
1414

1415
        return tx, nil
12✔
1416
}
1417

1418
func (tx *SQLTx) deleteIndexEntries(pkEncVals []byte, valuesByColID map[uint32]TypedValue, table *Table) error {
121✔
1419
        encodedRowValue, err := tx.encodeRowValue(valuesByColID, table)
121✔
1420
        if err != nil {
121✔
1421
                return err
×
1422
        }
×
1423

1424
        for _, index := range table.indexes {
291✔
1425
                if !index.IsPrimary() {
219✔
1426
                        continue
49✔
1427
                }
1428

1429
                encodedValues := make([][]byte, 3+len(index.cols))
121✔
1430
                encodedValues[0] = EncodeID(DatabaseID)
121✔
1431
                encodedValues[1] = EncodeID(table.id)
121✔
1432
                encodedValues[2] = EncodeID(index.id)
121✔
1433

121✔
1434
                for i, col := range index.cols {
242✔
1435
                        val, specified := valuesByColID[col.id]
121✔
1436
                        if !specified {
121✔
1437
                                val = &NullValue{t: col.colType}
×
1438
                        }
×
1439

1440
                        encVal, _, _ := EncodeValueAsKey(val, col.colType, col.MaxLen())
121✔
1441

121✔
1442
                        encodedValues[i+3] = encVal
121✔
1443
                }
1444

1445
                md := store.NewKVMetadata()
121✔
1446

121✔
1447
                md.AsDeleted(true)
121✔
1448

121✔
1449
                err := tx.set(MapKey(tx.sqlPrefix(), RowPrefix, encodedValues...), md, encodedRowValue)
121✔
1450
                if err != nil {
121✔
1451
                        return err
×
1452
                }
×
1453
        }
1454

1455
        return nil
121✔
1456
}
1457

1458
type ValueExp interface {
1459
        inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error)
1460
        requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error
1461
        substitute(params map[string]interface{}) (ValueExp, error)
1462
        reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error)
1463
        reduceSelectors(row *Row, implicitTable string) ValueExp
1464
        isConstant() bool
1465
        selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error
1466
}
1467

1468
type typedValueRange struct {
1469
        lRange *typedValueSemiRange
1470
        hRange *typedValueSemiRange
1471
}
1472

1473
type typedValueSemiRange struct {
1474
        val       TypedValue
1475
        inclusive bool
1476
}
1477

1478
func (r *typedValueRange) unitary() bool {
19✔
1479
        // TODO: this simplified implementation doesn't cover all unitary cases e.g. 3<=v<4
19✔
1480
        if r.lRange == nil || r.hRange == nil {
19✔
1481
                return false
×
1482
        }
×
1483

1484
        res, _ := r.lRange.val.Compare(r.hRange.val)
19✔
1485
        return res == 0 && r.lRange.inclusive && r.hRange.inclusive
19✔
1486
}
1487

1488
func (r *typedValueRange) refineWith(refiningRange *typedValueRange) error {
3✔
1489
        if r.lRange == nil {
4✔
1490
                r.lRange = refiningRange.lRange
1✔
1491
        } else if r.lRange != nil && refiningRange.lRange != nil {
4✔
1492
                maxRange, err := maxSemiRange(r.lRange, refiningRange.lRange)
1✔
1493
                if err != nil {
1✔
1494
                        return err
×
1495
                }
×
1496
                r.lRange = maxRange
1✔
1497
        }
1498

1499
        if r.hRange == nil {
4✔
1500
                r.hRange = refiningRange.hRange
1✔
1501
        } else if r.hRange != nil && refiningRange.hRange != nil {
5✔
1502
                minRange, err := minSemiRange(r.hRange, refiningRange.hRange)
2✔
1503
                if err != nil {
2✔
1504
                        return err
×
1505
                }
×
1506
                r.hRange = minRange
2✔
1507
        }
1508

1509
        return nil
3✔
1510
}
1511

1512
func (r *typedValueRange) extendWith(extendingRange *typedValueRange) error {
5✔
1513
        if r.lRange == nil || extendingRange.lRange == nil {
7✔
1514
                r.lRange = nil
2✔
1515
        } else {
5✔
1516
                minRange, err := minSemiRange(r.lRange, extendingRange.lRange)
3✔
1517
                if err != nil {
3✔
1518
                        return err
×
1519
                }
×
1520
                r.lRange = minRange
3✔
1521
        }
1522

1523
        if r.hRange == nil || extendingRange.hRange == nil {
8✔
1524
                r.hRange = nil
3✔
1525
        } else {
5✔
1526
                maxRange, err := maxSemiRange(r.hRange, extendingRange.hRange)
2✔
1527
                if err != nil {
2✔
1528
                        return err
×
1529
                }
×
1530
                r.hRange = maxRange
2✔
1531
        }
1532

1533
        return nil
5✔
1534
}
1535

1536
func maxSemiRange(or1, or2 *typedValueSemiRange) (*typedValueSemiRange, error) {
3✔
1537
        r, err := or1.val.Compare(or2.val)
3✔
1538
        if err != nil {
3✔
1539
                return nil, err
×
1540
        }
×
1541

1542
        maxVal := or1.val
3✔
1543
        if r < 0 {
5✔
1544
                maxVal = or2.val
2✔
1545
        }
2✔
1546

1547
        return &typedValueSemiRange{
3✔
1548
                val:       maxVal,
3✔
1549
                inclusive: or1.inclusive && or2.inclusive,
3✔
1550
        }, nil
3✔
1551
}
1552

1553
func minSemiRange(or1, or2 *typedValueSemiRange) (*typedValueSemiRange, error) {
5✔
1554
        r, err := or1.val.Compare(or2.val)
5✔
1555
        if err != nil {
5✔
1556
                return nil, err
×
1557
        }
×
1558

1559
        minVal := or1.val
5✔
1560
        if r > 0 {
9✔
1561
                minVal = or2.val
4✔
1562
        }
4✔
1563

1564
        return &typedValueSemiRange{
5✔
1565
                val:       minVal,
5✔
1566
                inclusive: or1.inclusive || or2.inclusive,
5✔
1567
        }, nil
5✔
1568
}
1569

1570
type TypedValue interface {
1571
        ValueExp
1572
        Type() SQLValueType
1573
        RawValue() interface{}
1574
        Compare(val TypedValue) (int, error)
1575
        IsNull() bool
1576
        String() string
1577
}
1578

1579
type Tuple []TypedValue
1580

1581
func (t Tuple) Compare(other Tuple) (int, int, error) {
85,700✔
1582
        if len(t) != len(other) {
85,700✔
1583
                return -1, -1, ErrNotComparableValues
×
1584
        }
×
1585

1586
        for i := range t {
187,354✔
1587
                res, err := t[i].Compare(other[i])
101,654✔
1588
                if err != nil || res != 0 {
179,729✔
1589
                        return res, i, err
78,075✔
1590
                }
78,075✔
1591
        }
1592
        return 0, -1, nil
7,625✔
1593
}
1594

1595
func NewNull(t SQLValueType) *NullValue {
102✔
1596
        return &NullValue{t: t}
102✔
1597
}
102✔
1598

1599
type NullValue struct {
1600
        t SQLValueType
1601
}
1602

1603
func (n *NullValue) Type() SQLValueType {
66✔
1604
        return n.t
66✔
1605
}
66✔
1606

1607
func (n *NullValue) RawValue() interface{} {
250✔
1608
        return nil
250✔
1609
}
250✔
1610

1611
func (n *NullValue) IsNull() bool {
307✔
1612
        return true
307✔
1613
}
307✔
1614

1615
func (n *NullValue) String() string {
1✔
1616
        return "NULL"
1✔
1617
}
1✔
1618

1619
func (n *NullValue) Compare(val TypedValue) (int, error) {
68✔
1620
        if n.t != AnyType && val.Type() != AnyType && n.t != val.Type() {
69✔
1621
                return 0, ErrNotComparableValues
1✔
1622
        }
1✔
1623

1624
        if val.RawValue() == nil {
97✔
1625
                return 0, nil
30✔
1626
        }
30✔
1627
        return -1, nil
37✔
1628
}
1629

1630
func (v *NullValue) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
5✔
1631
        return v.t, nil
5✔
1632
}
5✔
1633

1634
func (v *NullValue) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
8✔
1635
        if v.t == t {
13✔
1636
                return nil
5✔
1637
        }
5✔
1638

1639
        if v.t != AnyType {
4✔
1640
                return ErrInvalidTypes
1✔
1641
        }
1✔
1642

1643
        v.t = t
2✔
1644

2✔
1645
        return nil
2✔
1646
}
1647

1648
func (v *NullValue) substitute(params map[string]interface{}) (ValueExp, error) {
278✔
1649
        return v, nil
278✔
1650
}
278✔
1651

1652
func (v *NullValue) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
201✔
1653
        return v, nil
201✔
1654
}
201✔
1655

1656
func (v *NullValue) reduceSelectors(row *Row, implicitTable string) ValueExp {
10✔
1657
        return v
10✔
1658
}
10✔
1659

1660
func (v *NullValue) isConstant() bool {
12✔
1661
        return true
12✔
1662
}
12✔
1663

1664
func (v *NullValue) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1665
        return nil
1✔
1666
}
1✔
1667

1668
type Integer struct {
1669
        val int64
1670
}
1671

1672
func NewInteger(val int64) *Integer {
293✔
1673
        return &Integer{val: val}
293✔
1674
}
293✔
1675

1676
func (v *Integer) Type() SQLValueType {
164,274✔
1677
        return IntegerType
164,274✔
1678
}
164,274✔
1679

1680
func (v *Integer) IsNull() bool {
72,236✔
1681
        return false
72,236✔
1682
}
72,236✔
1683

1684
func (v *Integer) String() string {
11✔
1685
        return strconv.FormatInt(v.val, 10)
11✔
1686
}
11✔
1687

1688
func (v *Integer) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
19✔
1689
        return IntegerType, nil
19✔
1690
}
19✔
1691

1692
func (v *Integer) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
23✔
1693
        if t != IntegerType && t != JSONType {
27✔
1694
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
4✔
1695
        }
4✔
1696

1697
        return nil
19✔
1698
}
1699

1700
func (v *Integer) substitute(params map[string]interface{}) (ValueExp, error) {
2,145✔
1701
        return v, nil
2,145✔
1702
}
2,145✔
1703

1704
func (v *Integer) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
3,859✔
1705
        return v, nil
3,859✔
1706
}
3,859✔
1707

1708
func (v *Integer) reduceSelectors(row *Row, implicitTable string) ValueExp {
6✔
1709
        return v
6✔
1710
}
6✔
1711

1712
func (v *Integer) isConstant() bool {
113✔
1713
        return true
113✔
1714
}
113✔
1715

1716
func (v *Integer) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1717
        return nil
1✔
1718
}
1✔
1719

1720
func (v *Integer) RawValue() interface{} {
110,643✔
1721
        return v.val
110,643✔
1722
}
110,643✔
1723

1724
func (v *Integer) Compare(val TypedValue) (int, error) {
51,015✔
1725
        if val.IsNull() {
51,058✔
1726
                return 1, nil
43✔
1727
        }
43✔
1728

1729
        if val.Type() == JSONType {
50,973✔
1730
                res, err := val.Compare(v)
1✔
1731
                return -res, err
1✔
1732
        }
1✔
1733

1734
        if val.Type() == Float64Type {
50,971✔
1735
                r, err := val.Compare(v)
×
1736
                return r * -1, err
×
1737
        }
×
1738

1739
        if val.Type() != IntegerType {
50,978✔
1740
                return 0, ErrNotComparableValues
7✔
1741
        }
7✔
1742

1743
        rval := val.RawValue().(int64)
50,964✔
1744

50,964✔
1745
        if v.val == rval {
63,334✔
1746
                return 0, nil
12,370✔
1747
        }
12,370✔
1748

1749
        if v.val > rval {
57,703✔
1750
                return 1, nil
19,109✔
1751
        }
19,109✔
1752

1753
        return -1, nil
19,485✔
1754
}
1755

1756
type Timestamp struct {
1757
        val time.Time
1758
}
1759

1760
func (v *Timestamp) Type() SQLValueType {
19,456✔
1761
        return TimestampType
19,456✔
1762
}
19,456✔
1763

1764
func (v *Timestamp) IsNull() bool {
17,763✔
1765
        return false
17,763✔
1766
}
17,763✔
1767

1768
func (v *Timestamp) String() string {
1✔
1769
        return v.val.Format("2006-01-02 15:04:05.999999")
1✔
1770
}
1✔
1771

1772
func (v *Timestamp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
1773
        return TimestampType, nil
1✔
1774
}
1✔
1775

1776
func (v *Timestamp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
1777
        if t != TimestampType {
3✔
1778
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, TimestampType, t)
1✔
1779
        }
1✔
1780

1781
        return nil
1✔
1782
}
1783

1784
func (v *Timestamp) substitute(params map[string]interface{}) (ValueExp, error) {
120✔
1785
        return v, nil
120✔
1786
}
120✔
1787

1788
func (v *Timestamp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
969✔
1789
        return v, nil
969✔
1790
}
969✔
1791

1792
func (v *Timestamp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
1793
        return v
1✔
1794
}
1✔
1795

1796
func (v *Timestamp) isConstant() bool {
1✔
1797
        return true
1✔
1798
}
1✔
1799

1800
func (v *Timestamp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1801
        return nil
1✔
1802
}
1✔
1803

1804
func (v *Timestamp) RawValue() interface{} {
31,773✔
1805
        return v.val
31,773✔
1806
}
31,773✔
1807

1808
func (v *Timestamp) Compare(val TypedValue) (int, error) {
14,979✔
1809
        if val.IsNull() {
14,981✔
1810
                return 1, nil
2✔
1811
        }
2✔
1812

1813
        if val.Type() != TimestampType {
14,978✔
1814
                return 0, ErrNotComparableValues
1✔
1815
        }
1✔
1816

1817
        rval := val.RawValue().(time.Time)
14,976✔
1818

14,976✔
1819
        if v.val.Before(rval) {
22,214✔
1820
                return -1, nil
7,238✔
1821
        }
7,238✔
1822

1823
        if v.val.After(rval) {
15,397✔
1824
                return 1, nil
7,659✔
1825
        }
7,659✔
1826

1827
        return 0, nil
79✔
1828
}
1829

1830
type Varchar struct {
1831
        val string
1832
}
1833

1834
func NewVarchar(val string) *Varchar {
1,543✔
1835
        return &Varchar{val: val}
1,543✔
1836
}
1,543✔
1837

1838
func (v *Varchar) Type() SQLValueType {
84,327✔
1839
        return VarcharType
84,327✔
1840
}
84,327✔
1841

1842
func (v *Varchar) IsNull() bool {
43,342✔
1843
        return false
43,342✔
1844
}
43,342✔
1845

1846
func (v *Varchar) String() string {
12✔
1847
        return v.val
12✔
1848
}
12✔
1849

1850
func (v *Varchar) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
16✔
1851
        return VarcharType, nil
16✔
1852
}
16✔
1853

1854
func (v *Varchar) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
100✔
1855
        if t != VarcharType && t != JSONType {
102✔
1856
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
2✔
1857
        }
2✔
1858
        return nil
98✔
1859
}
1860

1861
func (v *Varchar) substitute(params map[string]interface{}) (ValueExp, error) {
1,554✔
1862
        return v, nil
1,554✔
1863
}
1,554✔
1864

1865
func (v *Varchar) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
2,495✔
1866
        return v, nil
2,495✔
1867
}
2,495✔
1868

1869
func (v *Varchar) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
1870
        return v
×
1871
}
×
1872

1873
func (v *Varchar) isConstant() bool {
38✔
1874
        return true
38✔
1875
}
38✔
1876

1877
func (v *Varchar) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1878
        return nil
1✔
1879
}
1✔
1880

1881
func (v *Varchar) RawValue() interface{} {
59,333✔
1882
        return v.val
59,333✔
1883
}
59,333✔
1884

1885
func (v *Varchar) Compare(val TypedValue) (int, error) {
39,668✔
1886
        if val.IsNull() {
39,688✔
1887
                return 1, nil
20✔
1888
        }
20✔
1889

1890
        if val.Type() == JSONType {
40,649✔
1891
                res, err := val.Compare(v)
1,001✔
1892
                return -res, err
1,001✔
1893
        }
1,001✔
1894

1895
        if val.Type() != VarcharType {
38,648✔
1896
                return 0, ErrNotComparableValues
1✔
1897
        }
1✔
1898

1899
        rval := val.RawValue().(string)
38,646✔
1900

38,646✔
1901
        return bytes.Compare([]byte(v.val), []byte(rval)), nil
38,646✔
1902
}
1903

1904
type UUID struct {
1905
        val uuid.UUID
1906
}
1907

1908
func NewUUID(val uuid.UUID) *UUID {
1✔
1909
        return &UUID{val: val}
1✔
1910
}
1✔
1911

1912
func (v *UUID) Type() SQLValueType {
10✔
1913
        return UUIDType
10✔
1914
}
10✔
1915

1916
func (v *UUID) IsNull() bool {
26✔
1917
        return false
26✔
1918
}
26✔
1919

1920
func (v *UUID) String() string {
1✔
1921
        return v.val.String()
1✔
1922
}
1✔
1923

1924
func (v *UUID) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
1925
        return UUIDType, nil
1✔
1926
}
1✔
1927

1928
func (v *UUID) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
4✔
1929
        if t != UUIDType {
6✔
1930
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, UUIDType, t)
2✔
1931
        }
2✔
1932

1933
        return nil
2✔
1934
}
1935

1936
func (v *UUID) substitute(params map[string]interface{}) (ValueExp, error) {
2✔
1937
        return v, nil
2✔
1938
}
2✔
1939

1940
func (v *UUID) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1✔
1941
        return v, nil
1✔
1942
}
1✔
1943

1944
func (v *UUID) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
1945
        return v
1✔
1946
}
1✔
1947

1948
func (v *UUID) isConstant() bool {
1✔
1949
        return true
1✔
1950
}
1✔
1951

1952
func (v *UUID) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1953
        return nil
1✔
1954
}
1✔
1955

1956
func (v *UUID) RawValue() interface{} {
40✔
1957
        return v.val
40✔
1958
}
40✔
1959

1960
func (v *UUID) Compare(val TypedValue) (int, error) {
5✔
1961
        if val.IsNull() {
7✔
1962
                return 1, nil
2✔
1963
        }
2✔
1964

1965
        if val.Type() != UUIDType {
4✔
1966
                return 0, ErrNotComparableValues
1✔
1967
        }
1✔
1968

1969
        rval := val.RawValue().(uuid.UUID)
2✔
1970

2✔
1971
        return bytes.Compare(v.val[:], rval[:]), nil
2✔
1972
}
1973

1974
type Bool struct {
1975
        val bool
1976
}
1977

1978
func NewBool(val bool) *Bool {
106✔
1979
        return &Bool{val: val}
106✔
1980
}
106✔
1981

1982
func (v *Bool) Type() SQLValueType {
557✔
1983
        return BooleanType
557✔
1984
}
557✔
1985

1986
func (v *Bool) IsNull() bool {
914✔
1987
        return false
914✔
1988
}
914✔
1989

1990
func (v *Bool) String() string {
3✔
1991
        return strconv.FormatBool(v.val)
3✔
1992
}
3✔
1993

1994
func (v *Bool) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
24✔
1995
        return BooleanType, nil
24✔
1996
}
24✔
1997

1998
func (v *Bool) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
49✔
1999
        if t != BooleanType && t != JSONType {
54✔
2000
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
5✔
2001
        }
5✔
2002
        return nil
44✔
2003
}
2004

2005
func (v *Bool) substitute(params map[string]interface{}) (ValueExp, error) {
392✔
2006
        return v, nil
392✔
2007
}
392✔
2008

2009
func (v *Bool) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
488✔
2010
        return v, nil
488✔
2011
}
488✔
2012

2013
func (v *Bool) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2014
        return v
×
2015
}
×
2016

2017
func (v *Bool) isConstant() bool {
3✔
2018
        return true
3✔
2019
}
3✔
2020

2021
func (v *Bool) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
7✔
2022
        return nil
7✔
2023
}
7✔
2024

2025
func (v *Bool) RawValue() interface{} {
895✔
2026
        return v.val
895✔
2027
}
895✔
2028

2029
func (v *Bool) Compare(val TypedValue) (int, error) {
212✔
2030
        if val.IsNull() {
242✔
2031
                return 1, nil
30✔
2032
        }
30✔
2033

2034
        if val.Type() == JSONType {
183✔
2035
                res, err := val.Compare(v)
1✔
2036
                return -res, err
1✔
2037
        }
1✔
2038

2039
        if val.Type() != BooleanType {
181✔
UNCOV
2040
                return 0, ErrNotComparableValues
×
UNCOV
2041
        }
×
2042

2043
        rval := val.RawValue().(bool)
181✔
2044

181✔
2045
        if v.val == rval {
287✔
2046
                return 0, nil
106✔
2047
        }
106✔
2048

2049
        if v.val {
81✔
2050
                return 1, nil
6✔
2051
        }
6✔
2052

2053
        return -1, nil
69✔
2054
}
2055

2056
type Blob struct {
2057
        val []byte
2058
}
2059

2060
func NewBlob(val []byte) *Blob {
286✔
2061
        return &Blob{val: val}
286✔
2062
}
286✔
2063

2064
func (v *Blob) Type() SQLValueType {
52✔
2065
        return BLOBType
52✔
2066
}
52✔
2067

2068
func (v *Blob) IsNull() bool {
2,312✔
2069
        return false
2,312✔
2070
}
2,312✔
2071

2072
func (v *Blob) String() string {
2✔
2073
        return hex.EncodeToString(v.val)
2✔
2074
}
2✔
2075

2076
func (v *Blob) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
2077
        return BLOBType, nil
1✔
2078
}
1✔
2079

2080
func (v *Blob) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
2081
        if t != BLOBType {
3✔
2082
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BLOBType, t)
1✔
2083
        }
1✔
2084

2085
        return nil
1✔
2086
}
2087

2088
func (v *Blob) substitute(params map[string]interface{}) (ValueExp, error) {
358✔
2089
        return v, nil
358✔
2090
}
358✔
2091

2092
func (v *Blob) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
370✔
2093
        return v, nil
370✔
2094
}
370✔
2095

2096
func (v *Blob) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2097
        return v
×
2098
}
×
2099

2100
func (v *Blob) isConstant() bool {
7✔
2101
        return true
7✔
2102
}
7✔
2103

2104
func (v *Blob) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
×
2105
        return nil
×
2106
}
×
2107

2108
func (v *Blob) RawValue() interface{} {
2,570✔
2109
        return v.val
2,570✔
2110
}
2,570✔
2111

2112
func (v *Blob) Compare(val TypedValue) (int, error) {
25✔
2113
        if val.IsNull() {
25✔
UNCOV
2114
                return 1, nil
×
UNCOV
2115
        }
×
2116

2117
        if val.Type() != BLOBType {
25✔
2118
                return 0, ErrNotComparableValues
×
2119
        }
×
2120

2121
        rval := val.RawValue().([]byte)
25✔
2122

25✔
2123
        return bytes.Compare(v.val, rval), nil
25✔
2124
}
2125

2126
type Float64 struct {
2127
        val float64
2128
}
2129

2130
func NewFloat64(val float64) *Float64 {
1,149✔
2131
        return &Float64{val: val}
1,149✔
2132
}
1,149✔
2133

2134
func (v *Float64) Type() SQLValueType {
5,798✔
2135
        return Float64Type
5,798✔
2136
}
5,798✔
2137

2138
func (v *Float64) IsNull() bool {
2,763✔
2139
        return false
2,763✔
2140
}
2,763✔
2141

2142
func (v *Float64) String() string {
1✔
2143
        return strconv.FormatFloat(float64(v.val), 'f', -1, 64)
1✔
2144
}
1✔
2145

2146
func (v *Float64) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
2147
        return Float64Type, nil
1✔
2148
}
1✔
2149

2150
func (v *Float64) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
2151
        if t != Float64Type && t != JSONType {
3✔
2152
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, Float64Type, t)
1✔
2153
        }
1✔
2154
        return nil
1✔
2155
}
2156

2157
func (v *Float64) substitute(params map[string]interface{}) (ValueExp, error) {
76✔
2158
        return v, nil
76✔
2159
}
76✔
2160

2161
func (v *Float64) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
939✔
2162
        return v, nil
939✔
2163
}
939✔
2164

2165
func (v *Float64) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
2166
        return v
1✔
2167
}
1✔
2168

2169
func (v *Float64) isConstant() bool {
5✔
2170
        return true
5✔
2171
}
5✔
2172

2173
func (v *Float64) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
2174
        return nil
1✔
2175
}
1✔
2176

2177
func (v *Float64) RawValue() interface{} {
18,696✔
2178
        return v.val
18,696✔
2179
}
18,696✔
2180

2181
func (v *Float64) Compare(val TypedValue) (int, error) {
772✔
2182
        if val.Type() == JSONType {
773✔
2183
                res, err := val.Compare(v)
1✔
2184
                return -res, err
1✔
2185
        }
1✔
2186

2187
        convVal, err := mayApplyImplicitConversion(val.RawValue(), Float64Type)
771✔
2188
        if err != nil {
772✔
2189
                return 0, err
1✔
2190
        }
1✔
2191

2192
        if convVal == nil {
773✔
2193
                return 1, nil
3✔
2194
        }
3✔
2195

2196
        rval, ok := convVal.(float64)
767✔
2197
        if !ok {
767✔
2198
                return 0, ErrNotComparableValues
×
2199
        }
×
2200

2201
        if v.val == rval {
778✔
2202
                return 0, nil
11✔
2203
        }
11✔
2204

2205
        if v.val > rval {
1,097✔
2206
                return 1, nil
341✔
2207
        }
341✔
2208

2209
        return -1, nil
415✔
2210
}
2211

2212
type FnCall struct {
2213
        fn     string
2214
        params []ValueExp
2215
}
2216

2217
func (v *FnCall) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
15✔
2218
        if strings.ToUpper(v.fn) == NowFnCall {
29✔
2219
                return TimestampType, nil
14✔
2220
        }
14✔
2221

2222
        if strings.ToUpper(v.fn) == UUIDFnCall {
1✔
2223
                return UUIDType, nil
×
2224
        }
×
2225

2226
        if strings.ToUpper(v.fn) == JSONTypeOfFnCall {
1✔
NEW
2227
                return VarcharType, nil
×
NEW
2228
        }
×
2229

2230
        return AnyType, fmt.Errorf("%w: unknown function %s", ErrIllegalArguments, v.fn)
1✔
2231
}
2232

2233
func (v *FnCall) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
4✔
2234
        if strings.ToUpper(v.fn) == NowFnCall {
6✔
2235
                if t != TimestampType {
3✔
2236
                        return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, TimestampType, t)
1✔
2237
                }
1✔
2238

2239
                return nil
1✔
2240
        }
2241

2242
        if strings.ToUpper(v.fn) == UUIDFnCall {
2✔
2243
                if t != UUIDType {
×
2244
                        return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, UUIDType, t)
×
2245
                }
×
2246

2247
                return nil
×
2248
        }
2249

2250
        if strings.ToUpper(v.fn) == JSONTypeOfFnCall {
2✔
NEW
2251
                if t != VarcharType {
×
NEW
2252
                        return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
2253
                }
×
NEW
2254
                return nil
×
2255
        }
2256

2257
        return fmt.Errorf("%w: unkown function %s", ErrIllegalArguments, v.fn)
2✔
2258
}
2259

2260
func (v *FnCall) substitute(params map[string]interface{}) (val ValueExp, err error) {
399✔
2261
        ps := make([]ValueExp, len(v.params))
399✔
2262

399✔
2263
        for i, p := range v.params {
699✔
2264
                ps[i], err = p.substitute(params)
300✔
2265
                if err != nil {
300✔
2266
                        return nil, err
×
2267
                }
×
2268
        }
2269

2270
        return &FnCall{
399✔
2271
                fn:     v.fn,
399✔
2272
                params: ps,
399✔
2273
        }, nil
399✔
2274
}
2275

2276
func (v *FnCall) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
399✔
2277
        if strings.ToUpper(v.fn) == NowFnCall {
494✔
2278
                if len(v.params) > 0 {
95✔
2279
                        return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, NowFnCall, len(v.params))
×
2280
                }
×
2281
                return &Timestamp{val: tx.Timestamp().Truncate(time.Microsecond).UTC()}, nil
95✔
2282
        }
2283

2284
        if strings.ToUpper(v.fn) == UUIDFnCall {
307✔
2285
                if len(v.params) > 0 {
3✔
2286
                        return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, UUIDFnCall, len(v.params))
×
2287
                }
×
2288
                return &UUID{val: uuid.New()}, nil
3✔
2289
        }
2290

2291
        if strings.ToUpper(v.fn) == JSONTypeOfFnCall {
601✔
2292
                if len(v.params) != 1 {
300✔
NEW
2293
                        return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, JSONTypeOfFnCall, 1, len(v.params))
×
NEW
2294
                }
×
2295

2296
                v, err := v.params[0].reduce(tx, row, implicitTable)
300✔
2297
                if err != nil {
300✔
NEW
2298
                        return nil, err
×
NEW
2299
                }
×
2300

2301
                if v.IsNull() {
300✔
NEW
2302
                        return NewNull(AnyType), nil
×
NEW
2303
                }
×
2304

2305
                jsonVal, ok := v.(*JSON)
300✔
2306
                if !ok {
300✔
NEW
2307
                        return nil, fmt.Errorf("%w: '%s' function expects an argument of type JSON", ErrIllegalArguments, JSONTypeOfFnCall)
×
NEW
2308
                }
×
2309
                return NewVarchar(jsonVal.primitiveType()), nil
300✔
2310
        }
2311
        return nil, fmt.Errorf("%w: unkown function %s", ErrIllegalArguments, v.fn)
1✔
2312
}
2313

2314
func (v *FnCall) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2315
        return v
×
2316
}
×
2317

2318
func (v *FnCall) isConstant() bool {
13✔
2319
        return false
13✔
2320
}
13✔
2321

2322
func (v *FnCall) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
×
2323
        return nil
×
2324
}
×
2325

2326
type Cast struct {
2327
        val ValueExp
2328
        t   SQLValueType
2329
}
2330

2331
func (c *Cast) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
11✔
2332
        _, err := c.val.inferType(cols, params, implicitTable)
11✔
2333
        if err != nil {
12✔
2334
                return AnyType, err
1✔
2335
        }
1✔
2336

2337
        // val type may be restricted by compatible conversions, but multiple types may be compatible...
2338

2339
        return c.t, nil
10✔
2340
}
2341

2342
func (c *Cast) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
2343
        if c.t != t {
×
2344
                return fmt.Errorf("%w: can not use value cast to %s as %s", ErrInvalidTypes, c.t, t)
×
2345
        }
×
2346

2347
        return nil
×
2348
}
2349

2350
func (c *Cast) substitute(params map[string]interface{}) (ValueExp, error) {
48✔
2351
        val, err := c.val.substitute(params)
48✔
2352
        if err != nil {
48✔
2353
                return nil, err
×
2354
        }
×
2355
        c.val = val
48✔
2356
        return c, nil
48✔
2357
}
2358

2359
func (c *Cast) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
48✔
2360
        val, err := c.val.reduce(tx, row, implicitTable)
48✔
2361
        if err != nil {
48✔
2362
                return nil, err
×
2363
        }
×
2364

2365
        conv, err := getConverter(val.Type(), c.t)
48✔
2366
        if conv == nil {
51✔
2367
                return nil, err
3✔
2368
        }
3✔
2369

2370
        return conv(val)
45✔
2371
}
2372

2373
func (c *Cast) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2374
        return &Cast{
×
2375
                val: c.val.reduceSelectors(row, implicitTable),
×
2376
                t:   c.t,
×
2377
        }
×
2378
}
×
2379

2380
func (c *Cast) isConstant() bool {
7✔
2381
        return c.val.isConstant()
7✔
2382
}
7✔
2383

2384
func (c *Cast) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
×
2385
        return nil
×
2386
}
×
2387

2388
type Param struct {
2389
        id  string
2390
        pos int
2391
}
2392

2393
func (v *Param) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
59✔
2394
        t, ok := params[v.id]
59✔
2395
        if !ok {
116✔
2396
                params[v.id] = AnyType
57✔
2397
                return AnyType, nil
57✔
2398
        }
57✔
2399

2400
        return t, nil
2✔
2401
}
2402

2403
func (v *Param) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
76✔
2404
        currT, ok := params[v.id]
76✔
2405
        if ok && currT != t && currT != AnyType {
80✔
2406
                return ErrInferredMultipleTypes
4✔
2407
        }
4✔
2408

2409
        params[v.id] = t
72✔
2410

72✔
2411
        return nil
72✔
2412
}
2413

2414
func (p *Param) substitute(params map[string]interface{}) (ValueExp, error) {
4,769✔
2415
        val, ok := params[p.id]
4,769✔
2416
        if !ok {
4,831✔
2417
                return nil, fmt.Errorf("%w(%s)", ErrMissingParameter, p.id)
62✔
2418
        }
62✔
2419

2420
        if val == nil {
4,740✔
2421
                return &NullValue{t: AnyType}, nil
33✔
2422
        }
33✔
2423

2424
        switch v := val.(type) {
4,674✔
2425
        case bool:
96✔
2426
                {
192✔
2427
                        return &Bool{val: v}, nil
96✔
2428
                }
96✔
2429
        case string:
1,039✔
2430
                {
2,078✔
2431
                        return &Varchar{val: v}, nil
1,039✔
2432
                }
1,039✔
2433
        case int:
1,651✔
2434
                {
3,302✔
2435
                        return &Integer{val: int64(v)}, nil
1,651✔
2436
                }
1,651✔
2437
        case uint:
×
2438
                {
×
2439
                        return &Integer{val: int64(v)}, nil
×
2440
                }
×
2441
        case uint64:
34✔
2442
                {
68✔
2443
                        return &Integer{val: int64(v)}, nil
34✔
2444
                }
34✔
2445
        case int64:
125✔
2446
                {
250✔
2447
                        return &Integer{val: v}, nil
125✔
2448
                }
125✔
2449
        case []byte:
14✔
2450
                {
28✔
2451
                        return &Blob{val: v}, nil
14✔
2452
                }
14✔
2453
        case time.Time:
850✔
2454
                {
1,700✔
2455
                        return &Timestamp{val: v.Truncate(time.Microsecond).UTC()}, nil
850✔
2456
                }
850✔
2457
        case float64:
864✔
2458
                {
1,728✔
2459
                        return &Float64{val: v}, nil
864✔
2460
                }
864✔
2461
        }
2462
        return nil, ErrUnsupportedParameter
1✔
2463
}
2464

2465
func (p *Param) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
×
2466
        return nil, ErrUnexpected
×
2467
}
×
2468

2469
func (p *Param) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2470
        return p
×
2471
}
×
2472

2473
func (p *Param) isConstant() bool {
130✔
2474
        return true
130✔
2475
}
130✔
2476

2477
func (v *Param) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
5✔
2478
        return nil
5✔
2479
}
5✔
2480

2481
type Comparison int
2482

2483
const (
2484
        EqualTo Comparison = iota
2485
        LowerThan
2486
        LowerOrEqualTo
2487
        GreaterThan
2488
        GreaterOrEqualTo
2489
)
2490

2491
type DataSource interface {
2492
        SQLStmt
2493
        Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, scanSpecs *ScanSpecs) (RowReader, error)
2494
        Alias() string
2495
}
2496

2497
type SelectStmt struct {
2498
        distinct  bool
2499
        selectors []Selector
2500
        ds        DataSource
2501
        indexOn   []string
2502
        joins     []*JoinSpec
2503
        where     ValueExp
2504
        groupBy   []*ColSelector
2505
        having    ValueExp
2506
        orderBy   []*OrdCol
2507
        limit     ValueExp
2508
        offset    ValueExp
2509
        as        string
2510
}
2511

2512
func NewSelectStmt(
2513
        selectors []Selector,
2514
        ds DataSource,
2515
        where ValueExp,
2516
        orderBy []*OrdCol,
2517
        limit ValueExp,
2518
        offset ValueExp,
2519
) *SelectStmt {
71✔
2520
        return &SelectStmt{
71✔
2521
                selectors: selectors,
71✔
2522
                ds:        ds,
71✔
2523
                where:     where,
71✔
2524
                orderBy:   orderBy,
71✔
2525
                limit:     limit,
71✔
2526
                offset:    offset,
71✔
2527
        }
71✔
2528
}
71✔
2529

2530
func (stmt *SelectStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
52✔
2531
        _, err := stmt.execAt(ctx, tx, nil)
52✔
2532
        if err != nil {
52✔
2533
                return err
×
2534
        }
×
2535

2536
        // TODO (jeroiraz) may be optimized so to resolve the query statement just once
2537
        rowReader, err := stmt.Resolve(ctx, tx, nil, nil)
52✔
2538
        if err != nil {
52✔
2539
                return err
×
2540
        }
×
2541
        defer rowReader.Close()
52✔
2542

52✔
2543
        return rowReader.InferParameters(ctx, params)
52✔
2544
}
2545

2546
func (stmt *SelectStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
545✔
2547
        if stmt.groupBy == nil && stmt.having != nil {
546✔
2548
                return nil, ErrHavingClauseRequiresGroupClause
1✔
2549
        }
1✔
2550

2551
        if stmt.containsAggregations() || len(stmt.groupBy) > 0 {
629✔
2552
                for _, sel := range stmt.selectors {
227✔
2553
                        _, isAgg := sel.(*AggColSelector)
142✔
2554
                        if !isAgg && !stmt.groupByContains(sel) {
144✔
2555
                                return nil, fmt.Errorf("%s: %w", EncodeSelector(sel.resolve(stmt.Alias())), ErrColumnMustAppearInGroupByOrAggregation)
2✔
2556
                        }
2✔
2557
                }
2558
        }
2559

2560
        if len(stmt.orderBy) > 0 {
678✔
2561
                for _, col := range stmt.orderBy {
298✔
2562
                        sel := col.sel
162✔
2563
                        _, isAgg := sel.(*AggColSelector)
162✔
2564
                        if (isAgg && !stmt.containsSelector(sel)) || (!isAgg && len(stmt.groupBy) > 0 && !stmt.groupByContains(sel)) {
164✔
2565
                                return nil, fmt.Errorf("%s: %w", EncodeSelector(sel.resolve(stmt.Alias())), ErrColumnMustAppearInGroupByOrAggregation)
2✔
2566
                        }
2✔
2567
                }
2568
        }
2569
        return tx, nil
540✔
2570
}
2571

2572
func (stmt *SelectStmt) containsSelector(s Selector) bool {
4✔
2573
        encSel := EncodeSelector(s.resolve(stmt.Alias()))
4✔
2574

4✔
2575
        for _, sel := range stmt.selectors {
12✔
2576
                if EncodeSelector(sel.resolve(stmt.Alias())) == encSel {
11✔
2577
                        return true
3✔
2578
                }
3✔
2579
        }
2580
        return false
1✔
2581
}
2582

2583
func (stmt *SelectStmt) groupByContains(sel Selector) bool {
57✔
2584
        encSel := EncodeSelector(sel.resolve(stmt.Alias()))
57✔
2585

57✔
2586
        for _, colSel := range stmt.groupBy {
137✔
2587
                if EncodeSelector(colSel.resolve(stmt.Alias())) == encSel {
134✔
2588
                        return true
54✔
2589
                }
54✔
2590
        }
2591
        return false
3✔
2592
}
2593

2594
func (stmt *SelectStmt) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (ret RowReader, err error) {
764✔
2595
        scanSpecs, err := stmt.genScanSpecs(tx, params)
764✔
2596
        if err != nil {
778✔
2597
                return nil, err
14✔
2598
        }
14✔
2599

2600
        rowReader, err := stmt.ds.Resolve(ctx, tx, params, scanSpecs)
750✔
2601
        if err != nil {
751✔
2602
                return nil, err
1✔
2603
        }
1✔
2604
        defer func() {
1,498✔
2605
                if err != nil {
755✔
2606
                        rowReader.Close()
6✔
2607
                }
6✔
2608
        }()
2609

2610
        if stmt.joins != nil {
761✔
2611
                var jointRowReader *jointRowReader
12✔
2612
                jointRowReader, err = newJointRowReader(rowReader, stmt.joins)
12✔
2613
                if err != nil {
13✔
2614
                        return nil, err
1✔
2615
                }
1✔
2616
                rowReader = jointRowReader
11✔
2617
        }
2618

2619
        if stmt.where != nil {
1,155✔
2620
                rowReader = newConditionalRowReader(rowReader, stmt.where)
407✔
2621
        }
407✔
2622

2623
        if stmt.containsAggregations() || len(stmt.groupBy) > 0 {
828✔
2624
                if len(scanSpecs.groupBySortColumns) > 0 {
92✔
2625
                        var sortRowReader *sortRowReader
12✔
2626
                        sortRowReader, err = newSortRowReader(rowReader, scanSpecs.groupBySortColumns)
12✔
2627
                        if err != nil {
12✔
2628
                                return nil, err
×
2629
                        }
×
2630
                        rowReader = sortRowReader
12✔
2631
                }
2632

2633
                var groupedRowReader *groupedRowReader
80✔
2634
                groupedRowReader, err = newGroupedRowReader(rowReader, stmt.selectors, stmt.groupBy)
80✔
2635
                if err != nil {
82✔
2636
                        return nil, err
2✔
2637
                }
2✔
2638
                rowReader = groupedRowReader
78✔
2639

78✔
2640
                if stmt.having != nil {
82✔
2641
                        rowReader = newConditionalRowReader(rowReader, stmt.having)
4✔
2642
                }
4✔
2643
        }
2644

2645
        if len(scanSpecs.orderBySortCols) > 0 {
777✔
2646
                var sortRowReader *sortRowReader
31✔
2647
                sortRowReader, err = newSortRowReader(rowReader, stmt.orderBy)
31✔
2648
                if err != nil {
32✔
2649
                        return nil, err
1✔
2650
                }
1✔
2651
                rowReader = sortRowReader
30✔
2652
        }
2653

2654
        projectedRowReader, err := newProjectedRowReader(ctx, rowReader, stmt.as, stmt.selectors)
745✔
2655
        if err != nil {
746✔
2656
                return nil, err
1✔
2657
        }
1✔
2658
        rowReader = projectedRowReader
744✔
2659

744✔
2660
        if stmt.distinct {
752✔
2661
                var distinctRowReader *distinctRowReader
8✔
2662
                distinctRowReader, err = newDistinctRowReader(ctx, rowReader)
8✔
2663
                if err != nil {
9✔
2664
                        return nil, err
1✔
2665
                }
1✔
2666
                rowReader = distinctRowReader
7✔
2667
        }
2668

2669
        if stmt.offset != nil {
793✔
2670
                var offset int
50✔
2671
                offset, err = evalExpAsInt(tx, stmt.offset, params)
50✔
2672
                if err != nil {
50✔
2673
                        return nil, fmt.Errorf("%w: invalid offset", err)
×
2674
                }
×
2675

2676
                rowReader = newOffsetRowReader(rowReader, offset)
50✔
2677
        }
2678

2679
        if stmt.limit != nil {
839✔
2680
                var limit int
96✔
2681
                limit, err = evalExpAsInt(tx, stmt.limit, params)
96✔
2682
                if err != nil {
96✔
2683
                        return nil, fmt.Errorf("%w: invalid limit", err)
×
2684
                }
×
2685

2686
                if limit < 0 {
96✔
2687
                        return nil, fmt.Errorf("%w: invalid limit", ErrIllegalArguments)
×
2688
                }
×
2689

2690
                if limit > 0 {
138✔
2691
                        rowReader = newLimitRowReader(rowReader, limit)
42✔
2692
                }
42✔
2693
        }
2694

2695
        return rowReader, nil
743✔
2696
}
2697

2698
func (stmt *SelectStmt) rearrangeOrdColumns(groupByCols, orderByCols []*OrdCol) ([]*OrdCol, []*OrdCol) {
750✔
2699
        if len(groupByCols) > 0 && len(orderByCols) > 0 && !ordColumnsHaveAggregations(orderByCols) {
756✔
2700
                if ordColsHasPrefix(orderByCols, groupByCols, stmt.Alias()) {
8✔
2701
                        return orderByCols, nil
2✔
2702
                }
2✔
2703

2704
                if ordColsHasPrefix(groupByCols, orderByCols, stmt.Alias()) {
5✔
2705
                        for i := range orderByCols {
2✔
2706
                                groupByCols[i].descOrder = orderByCols[i].descOrder
1✔
2707
                        }
1✔
2708
                        return groupByCols, nil
1✔
2709
                }
2710
        }
2711
        return groupByCols, orderByCols
747✔
2712
}
2713

2714
func ordColsHasPrefix(cols, prefix []*OrdCol, table string) bool {
10✔
2715
        if len(prefix) > len(cols) {
12✔
2716
                return false
2✔
2717
        }
2✔
2718

2719
        for i := range prefix {
17✔
2720
                if EncodeSelector(prefix[i].sel.resolve(table)) != EncodeSelector(cols[i].sel.resolve(table)) {
14✔
2721
                        return false
5✔
2722
                }
5✔
2723
        }
2724
        return true
3✔
2725
}
2726

2727
func (stmt *SelectStmt) groupByOrdColumns() []*OrdCol {
764✔
2728
        groupByCols := stmt.groupBy
764✔
2729

764✔
2730
        ordCols := make([]*OrdCol, 0, len(groupByCols))
764✔
2731
        for _, col := range groupByCols {
811✔
2732
                ordCols = append(ordCols, &OrdCol{sel: col})
47✔
2733
        }
47✔
2734
        return ordCols
764✔
2735
}
2736

2737
func ordColumnsHaveAggregations(cols []*OrdCol) bool {
7✔
2738
        for _, ordCol := range cols {
17✔
2739
                if _, isAgg := ordCol.sel.(*AggColSelector); isAgg {
11✔
2740
                        return true
1✔
2741
                }
1✔
2742
        }
2743
        return false
6✔
2744
}
2745

2746
func (stmt *SelectStmt) containsAggregations() bool {
1,292✔
2747
        for _, sel := range stmt.selectors {
2,766✔
2748
                _, isAgg := sel.(*AggColSelector)
1,474✔
2749
                if isAgg {
1,637✔
2750
                        return true
163✔
2751
                }
163✔
2752
        }
2753
        return false
1,129✔
2754
}
2755

2756
func evalExpAsInt(tx *SQLTx, exp ValueExp, params map[string]interface{}) (int, error) {
146✔
2757
        offset, err := exp.substitute(params)
146✔
2758
        if err != nil {
146✔
2759
                return 0, err
×
2760
        }
×
2761

2762
        texp, err := offset.reduce(tx, nil, "")
146✔
2763
        if err != nil {
146✔
2764
                return 0, err
×
2765
        }
×
2766

2767
        convVal, err := mayApplyImplicitConversion(texp.RawValue(), IntegerType)
146✔
2768
        if err != nil {
146✔
2769
                return 0, ErrInvalidValue
×
2770
        }
×
2771

2772
        num, ok := convVal.(int64)
146✔
2773
        if !ok {
146✔
2774
                return 0, ErrInvalidValue
×
2775
        }
×
2776

2777
        if num > math.MaxInt32 {
146✔
2778
                return 0, ErrInvalidValue
×
2779
        }
×
2780

2781
        return int(num), nil
146✔
2782
}
2783

2784
func (stmt *SelectStmt) Alias() string {
167✔
2785
        if stmt.as == "" {
333✔
2786
                return stmt.ds.Alias()
166✔
2787
        }
166✔
2788

2789
        return stmt.as
1✔
2790
}
2791

2792
func (stmt *SelectStmt) hasTxMetadata() bool {
698✔
2793
        for _, sel := range stmt.selectors {
1,454✔
2794
                switch s := sel.(type) {
756✔
2795
                case *ColSelector:
650✔
2796
                        if s.col == txMetadataCol {
651✔
2797
                                return true
1✔
2798
                        }
1✔
2799
                case *JSONSelector:
13✔
2800
                        if s.ColSelector.col == txMetadataCol {
16✔
2801
                                return true
3✔
2802
                        }
3✔
2803
                }
2804
        }
2805
        return false
694✔
2806
}
2807

2808
func (stmt *SelectStmt) genScanSpecs(tx *SQLTx, params map[string]interface{}) (*ScanSpecs, error) {
764✔
2809
        groupByCols, orderByCols := stmt.groupByOrdColumns(), stmt.orderBy
764✔
2810

764✔
2811
        tableRef, isTableRef := stmt.ds.(*tableRef)
764✔
2812
        if !isTableRef {
816✔
2813
                groupByCols, orderByCols = stmt.rearrangeOrdColumns(groupByCols, orderByCols)
52✔
2814

52✔
2815
                return &ScanSpecs{
52✔
2816
                        groupBySortColumns: groupByCols,
52✔
2817
                        orderBySortCols:    orderByCols,
52✔
2818
                }, nil
52✔
2819
        }
52✔
2820

2821
        table, err := tableRef.referencedTable(tx)
712✔
2822
        if err != nil {
724✔
2823
                return nil, err
12✔
2824
        }
12✔
2825

2826
        rangesByColID := make(map[uint32]*typedValueRange)
700✔
2827
        if stmt.where != nil {
1,096✔
2828
                err = stmt.where.selectorRanges(table, tableRef.Alias(), params, rangesByColID)
396✔
2829
                if err != nil {
398✔
2830
                        return nil, err
2✔
2831
                }
2✔
2832
        }
2833

2834
        preferredIndex, err := stmt.getPreferredIndex(table)
698✔
2835
        if err != nil {
698✔
2836
                return nil, err
×
2837
        }
×
2838

2839
        var sortingIndex *Index
698✔
2840
        if preferredIndex == nil {
1,366✔
2841
                sortingIndex = stmt.selectSortingIndex(groupByCols, orderByCols, table, rangesByColID)
668✔
2842
        } else {
698✔
2843
                sortingIndex = preferredIndex
30✔
2844
        }
30✔
2845

2846
        if sortingIndex == nil {
1,276✔
2847
                sortingIndex = table.primaryIndex
578✔
2848
        }
578✔
2849

2850
        if tableRef.history && !sortingIndex.IsPrimary() {
698✔
2851
                return nil, fmt.Errorf("%w: historical queries are supported over primary index", ErrIllegalArguments)
×
2852
        }
×
2853

2854
        var descOrder bool
698✔
2855
        if len(groupByCols) > 0 && sortingIndex.coversOrdCols(groupByCols, rangesByColID) {
715✔
2856
                groupByCols = nil
17✔
2857
        }
17✔
2858

2859
        if len(groupByCols) == 0 && len(orderByCols) > 0 && sortingIndex.coversOrdCols(orderByCols, rangesByColID) {
797✔
2860
                descOrder = orderByCols[0].descOrder
99✔
2861
                orderByCols = nil
99✔
2862
        }
99✔
2863

2864
        groupByCols, orderByCols = stmt.rearrangeOrdColumns(groupByCols, orderByCols)
698✔
2865

698✔
2866
        return &ScanSpecs{
698✔
2867
                Index:              sortingIndex,
698✔
2868
                rangesByColID:      rangesByColID,
698✔
2869
                IncludeHistory:     tableRef.history,
698✔
2870
                IncludeTxMetadata:  stmt.hasTxMetadata(),
698✔
2871
                DescOrder:          descOrder,
698✔
2872
                groupBySortColumns: groupByCols,
698✔
2873
                orderBySortCols:    orderByCols,
698✔
2874
        }, nil
698✔
2875
}
2876

2877
func (stmt *SelectStmt) selectSortingIndex(groupByCols, orderByCols []*OrdCol, table *Table, rangesByColId map[uint32]*typedValueRange) *Index {
668✔
2878
        sortCols := groupByCols
668✔
2879
        if len(sortCols) == 0 {
1,310✔
2880
                sortCols = orderByCols
642✔
2881
        }
642✔
2882

2883
        if len(sortCols) == 0 {
1,218✔
2884
                return nil
550✔
2885
        }
550✔
2886

2887
        for _, idx := range table.indexes {
322✔
2888
                if idx.coversOrdCols(sortCols, rangesByColId) {
294✔
2889
                        return idx
90✔
2890
                }
90✔
2891
        }
2892
        return nil
28✔
2893
}
2894

2895
func (stmt *SelectStmt) getPreferredIndex(table *Table) (*Index, error) {
698✔
2896
        if len(stmt.indexOn) == 0 {
1,366✔
2897
                return nil, nil
668✔
2898
        }
668✔
2899

2900
        cols := make([]*Column, len(stmt.indexOn))
30✔
2901
        for i, colName := range stmt.indexOn {
80✔
2902
                col, err := table.GetColumnByName(colName)
50✔
2903
                if err != nil {
50✔
2904
                        return nil, err
×
2905
                }
×
2906

2907
                cols[i] = col
50✔
2908
        }
2909
        return table.GetIndexByName(indexName(table.name, cols))
30✔
2910
}
2911

2912
type UnionStmt struct {
2913
        distinct    bool
2914
        left, right DataSource
2915
}
2916

2917
func (stmt *UnionStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
2918
        err := stmt.left.inferParameters(ctx, tx, params)
1✔
2919
        if err != nil {
1✔
2920
                return err
×
2921
        }
×
2922
        return stmt.right.inferParameters(ctx, tx, params)
1✔
2923
}
2924

2925
func (stmt *UnionStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
9✔
2926
        _, err := stmt.left.execAt(ctx, tx, params)
9✔
2927
        if err != nil {
9✔
2928
                return tx, err
×
2929
        }
×
2930

2931
        return stmt.right.execAt(ctx, tx, params)
9✔
2932
}
2933

2934
func (stmt *UnionStmt) resolveUnionAll(ctx context.Context, tx *SQLTx, params map[string]interface{}) (ret RowReader, err error) {
11✔
2935
        leftRowReader, err := stmt.left.Resolve(ctx, tx, params, nil)
11✔
2936
        if err != nil {
12✔
2937
                return nil, err
1✔
2938
        }
1✔
2939
        defer func() {
20✔
2940
                if err != nil {
14✔
2941
                        leftRowReader.Close()
4✔
2942
                }
4✔
2943
        }()
2944

2945
        rightRowReader, err := stmt.right.Resolve(ctx, tx, params, nil)
10✔
2946
        if err != nil {
11✔
2947
                return nil, err
1✔
2948
        }
1✔
2949
        defer func() {
18✔
2950
                if err != nil {
12✔
2951
                        rightRowReader.Close()
3✔
2952
                }
3✔
2953
        }()
2954

2955
        rowReader, err := newUnionRowReader(ctx, []RowReader{leftRowReader, rightRowReader})
9✔
2956
        if err != nil {
12✔
2957
                return nil, err
3✔
2958
        }
3✔
2959

2960
        return rowReader, nil
6✔
2961
}
2962

2963
func (stmt *UnionStmt) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (ret RowReader, err error) {
11✔
2964
        rowReader, err := stmt.resolveUnionAll(ctx, tx, params)
11✔
2965
        if err != nil {
16✔
2966
                return nil, err
5✔
2967
        }
5✔
2968
        defer func() {
12✔
2969
                if err != nil {
7✔
2970
                        rowReader.Close()
1✔
2971
                }
1✔
2972
        }()
2973

2974
        if stmt.distinct {
11✔
2975
                distinctReader, err := newDistinctRowReader(ctx, rowReader)
5✔
2976
                if err != nil {
6✔
2977
                        return nil, err
1✔
2978
                }
1✔
2979
                rowReader = distinctReader
4✔
2980
        }
2981

2982
        return rowReader, nil
5✔
2983
}
2984

2985
func (stmt *UnionStmt) Alias() string {
×
2986
        return ""
×
2987
}
×
2988

2989
func NewTableRef(table string, as string) *tableRef {
179✔
2990
        return &tableRef{
179✔
2991
                table: table,
179✔
2992
                as:    as,
179✔
2993
        }
179✔
2994
}
179✔
2995

2996
type tableRef struct {
2997
        table   string
2998
        history bool
2999
        period  period
3000
        as      string
3001
}
3002

3003
type period struct {
3004
        start *openPeriod
3005
        end   *openPeriod
3006
}
3007

3008
type openPeriod struct {
3009
        inclusive bool
3010
        instant   periodInstant
3011
}
3012

3013
type periodInstant struct {
3014
        exp         ValueExp
3015
        instantType instantType
3016
}
3017

3018
type instantType = int
3019

3020
const (
3021
        txInstant instantType = iota
3022
        timeInstant
3023
)
3024

3025
func (i periodInstant) resolve(tx *SQLTx, params map[string]interface{}, asc, inclusive bool) (uint64, error) {
81✔
3026
        exp, err := i.exp.substitute(params)
81✔
3027
        if err != nil {
81✔
3028
                return 0, err
×
3029
        }
×
3030

3031
        instantVal, err := exp.reduce(tx, nil, "")
81✔
3032
        if err != nil {
83✔
3033
                return 0, err
2✔
3034
        }
2✔
3035

3036
        if i.instantType == txInstant {
124✔
3037
                txID, ok := instantVal.RawValue().(int64)
45✔
3038
                if !ok {
45✔
3039
                        return 0, fmt.Errorf("%w: invalid tx range, tx ID must be a positive integer, %s given", ErrIllegalArguments, instantVal.Type())
×
3040
                }
×
3041

3042
                if txID <= 0 {
52✔
3043
                        return 0, fmt.Errorf("%w: invalid tx range, tx ID must be a positive integer, %d given", ErrIllegalArguments, txID)
7✔
3044
                }
7✔
3045

3046
                if inclusive {
61✔
3047
                        return uint64(txID), nil
23✔
3048
                }
23✔
3049

3050
                if asc {
26✔
3051
                        return uint64(txID + 1), nil
11✔
3052
                }
11✔
3053

3054
                if txID <= 1 {
5✔
3055
                        return 0, fmt.Errorf("%w: invalid tx range, tx ID must be greater than 1, %d given", ErrIllegalArguments, txID)
1✔
3056
                }
1✔
3057

3058
                return uint64(txID - 1), nil
3✔
3059
        } else {
34✔
3060

34✔
3061
                var ts time.Time
34✔
3062

34✔
3063
                if instantVal.Type() == TimestampType {
67✔
3064
                        ts = instantVal.RawValue().(time.Time)
33✔
3065
                } else {
34✔
3066
                        conv, err := getConverter(instantVal.Type(), TimestampType)
1✔
3067
                        if err != nil {
1✔
3068
                                return 0, err
×
3069
                        }
×
3070

3071
                        tval, err := conv(instantVal)
1✔
3072
                        if err != nil {
1✔
3073
                                return 0, err
×
3074
                        }
×
3075

3076
                        ts = tval.RawValue().(time.Time)
1✔
3077
                }
3078

3079
                sts := ts
34✔
3080

34✔
3081
                if asc {
57✔
3082
                        if !inclusive {
34✔
3083
                                sts = sts.Add(1 * time.Second)
11✔
3084
                        }
11✔
3085

3086
                        txHdr, err := tx.engine.store.FirstTxSince(sts)
23✔
3087
                        if err != nil {
34✔
3088
                                return 0, err
11✔
3089
                        }
11✔
3090

3091
                        return txHdr.ID, nil
12✔
3092
                }
3093

3094
                if !inclusive {
11✔
3095
                        sts = sts.Add(-1 * time.Second)
×
3096
                }
×
3097

3098
                txHdr, err := tx.engine.store.LastTxUntil(sts)
11✔
3099
                if err != nil {
11✔
3100
                        return 0, err
×
3101
                }
×
3102

3103
                return txHdr.ID, nil
11✔
3104
        }
3105
}
3106

3107
func (stmt *tableRef) referencedTable(tx *SQLTx) (*Table, error) {
3,340✔
3108
        table, err := tx.catalog.GetTableByName(stmt.table)
3,340✔
3109
        if err != nil {
3,356✔
3110
                return nil, err
16✔
3111
        }
16✔
3112

3113
        return table, nil
3,324✔
3114
}
3115

3116
func (stmt *tableRef) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
3117
        return nil
1✔
3118
}
1✔
3119

3120
func (stmt *tableRef) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
×
3121
        return tx, nil
×
3122
}
×
3123

3124
func (stmt *tableRef) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, scanSpecs *ScanSpecs) (RowReader, error) {
714✔
3125
        if tx == nil {
714✔
3126
                return nil, ErrIllegalArguments
×
3127
        }
×
3128

3129
        table, err := stmt.referencedTable(tx)
714✔
3130
        if err != nil {
714✔
3131
                return nil, err
×
3132
        }
×
3133

3134
        return newRawRowReader(tx, params, table, stmt.period, stmt.as, scanSpecs)
714✔
3135
}
3136

3137
func (stmt *tableRef) Alias() string {
560✔
3138
        if stmt.as == "" {
1,074✔
3139
                return stmt.table
514✔
3140
        }
514✔
3141
        return stmt.as
46✔
3142
}
3143

3144
type JoinSpec struct {
3145
        joinType JoinType
3146
        ds       DataSource
3147
        cond     ValueExp
3148
        indexOn  []string
3149
}
3150

3151
type OrdCol struct {
3152
        sel       Selector
3153
        descOrder bool
3154
}
3155

3156
func NewOrdCol(table string, col string, descOrder bool) *OrdCol {
1✔
3157
        return &OrdCol{
1✔
3158
                sel:       NewColSelector(table, col),
1✔
3159
                descOrder: descOrder,
1✔
3160
        }
1✔
3161
}
1✔
3162

3163
type Selector interface {
3164
        ValueExp
3165
        resolve(implicitTable string) (aggFn, table, col string)
3166
        alias() string
3167
        setAlias(alias string)
3168
}
3169

3170
type ColSelector struct {
3171
        table string
3172
        col   string
3173
        as    string
3174
}
3175

3176
func NewColSelector(table, col string) *ColSelector {
125✔
3177
        return &ColSelector{
125✔
3178
                table: table,
125✔
3179
                col:   col,
125✔
3180
        }
125✔
3181
}
125✔
3182

3183
func (sel *ColSelector) resolve(implicitTable string) (aggFn, table, col string) {
385,959✔
3184
        table = implicitTable
385,959✔
3185
        if sel.table != "" {
496,658✔
3186
                table = sel.table
110,699✔
3187
        }
110,699✔
3188
        return "", table, sel.col
385,959✔
3189
}
3190

3191
func (sel *ColSelector) alias() string {
125,560✔
3192
        if sel.as == "" {
251,028✔
3193
                return sel.col
125,468✔
3194
        }
125,468✔
3195

3196
        return sel.as
92✔
3197
}
3198

3199
func (sel *ColSelector) setAlias(alias string) {
698✔
3200
        sel.as = alias
698✔
3201
}
698✔
3202

3203
func (sel *ColSelector) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
501✔
3204
        _, table, col := sel.resolve(implicitTable)
501✔
3205
        encSel := EncodeSelector("", table, col)
501✔
3206

501✔
3207
        desc, ok := cols[encSel]
501✔
3208
        if !ok {
504✔
3209
                return AnyType, fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, col)
3✔
3210
        }
3✔
3211

3212
        return desc.Type, nil
498✔
3213
}
3214

3215
func (sel *ColSelector) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
15✔
3216
        _, table, col := sel.resolve(implicitTable)
15✔
3217
        encSel := EncodeSelector("", table, col)
15✔
3218

15✔
3219
        desc, ok := cols[encSel]
15✔
3220
        if !ok {
17✔
3221
                return fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, col)
2✔
3222
        }
2✔
3223

3224
        if desc.Type != t {
16✔
3225
                return fmt.Errorf("%w: %v(%s) can not be interpreted as type %v", ErrInvalidTypes, desc.Type, encSel, t)
3✔
3226
        }
3✔
3227

3228
        return nil
10✔
3229
}
3230

3231
func (sel *ColSelector) substitute(params map[string]interface{}) (ValueExp, error) {
3,003✔
3232
        return sel, nil
3,003✔
3233
}
3,003✔
3234

3235
func (sel *ColSelector) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
319,082✔
3236
        if row == nil {
319,083✔
3237
                return nil, fmt.Errorf("%w: no row to evaluate in current context", ErrInvalidValue)
1✔
3238
        }
1✔
3239

3240
        aggFn, table, col := sel.resolve(implicitTable)
319,081✔
3241

319,081✔
3242
        v, ok := row.ValuesBySelector[EncodeSelector(aggFn, table, col)]
319,081✔
3243
        if !ok {
319,087✔
3244
                return nil, fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, col)
6✔
3245
        }
6✔
3246

3247
        return v, nil
319,075✔
3248
}
3249

3250
func (sel *ColSelector) reduceSelectors(row *Row, implicitTable string) ValueExp {
339✔
3251
        aggFn, table, col := sel.resolve(implicitTable)
339✔
3252

339✔
3253
        v, ok := row.ValuesBySelector[EncodeSelector(aggFn, table, col)]
339✔
3254
        if !ok {
503✔
3255
                return sel
164✔
3256
        }
164✔
3257

3258
        return v
175✔
3259
}
3260

3261
func (sel *ColSelector) isConstant() bool {
12✔
3262
        return false
12✔
3263
}
12✔
3264

3265
func (sel *ColSelector) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
11✔
3266
        return nil
11✔
3267
}
11✔
3268

3269
type AggColSelector struct {
3270
        aggFn AggregateFn
3271
        table string
3272
        col   string
3273
        as    string
3274
}
3275

3276
func NewAggColSelector(aggFn AggregateFn, table, col string) *AggColSelector {
16✔
3277
        return &AggColSelector{
16✔
3278
                aggFn: aggFn,
16✔
3279
                table: table,
16✔
3280
                col:   col,
16✔
3281
        }
16✔
3282
}
16✔
3283

3284
func EncodeSelector(aggFn, table, col string) string {
594,620✔
3285
        return aggFn + "(" + table + "." + col + ")"
594,620✔
3286
}
594,620✔
3287

3288
func (sel *AggColSelector) resolve(implicitTable string) (aggFn, table, col string) {
1,581✔
3289
        table = implicitTable
1,581✔
3290
        if sel.table != "" {
1,712✔
3291
                table = sel.table
131✔
3292
        }
131✔
3293

3294
        return sel.aggFn, table, sel.col
1,581✔
3295
}
3296

3297
func (sel *AggColSelector) alias() string {
435✔
3298
        return sel.as
435✔
3299
}
435✔
3300

3301
func (sel *AggColSelector) setAlias(alias string) {
106✔
3302
        sel.as = alias
106✔
3303
}
106✔
3304

3305
func (sel *AggColSelector) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
33✔
3306
        if sel.aggFn == COUNT {
50✔
3307
                return IntegerType, nil
17✔
3308
        }
17✔
3309

3310
        colSelector := &ColSelector{table: sel.table, col: sel.col}
16✔
3311

16✔
3312
        if sel.aggFn == SUM || sel.aggFn == AVG {
23✔
3313
                t, err := colSelector.inferType(cols, params, implicitTable)
7✔
3314
                if err != nil {
7✔
3315
                        return AnyType, err
×
3316
                }
×
3317

3318
                if t != IntegerType && t != Float64Type {
7✔
3319
                        return AnyType, fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, t)
×
3320

×
3321
                }
×
3322

3323
                return t, nil
7✔
3324
        }
3325

3326
        return colSelector.inferType(cols, params, implicitTable)
9✔
3327
}
3328

3329
func (sel *AggColSelector) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
8✔
3330
        if sel.aggFn == COUNT {
10✔
3331
                if t != IntegerType {
3✔
3332
                        return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
1✔
3333
                }
1✔
3334
                return nil
1✔
3335
        }
3336

3337
        colSelector := &ColSelector{table: sel.table, col: sel.col}
6✔
3338

6✔
3339
        if sel.aggFn == SUM || sel.aggFn == AVG {
10✔
3340
                if t != IntegerType && t != Float64Type {
5✔
3341
                        return fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, t)
1✔
3342
                }
1✔
3343
        }
3344

3345
        return colSelector.requiresType(t, cols, params, implicitTable)
5✔
3346
}
3347

3348
func (sel *AggColSelector) substitute(params map[string]interface{}) (ValueExp, error) {
25✔
3349
        return sel, nil
25✔
3350
}
25✔
3351

3352
func (sel *AggColSelector) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
459✔
3353
        if row == nil {
460✔
3354
                return nil, fmt.Errorf("%w: no row to evaluate aggregation (%s) in current context", ErrInvalidValue, sel.aggFn)
1✔
3355
        }
1✔
3356

3357
        v, ok := row.ValuesBySelector[EncodeSelector(sel.resolve(implicitTable))]
458✔
3358
        if !ok {
459✔
3359
                return nil, fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, sel.col)
1✔
3360
        }
1✔
3361
        return v, nil
457✔
3362
}
3363

3364
func (sel *AggColSelector) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
3365
        return sel
×
3366
}
×
3367

3368
func (sel *AggColSelector) isConstant() bool {
1✔
3369
        return false
1✔
3370
}
1✔
3371

3372
func (sel *AggColSelector) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
×
3373
        return nil
×
3374
}
×
3375

3376
type NumExp struct {
3377
        op          NumOperator
3378
        left, right ValueExp
3379
}
3380

3381
func (bexp *NumExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
3382
        // First step - check if we can infer the type of sub-expressions
6✔
3383
        tleft, err := bexp.left.inferType(cols, params, implicitTable)
6✔
3384
        if err != nil {
6✔
3385
                return AnyType, err
×
3386
        }
×
3387
        if tleft != AnyType && tleft != IntegerType && tleft != Float64Type {
6✔
3388
                return AnyType, fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, tleft)
×
3389
        }
×
3390

3391
        tright, err := bexp.right.inferType(cols, params, implicitTable)
6✔
3392
        if err != nil {
6✔
3393
                return AnyType, err
×
3394
        }
×
3395
        if tright != AnyType && tright != IntegerType && tright != Float64Type {
8✔
3396
                return AnyType, fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, tright)
2✔
3397
        }
2✔
3398

3399
        if tleft == IntegerType && tright == IntegerType {
6✔
3400
                // Both sides are integer types - the result is also integer
2✔
3401
                return IntegerType, nil
2✔
3402
        }
2✔
3403

3404
        if tleft != AnyType && tright != AnyType {
2✔
3405
                // Both sides have concrete types but at least one of them is float
×
3406
                return Float64Type, nil
×
3407
        }
×
3408

3409
        // Both sides are ambiguous
3410
        return AnyType, nil
2✔
3411
}
3412

3413
func copyParams(params map[string]SQLValueType) map[string]SQLValueType {
11✔
3414
        ret := make(map[string]SQLValueType, len(params))
11✔
3415
        for k, v := range params {
15✔
3416
                ret[k] = v
4✔
3417
        }
4✔
3418
        return ret
11✔
3419
}
3420

3421
func restoreParams(params, restore map[string]SQLValueType) {
2✔
3422
        for k := range params {
2✔
3423
                delete(params, k)
×
3424
        }
×
3425
        for k, v := range restore {
2✔
3426
                params[k] = v
×
3427
        }
×
3428
}
3429

3430
func (bexp *NumExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
7✔
3431
        if t != IntegerType && t != Float64Type {
8✔
3432
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
1✔
3433
        }
1✔
3434

3435
        floatArgs := 2
6✔
3436
        paramsOrig := copyParams(params)
6✔
3437
        err := bexp.left.requiresType(t, cols, params, implicitTable)
6✔
3438
        if err != nil && t == Float64Type {
7✔
3439
                restoreParams(params, paramsOrig)
1✔
3440
                floatArgs--
1✔
3441
                err = bexp.left.requiresType(IntegerType, cols, params, implicitTable)
1✔
3442
        }
1✔
3443
        if err != nil {
7✔
3444
                return err
1✔
3445
        }
1✔
3446

3447
        paramsOrig = copyParams(params)
5✔
3448
        err = bexp.right.requiresType(t, cols, params, implicitTable)
5✔
3449
        if err != nil && t == Float64Type {
6✔
3450
                restoreParams(params, paramsOrig)
1✔
3451
                floatArgs--
1✔
3452
                err = bexp.right.requiresType(IntegerType, cols, params, implicitTable)
1✔
3453
        }
1✔
3454
        if err != nil {
7✔
3455
                return err
2✔
3456
        }
2✔
3457

3458
        if t == Float64Type && floatArgs == 0 {
3✔
3459
                // Currently this case requires explicit float cast
×
3460
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
×
3461
        }
×
3462

3463
        return nil
3✔
3464
}
3465

3466
func (bexp *NumExp) substitute(params map[string]interface{}) (ValueExp, error) {
142✔
3467
        rlexp, err := bexp.left.substitute(params)
142✔
3468
        if err != nil {
142✔
3469
                return nil, err
×
3470
        }
×
3471

3472
        rrexp, err := bexp.right.substitute(params)
142✔
3473
        if err != nil {
142✔
3474
                return nil, err
×
3475
        }
×
3476

3477
        bexp.left = rlexp
142✔
3478
        bexp.right = rrexp
142✔
3479

142✔
3480
        return bexp, nil
142✔
3481
}
3482

3483
func (bexp *NumExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
132✔
3484
        vl, err := bexp.left.reduce(tx, row, implicitTable)
132✔
3485
        if err != nil {
132✔
3486
                return nil, err
×
3487
        }
×
3488

3489
        vr, err := bexp.right.reduce(tx, row, implicitTable)
132✔
3490
        if err != nil {
132✔
3491
                return nil, err
×
3492
        }
×
3493

3494
        vl = unwrapJSON(vl)
132✔
3495
        vr = unwrapJSON(vr)
132✔
3496

132✔
3497
        return applyNumOperator(bexp.op, vl, vr)
132✔
3498
}
3499

3500
func unwrapJSON(v TypedValue) TypedValue {
264✔
3501
        if jsonVal, ok := v.(*JSON); ok {
364✔
3502
                if sv, isSimple := jsonVal.castToTypedValue(); isSimple {
200✔
3503
                        return sv
100✔
3504
                }
100✔
3505
        }
3506
        return v
164✔
3507
}
3508

3509
func (bexp *NumExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
3510
        return &NumExp{
1✔
3511
                op:    bexp.op,
1✔
3512
                left:  bexp.left.reduceSelectors(row, implicitTable),
1✔
3513
                right: bexp.right.reduceSelectors(row, implicitTable),
1✔
3514
        }
1✔
3515
}
1✔
3516

3517
func (bexp *NumExp) isConstant() bool {
5✔
3518
        return bexp.left.isConstant() && bexp.right.isConstant()
5✔
3519
}
5✔
3520

3521
func (bexp *NumExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
3✔
3522
        return nil
3✔
3523
}
3✔
3524

3525
type NotBoolExp struct {
3526
        exp ValueExp
3527
}
3528

3529
func (bexp *NotBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
2✔
3530
        err := bexp.exp.requiresType(BooleanType, cols, params, implicitTable)
2✔
3531
        if err != nil {
2✔
3532
                return AnyType, err
×
3533
        }
×
3534

3535
        return BooleanType, nil
2✔
3536
}
3537

3538
func (bexp *NotBoolExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
6✔
3539
        if t != BooleanType {
7✔
3540
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
1✔
3541
        }
1✔
3542

3543
        return bexp.exp.requiresType(BooleanType, cols, params, implicitTable)
5✔
3544
}
3545

3546
func (bexp *NotBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
22✔
3547
        rexp, err := bexp.exp.substitute(params)
22✔
3548
        if err != nil {
22✔
3549
                return nil, err
×
3550
        }
×
3551

3552
        bexp.exp = rexp
22✔
3553

22✔
3554
        return bexp, nil
22✔
3555
}
3556

3557
func (bexp *NotBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
22✔
3558
        v, err := bexp.exp.reduce(tx, row, implicitTable)
22✔
3559
        if err != nil {
22✔
3560
                return nil, err
×
3561
        }
×
3562

3563
        r, isBool := v.RawValue().(bool)
22✔
3564
        if !isBool {
22✔
3565
                return nil, ErrInvalidCondition
×
3566
        }
×
3567

3568
        return &Bool{val: !r}, nil
22✔
3569
}
3570

3571
func (bexp *NotBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
3572
        return &NotBoolExp{
×
3573
                exp: bexp.exp.reduceSelectors(row, implicitTable),
×
3574
        }
×
3575
}
×
3576

3577
func (bexp *NotBoolExp) isConstant() bool {
1✔
3578
        return bexp.exp.isConstant()
1✔
3579
}
1✔
3580

3581
func (bexp *NotBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
7✔
3582
        return nil
7✔
3583
}
7✔
3584

3585
type LikeBoolExp struct {
3586
        val     ValueExp
3587
        notLike bool
3588
        pattern ValueExp
3589
}
3590

3591
func NewLikeBoolExp(val ValueExp, notLike bool, pattern ValueExp) *LikeBoolExp {
3✔
3592
        return &LikeBoolExp{
3✔
3593
                val:     val,
3✔
3594
                notLike: notLike,
3✔
3595
                pattern: pattern,
3✔
3596
        }
3✔
3597
}
3✔
3598

3599
func (bexp *LikeBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
3✔
3600
        if bexp.val == nil || bexp.pattern == nil {
4✔
3601
                return AnyType, fmt.Errorf("error in 'LIKE' clause: %w", ErrInvalidCondition)
1✔
3602
        }
1✔
3603

3604
        err := bexp.pattern.requiresType(VarcharType, cols, params, implicitTable)
2✔
3605
        if err != nil {
3✔
3606
                return AnyType, fmt.Errorf("error in 'LIKE' clause: %w", err)
1✔
3607
        }
1✔
3608

3609
        return BooleanType, nil
1✔
3610
}
3611

3612
func (bexp *LikeBoolExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
7✔
3613
        if bexp.val == nil || bexp.pattern == nil {
9✔
3614
                return fmt.Errorf("error in 'LIKE' clause: %w", ErrInvalidCondition)
2✔
3615
        }
2✔
3616

3617
        if t != BooleanType {
7✔
3618
                return fmt.Errorf("error using the value of the LIKE operator as %s: %w", t, ErrInvalidTypes)
2✔
3619
        }
2✔
3620

3621
        err := bexp.pattern.requiresType(VarcharType, cols, params, implicitTable)
3✔
3622
        if err != nil {
4✔
3623
                return fmt.Errorf("error in 'LIKE' clause: %w", err)
1✔
3624
        }
1✔
3625

3626
        return nil
2✔
3627
}
3628

3629
func (bexp *LikeBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
135✔
3630
        if bexp.val == nil || bexp.pattern == nil {
136✔
3631
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", ErrInvalidCondition)
1✔
3632
        }
1✔
3633

3634
        val, err := bexp.val.substitute(params)
134✔
3635
        if err != nil {
134✔
3636
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3637
        }
×
3638

3639
        pattern, err := bexp.pattern.substitute(params)
134✔
3640
        if err != nil {
134✔
3641
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3642
        }
×
3643

3644
        return &LikeBoolExp{
134✔
3645
                val:     val,
134✔
3646
                notLike: bexp.notLike,
134✔
3647
                pattern: pattern,
134✔
3648
        }, nil
134✔
3649
}
3650

3651
func (bexp *LikeBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
132✔
3652
        if bexp.val == nil || bexp.pattern == nil {
133✔
3653
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", ErrInvalidCondition)
1✔
3654
        }
1✔
3655

3656
        rval, err := bexp.val.reduce(tx, row, implicitTable)
131✔
3657
        if err != nil {
131✔
3658
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3659
        }
×
3660

3661
        if rval.IsNull() {
132✔
3662
                return &Bool{val: false}, nil
1✔
3663
        }
1✔
3664

3665
        rvalStr, ok := rval.RawValue().(string)
130✔
3666
        if !ok {
131✔
3667
                return nil, fmt.Errorf("error in 'LIKE' clause: %w (expecting %s)", ErrInvalidTypes, VarcharType)
1✔
3668
        }
1✔
3669

3670
        rpattern, err := bexp.pattern.reduce(tx, row, implicitTable)
129✔
3671
        if err != nil {
129✔
3672
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3673
        }
×
3674

3675
        if rpattern.Type() != VarcharType {
129✔
3676
                return nil, fmt.Errorf("error evaluating 'LIKE' clause: %w", ErrInvalidTypes)
×
3677
        }
×
3678

3679
        matched, err := regexp.MatchString(rpattern.RawValue().(string), rvalStr)
129✔
3680
        if err != nil {
129✔
3681
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3682
        }
×
3683

3684
        return &Bool{val: matched != bexp.notLike}, nil
129✔
3685
}
3686

3687
func (bexp *LikeBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
3688
        return bexp
1✔
3689
}
1✔
3690

3691
func (bexp *LikeBoolExp) isConstant() bool {
2✔
3692
        return false
2✔
3693
}
2✔
3694

3695
func (bexp *LikeBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
8✔
3696
        return nil
8✔
3697
}
8✔
3698

3699
type CmpBoolExp struct {
3700
        op          CmpOperator
3701
        left, right ValueExp
3702
}
3703

3704
func NewCmpBoolExp(op CmpOperator, left, right ValueExp) *CmpBoolExp {
66✔
3705
        return &CmpBoolExp{
66✔
3706
                op:    op,
66✔
3707
                left:  left,
66✔
3708
                right: right,
66✔
3709
        }
66✔
3710
}
66✔
3711

3712
func (bexp *CmpBoolExp) Left() ValueExp {
×
3713
        return bexp.left
×
3714
}
×
3715

3716
func (bexp *CmpBoolExp) Right() ValueExp {
×
3717
        return bexp.right
×
3718
}
×
3719

3720
func (bexp *CmpBoolExp) OP() CmpOperator {
×
3721
        return bexp.op
×
3722
}
×
3723

3724
func (bexp *CmpBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
59✔
3725
        tleft, err := bexp.left.inferType(cols, params, implicitTable)
59✔
3726
        if err != nil {
59✔
3727
                return AnyType, err
×
3728
        }
×
3729

3730
        tright, err := bexp.right.inferType(cols, params, implicitTable)
59✔
3731
        if err != nil {
62✔
3732
                return AnyType, err
3✔
3733
        }
3✔
3734

3735
        // unification step
3736

3737
        if tleft == tright {
65✔
3738
                return BooleanType, nil
9✔
3739
        }
9✔
3740

3741
        if tleft != AnyType && tright != AnyType {
51✔
3742
                return AnyType, fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, tleft, tright)
4✔
3743
        }
4✔
3744

3745
        if tleft == AnyType {
47✔
3746
                err = bexp.left.requiresType(tright, cols, params, implicitTable)
4✔
3747
                if err != nil {
4✔
3748
                        return AnyType, err
×
3749
                }
×
3750
        }
3751

3752
        if tright == AnyType {
82✔
3753
                err = bexp.right.requiresType(tleft, cols, params, implicitTable)
39✔
3754
                if err != nil {
39✔
3755
                        return AnyType, err
×
3756
                }
×
3757
        }
3758

3759
        return BooleanType, nil
43✔
3760
}
3761

3762
func (bexp *CmpBoolExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
41✔
3763
        if t != BooleanType {
42✔
3764
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
1✔
3765
        }
1✔
3766

3767
        _, err := bexp.inferType(cols, params, implicitTable)
40✔
3768

40✔
3769
        return err
40✔
3770
}
3771

3772
func (bexp *CmpBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
3,250✔
3773
        rlexp, err := bexp.left.substitute(params)
3,250✔
3774
        if err != nil {
3,250✔
3775
                return nil, err
×
3776
        }
×
3777

3778
        rrexp, err := bexp.right.substitute(params)
3,250✔
3779
        if err != nil {
3,251✔
3780
                return nil, err
1✔
3781
        }
1✔
3782

3783
        bexp.left = rlexp
3,249✔
3784
        bexp.right = rrexp
3,249✔
3785

3,249✔
3786
        return bexp, nil
3,249✔
3787
}
3788

3789
func (bexp *CmpBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
3,069✔
3790
        vl, err := bexp.left.reduce(tx, row, implicitTable)
3,069✔
3791
        if err != nil {
3,070✔
3792
                return nil, err
1✔
3793
        }
1✔
3794

3795
        vr, err := bexp.right.reduce(tx, row, implicitTable)
3,068✔
3796
        if err != nil {
3,070✔
3797
                return nil, err
2✔
3798
        }
2✔
3799

3800
        r, err := vl.Compare(vr)
3,066✔
3801
        if err != nil {
3,070✔
3802
                return nil, err
4✔
3803
        }
4✔
3804

3805
        return &Bool{val: cmpSatisfiesOp(r, bexp.op)}, nil
3,062✔
3806
}
3807

3808
func (bexp *CmpBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
167✔
3809
        return &CmpBoolExp{
167✔
3810
                op:    bexp.op,
167✔
3811
                left:  bexp.left.reduceSelectors(row, implicitTable),
167✔
3812
                right: bexp.right.reduceSelectors(row, implicitTable),
167✔
3813
        }
167✔
3814
}
167✔
3815

3816
func (bexp *CmpBoolExp) isConstant() bool {
2✔
3817
        return bexp.left.isConstant() && bexp.right.isConstant()
2✔
3818
}
2✔
3819

3820
func (bexp *CmpBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
486✔
3821
        matchingFunc := func(left, right ValueExp) (*ColSelector, ValueExp, bool) {
1,068✔
3822
                s, isSel := bexp.left.(*ColSelector)
582✔
3823
                if isSel && s.col != revCol && bexp.right.isConstant() {
972✔
3824
                        return s, right, true
390✔
3825
                }
390✔
3826
                return nil, nil, false
192✔
3827
        }
3828

3829
        sel, c, ok := matchingFunc(bexp.left, bexp.right)
486✔
3830
        if !ok {
582✔
3831
                sel, c, ok = matchingFunc(bexp.right, bexp.left)
96✔
3832
        }
96✔
3833

3834
        if !ok {
582✔
3835
                return nil
96✔
3836
        }
96✔
3837

3838
        aggFn, t, col := sel.resolve(table.name)
390✔
3839
        if aggFn != "" || t != asTable {
404✔
3840
                return nil
14✔
3841
        }
14✔
3842

3843
        column, err := table.GetColumnByName(col)
376✔
3844
        if err != nil {
377✔
3845
                return err
1✔
3846
        }
1✔
3847

3848
        val, err := c.substitute(params)
375✔
3849
        if errors.Is(err, ErrMissingParameter) {
434✔
3850
                // TODO: not supported when parameters are not provided during query resolution
59✔
3851
                return nil
59✔
3852
        }
59✔
3853
        if err != nil {
316✔
3854
                return err
×
3855
        }
×
3856

3857
        rval, err := val.reduce(nil, nil, table.name)
316✔
3858
        if err != nil {
317✔
3859
                return err
1✔
3860
        }
1✔
3861

3862
        return updateRangeFor(column.id, rval, bexp.op, rangesByColID)
315✔
3863
}
3864

3865
func updateRangeFor(colID uint32, val TypedValue, cmp CmpOperator, rangesByColID map[uint32]*typedValueRange) error {
315✔
3866
        currRange, ranged := rangesByColID[colID]
315✔
3867
        var newRange *typedValueRange
315✔
3868

315✔
3869
        switch cmp {
315✔
3870
        case EQ:
247✔
3871
                {
494✔
3872
                        newRange = &typedValueRange{
247✔
3873
                                lRange: &typedValueSemiRange{
247✔
3874
                                        val:       val,
247✔
3875
                                        inclusive: true,
247✔
3876
                                },
247✔
3877
                                hRange: &typedValueSemiRange{
247✔
3878
                                        val:       val,
247✔
3879
                                        inclusive: true,
247✔
3880
                                },
247✔
3881
                        }
247✔
3882
                }
247✔
3883
        case LT:
13✔
3884
                {
26✔
3885
                        newRange = &typedValueRange{
13✔
3886
                                hRange: &typedValueSemiRange{
13✔
3887
                                        val: val,
13✔
3888
                                },
13✔
3889
                        }
13✔
3890
                }
13✔
3891
        case LE:
10✔
3892
                {
20✔
3893
                        newRange = &typedValueRange{
10✔
3894
                                hRange: &typedValueSemiRange{
10✔
3895
                                        val:       val,
10✔
3896
                                        inclusive: true,
10✔
3897
                                },
10✔
3898
                        }
10✔
3899
                }
10✔
3900
        case GT:
18✔
3901
                {
36✔
3902
                        newRange = &typedValueRange{
18✔
3903
                                lRange: &typedValueSemiRange{
18✔
3904
                                        val: val,
18✔
3905
                                },
18✔
3906
                        }
18✔
3907
                }
18✔
3908
        case GE:
16✔
3909
                {
32✔
3910
                        newRange = &typedValueRange{
16✔
3911
                                lRange: &typedValueSemiRange{
16✔
3912
                                        val:       val,
16✔
3913
                                        inclusive: true,
16✔
3914
                                },
16✔
3915
                        }
16✔
3916
                }
16✔
3917
        case NE:
11✔
3918
                {
22✔
3919
                        return nil
11✔
3920
                }
11✔
3921
        }
3922

3923
        if !ranged {
605✔
3924
                rangesByColID[colID] = newRange
301✔
3925
                return nil
301✔
3926
        }
301✔
3927

3928
        return currRange.refineWith(newRange)
3✔
3929
}
3930

3931
func cmpSatisfiesOp(cmp int, op CmpOperator) bool {
3,062✔
3932
        switch {
3,062✔
3933
        case cmp == 0:
523✔
3934
                {
1,046✔
3935
                        return op == EQ || op == LE || op == GE
523✔
3936
                }
523✔
3937
        case cmp < 0:
1,404✔
3938
                {
2,808✔
3939
                        return op == NE || op == LT || op == LE
1,404✔
3940
                }
1,404✔
3941
        case cmp > 0:
1,135✔
3942
                {
2,270✔
3943
                        return op == NE || op == GT || op == GE
1,135✔
3944
                }
1,135✔
3945
        }
3946
        return false
×
3947
}
3948

3949
type BinBoolExp struct {
3950
        op          LogicOperator
3951
        left, right ValueExp
3952
}
3953

3954
func NewBinBoolExp(op LogicOperator, lrexp, rrexp ValueExp) *BinBoolExp {
18✔
3955
        bexp := &BinBoolExp{
18✔
3956
                op: op,
18✔
3957
        }
18✔
3958

18✔
3959
        bexp.left = lrexp
18✔
3960
        bexp.right = rrexp
18✔
3961

18✔
3962
        return bexp
18✔
3963
}
18✔
3964

3965
func (bexp *BinBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
19✔
3966
        err := bexp.left.requiresType(BooleanType, cols, params, implicitTable)
19✔
3967
        if err != nil {
19✔
3968
                return AnyType, err
×
3969
        }
×
3970

3971
        err = bexp.right.requiresType(BooleanType, cols, params, implicitTable)
19✔
3972
        if err != nil {
21✔
3973
                return AnyType, err
2✔
3974
        }
2✔
3975

3976
        return BooleanType, nil
17✔
3977
}
3978

3979
func (bexp *BinBoolExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
22✔
3980
        if t != BooleanType {
25✔
3981
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
3✔
3982
        }
3✔
3983

3984
        err := bexp.left.requiresType(BooleanType, cols, params, implicitTable)
19✔
3985
        if err != nil {
20✔
3986
                return err
1✔
3987
        }
1✔
3988

3989
        err = bexp.right.requiresType(BooleanType, cols, params, implicitTable)
18✔
3990
        if err != nil {
18✔
3991
                return err
×
3992
        }
×
3993

3994
        return nil
18✔
3995
}
3996

3997
func (bexp *BinBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
470✔
3998
        rlexp, err := bexp.left.substitute(params)
470✔
3999
        if err != nil {
470✔
4000
                return nil, err
×
4001
        }
×
4002

4003
        rrexp, err := bexp.right.substitute(params)
470✔
4004
        if err != nil {
470✔
4005
                return nil, err
×
4006
        }
×
4007

4008
        bexp.left = rlexp
470✔
4009
        bexp.right = rrexp
470✔
4010

470✔
4011
        return bexp, nil
470✔
4012
}
4013

4014
func (bexp *BinBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
461✔
4015
        vl, err := bexp.left.reduce(tx, row, implicitTable)
461✔
4016
        if err != nil {
461✔
4017
                return nil, err
×
4018
        }
×
4019

4020
        bl, isBool := vl.(*Bool)
461✔
4021
        if !isBool {
461✔
4022
                return nil, fmt.Errorf("%w (expecting boolean value)", ErrInvalidValue)
×
4023
        }
×
4024

4025
        if (bexp.op == OR && bl.val) || (bexp.op == AND && !bl.val) {
636✔
4026
                return &Bool{val: bl.val}, nil
175✔
4027
        }
175✔
4028

4029
        vr, err := bexp.right.reduce(tx, row, implicitTable)
286✔
4030
        if err != nil {
287✔
4031
                return nil, err
1✔
4032
        }
1✔
4033

4034
        br, isBool := vr.(*Bool)
285✔
4035
        if !isBool {
285✔
4036
                return nil, fmt.Errorf("%w (expecting boolean value)", ErrInvalidValue)
×
4037
        }
×
4038

4039
        switch bexp.op {
285✔
4040
        case AND:
273✔
4041
                {
546✔
4042
                        return &Bool{val: bl.val && br.val}, nil
273✔
4043
                }
273✔
4044
        case OR:
12✔
4045
                {
24✔
4046
                        return &Bool{val: bl.val || br.val}, nil
12✔
4047
                }
12✔
4048
        }
4049

4050
        return nil, ErrUnexpected
×
4051
}
4052

4053
func (bexp *BinBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
15✔
4054
        return &BinBoolExp{
15✔
4055
                op:    bexp.op,
15✔
4056
                left:  bexp.left.reduceSelectors(row, implicitTable),
15✔
4057
                right: bexp.right.reduceSelectors(row, implicitTable),
15✔
4058
        }
15✔
4059
}
15✔
4060

4061
func (bexp *BinBoolExp) isConstant() bool {
1✔
4062
        return bexp.left.isConstant() && bexp.right.isConstant()
1✔
4063
}
1✔
4064

4065
func (bexp *BinBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
150✔
4066
        if bexp.op == AND {
287✔
4067
                err := bexp.left.selectorRanges(table, asTable, params, rangesByColID)
137✔
4068
                if err != nil {
137✔
4069
                        return err
×
4070
                }
×
4071

4072
                return bexp.right.selectorRanges(table, asTable, params, rangesByColID)
137✔
4073
        }
4074

4075
        lRanges := make(map[uint32]*typedValueRange)
13✔
4076
        rRanges := make(map[uint32]*typedValueRange)
13✔
4077

13✔
4078
        err := bexp.left.selectorRanges(table, asTable, params, lRanges)
13✔
4079
        if err != nil {
13✔
4080
                return err
×
4081
        }
×
4082

4083
        err = bexp.right.selectorRanges(table, asTable, params, rRanges)
13✔
4084
        if err != nil {
13✔
4085
                return err
×
4086
        }
×
4087

4088
        for colID, lr := range lRanges {
20✔
4089
                rr, ok := rRanges[colID]
7✔
4090
                if !ok {
9✔
4091
                        continue
2✔
4092
                }
4093

4094
                err = lr.extendWith(rr)
5✔
4095
                if err != nil {
5✔
4096
                        return err
×
4097
                }
×
4098

4099
                rangesByColID[colID] = lr
5✔
4100
        }
4101

4102
        return nil
13✔
4103
}
4104

4105
type ExistsBoolExp struct {
4106
        q DataSource
4107
}
4108

4109
func (bexp *ExistsBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
4110
        return AnyType, errors.New("not yet supported")
1✔
4111
}
1✔
4112

4113
func (bexp *ExistsBoolExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
1✔
4114
        return errors.New("not yet supported")
1✔
4115
}
1✔
4116

4117
func (bexp *ExistsBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
1✔
4118
        return bexp, nil
1✔
4119
}
1✔
4120

4121
func (bexp *ExistsBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1✔
4122
        return nil, errors.New("not yet supported")
1✔
4123
}
1✔
4124

4125
func (bexp *ExistsBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
4126
        return bexp
1✔
4127
}
1✔
4128

4129
func (bexp *ExistsBoolExp) isConstant() bool {
2✔
4130
        return false
2✔
4131
}
2✔
4132

4133
func (bexp *ExistsBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
4134
        return nil
1✔
4135
}
1✔
4136

4137
type InSubQueryExp struct {
4138
        val   ValueExp
4139
        notIn bool
4140
        q     *SelectStmt
4141
}
4142

4143
func (bexp *InSubQueryExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
4144
        return AnyType, fmt.Errorf("error inferring type in 'IN' clause: %w", ErrNoSupported)
1✔
4145
}
1✔
4146

4147
func (bexp *InSubQueryExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
1✔
4148
        return fmt.Errorf("error inferring type in 'IN' clause: %w", ErrNoSupported)
1✔
4149
}
1✔
4150

4151
func (bexp *InSubQueryExp) substitute(params map[string]interface{}) (ValueExp, error) {
1✔
4152
        return bexp, nil
1✔
4153
}
1✔
4154

4155
func (bexp *InSubQueryExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1✔
4156
        return nil, fmt.Errorf("error inferring type in 'IN' clause: %w", ErrNoSupported)
1✔
4157
}
1✔
4158

4159
func (bexp *InSubQueryExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
4160
        return bexp
1✔
4161
}
1✔
4162

4163
func (bexp *InSubQueryExp) isConstant() bool {
1✔
4164
        return false
1✔
4165
}
1✔
4166

4167
func (bexp *InSubQueryExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
4168
        return nil
1✔
4169
}
1✔
4170

4171
// TODO: once InSubQueryExp is supported, this struct may become obsolete by creating a ListDataSource struct
4172
type InListExp struct {
4173
        val    ValueExp
4174
        notIn  bool
4175
        values []ValueExp
4176
}
4177

4178
func (bexp *InListExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
4179
        t, err := bexp.val.inferType(cols, params, implicitTable)
6✔
4180
        if err != nil {
7✔
4181
                return AnyType, fmt.Errorf("error inferring type in 'IN' clause: %w", err)
1✔
4182
        }
1✔
4183

4184
        for _, v := range bexp.values {
15✔
4185
                err = v.requiresType(t, cols, params, implicitTable)
10✔
4186
                if err != nil {
11✔
4187
                        return AnyType, fmt.Errorf("error inferring type in 'IN' clause: %w", err)
1✔
4188
                }
1✔
4189
        }
4190

4191
        return BooleanType, nil
4✔
4192
}
4193

4194
func (bexp *InListExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
4195
        _, err := bexp.inferType(cols, params, implicitTable)
2✔
4196
        if err != nil {
3✔
4197
                return err
1✔
4198
        }
1✔
4199

4200
        if t != BooleanType {
1✔
4201
                return fmt.Errorf("error inferring type in 'IN' clause: %w", ErrInvalidTypes)
×
4202
        }
×
4203

4204
        return nil
1✔
4205
}
4206

4207
func (bexp *InListExp) substitute(params map[string]interface{}) (ValueExp, error) {
115✔
4208
        val, err := bexp.val.substitute(params)
115✔
4209
        if err != nil {
115✔
4210
                return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
×
4211
        }
×
4212

4213
        values := make([]ValueExp, len(bexp.values))
115✔
4214

115✔
4215
        for i, val := range bexp.values {
245✔
4216
                values[i], err = val.substitute(params)
130✔
4217
                if err != nil {
130✔
4218
                        return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
×
4219
                }
×
4220
        }
4221

4222
        return &InListExp{
115✔
4223
                val:    val,
115✔
4224
                notIn:  bexp.notIn,
115✔
4225
                values: values,
115✔
4226
        }, nil
115✔
4227
}
4228

4229
func (bexp *InListExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
115✔
4230
        rval, err := bexp.val.reduce(tx, row, implicitTable)
115✔
4231
        if err != nil {
116✔
4232
                return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
1✔
4233
        }
1✔
4234

4235
        var found bool
114✔
4236

114✔
4237
        for _, v := range bexp.values {
241✔
4238
                rv, err := v.reduce(tx, row, implicitTable)
127✔
4239
                if err != nil {
128✔
4240
                        return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
1✔
4241
                }
1✔
4242

4243
                r, err := rval.Compare(rv)
126✔
4244
                if err != nil {
127✔
4245
                        return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
1✔
4246
                }
1✔
4247

4248
                if r == 0 {
140✔
4249
                        // TODO: short-circuit evaluation may be preferred when upfront static type inference is in place
15✔
4250
                        found = found || true
15✔
4251
                }
15✔
4252
        }
4253

4254
        return &Bool{val: found != bexp.notIn}, nil
112✔
4255
}
4256

4257
func (bexp *InListExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
10✔
4258
        values := make([]ValueExp, len(bexp.values))
10✔
4259

10✔
4260
        for i, val := range bexp.values {
20✔
4261
                values[i] = val.reduceSelectors(row, implicitTable)
10✔
4262
        }
10✔
4263

4264
        return &InListExp{
10✔
4265
                val:    bexp.val.reduceSelectors(row, implicitTable),
10✔
4266
                values: values,
10✔
4267
        }
10✔
4268
}
4269

4270
func (bexp *InListExp) isConstant() bool {
1✔
4271
        return false
1✔
4272
}
1✔
4273

4274
func (bexp *InListExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
20✔
4275
        // TODO: may be determiined by smallest and bigggest value in the list
20✔
4276
        return nil
20✔
4277
}
20✔
4278

4279
type FnDataSourceStmt struct {
4280
        fnCall *FnCall
4281
        as     string
4282
}
4283

4284
func (stmt *FnDataSourceStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
×
4285
        return tx, nil
×
4286
}
×
4287

4288
func (stmt *FnDataSourceStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
4289
        return nil
1✔
4290
}
1✔
4291

4292
func (stmt *FnDataSourceStmt) Alias() string {
22✔
4293
        if stmt.as != "" {
24✔
4294
                return stmt.as
2✔
4295
        }
2✔
4296

4297
        switch strings.ToUpper(stmt.fnCall.fn) {
20✔
4298
        case DatabasesFnCall:
3✔
4299
                {
6✔
4300
                        return "databases"
3✔
4301
                }
3✔
4302
        case TablesFnCall:
5✔
4303
                {
10✔
4304
                        return "tables"
5✔
4305
                }
5✔
4306
        case TableFnCall:
×
4307
                {
×
4308
                        return "table"
×
4309
                }
×
4310
        case UsersFnCall:
7✔
4311
                {
14✔
4312
                        return "users"
7✔
4313
                }
7✔
4314
        case ColumnsFnCall:
3✔
4315
                {
6✔
4316
                        return "columns"
3✔
4317
                }
3✔
4318
        case IndexesFnCall:
2✔
4319
                {
4✔
4320
                        return "indexes"
2✔
4321
                }
2✔
4322
        }
4323

4324
        // not reachable
4325
        return ""
×
4326
}
4327

4328
func (stmt *FnDataSourceStmt) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, scanSpecs *ScanSpecs) (rowReader RowReader, err error) {
23✔
4329
        if stmt.fnCall == nil {
23✔
4330
                return nil, fmt.Errorf("%w: function is unspecified", ErrIllegalArguments)
×
4331
        }
×
4332

4333
        switch strings.ToUpper(stmt.fnCall.fn) {
23✔
4334
        case DatabasesFnCall:
5✔
4335
                {
10✔
4336
                        return stmt.resolveListDatabases(ctx, tx, params, scanSpecs)
5✔
4337
                }
5✔
4338
        case TablesFnCall:
5✔
4339
                {
10✔
4340
                        return stmt.resolveListTables(ctx, tx, params, scanSpecs)
5✔
4341
                }
5✔
4342
        case TableFnCall:
×
4343
                {
×
4344
                        return stmt.resolveShowTable(ctx, tx, params, scanSpecs)
×
4345
                }
×
4346
        case UsersFnCall:
7✔
4347
                {
14✔
4348
                        return stmt.resolveListUsers(ctx, tx, params, scanSpecs)
7✔
4349
                }
7✔
4350
        case ColumnsFnCall:
3✔
4351
                {
6✔
4352
                        return stmt.resolveListColumns(ctx, tx, params, scanSpecs)
3✔
4353
                }
3✔
4354
        case IndexesFnCall:
3✔
4355
                {
6✔
4356
                        return stmt.resolveListIndexes(ctx, tx, params, scanSpecs)
3✔
4357
                }
3✔
4358
        }
4359

4360
        return nil, fmt.Errorf("%w (%s)", ErrFunctionDoesNotExist, stmt.fnCall.fn)
×
4361
}
4362

4363
func (stmt *FnDataSourceStmt) resolveListDatabases(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (rowReader RowReader, err error) {
5✔
4364
        if len(stmt.fnCall.params) > 0 {
5✔
4365
                return nil, fmt.Errorf("%w: function '%s' expect no parameters but %d were provided", ErrIllegalArguments, DatabasesFnCall, len(stmt.fnCall.params))
×
4366
        }
×
4367

4368
        cols := make([]ColDescriptor, 1)
5✔
4369
        cols[0] = ColDescriptor{
5✔
4370
                Column: "name",
5✔
4371
                Type:   VarcharType,
5✔
4372
        }
5✔
4373

5✔
4374
        var dbs []string
5✔
4375

5✔
4376
        if tx.engine.multidbHandler == nil {
6✔
4377
                return nil, ErrUnspecifiedMultiDBHandler
1✔
4378
        } else {
5✔
4379
                dbs, err = tx.engine.multidbHandler.ListDatabases(ctx)
4✔
4380
                if err != nil {
4✔
4381
                        return nil, err
×
4382
                }
×
4383
        }
4384

4385
        values := make([][]ValueExp, len(dbs))
4✔
4386

4✔
4387
        for i, db := range dbs {
12✔
4388
                values[i] = []ValueExp{&Varchar{val: db}}
8✔
4389
        }
8✔
4390

4391
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
4✔
4392
}
4393

4394
func (stmt *FnDataSourceStmt) resolveListTables(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (rowReader RowReader, err error) {
5✔
4395
        if len(stmt.fnCall.params) > 0 {
5✔
4396
                return nil, fmt.Errorf("%w: function '%s' expect no parameters but %d were provided", ErrIllegalArguments, TablesFnCall, len(stmt.fnCall.params))
×
4397
        }
×
4398

4399
        cols := make([]ColDescriptor, 1)
5✔
4400
        cols[0] = ColDescriptor{
5✔
4401
                Column: "name",
5✔
4402
                Type:   VarcharType,
5✔
4403
        }
5✔
4404

5✔
4405
        tables := tx.catalog.GetTables()
5✔
4406

5✔
4407
        values := make([][]ValueExp, len(tables))
5✔
4408

5✔
4409
        for i, t := range tables {
14✔
4410
                values[i] = []ValueExp{&Varchar{val: t.name}}
9✔
4411
        }
9✔
4412

4413
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
5✔
4414
}
4415

4416
func (stmt *FnDataSourceStmt) resolveShowTable(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (rowReader RowReader, err error) {
×
4417
        cols := []ColDescriptor{
×
4418
                {
×
4419
                        Column: "column_name",
×
4420
                        Type:   VarcharType,
×
4421
                },
×
4422
                {
×
4423
                        Column: "type_name",
×
4424
                        Type:   VarcharType,
×
4425
                },
×
4426
                {
×
4427
                        Column: "is_nullable",
×
4428
                        Type:   BooleanType,
×
4429
                },
×
4430
                {
×
4431
                        Column: "is_indexed",
×
4432
                        Type:   VarcharType,
×
4433
                },
×
4434
                {
×
4435
                        Column: "is_auto_increment",
×
4436
                        Type:   BooleanType,
×
4437
                },
×
4438
                {
×
4439
                        Column: "is_unique",
×
4440
                        Type:   BooleanType,
×
4441
                },
×
4442
        }
×
4443

×
4444
        tableName, _ := stmt.fnCall.params[0].reduce(tx, nil, "")
×
4445
        table, err := tx.catalog.GetTableByName(tableName.RawValue().(string))
×
4446
        if err != nil {
×
4447
                return nil, err
×
4448
        }
×
4449

4450
        values := make([][]ValueExp, len(table.cols))
×
4451

×
4452
        for i, c := range table.cols {
×
4453
                index := "NO"
×
4454

×
4455
                indexed, err := table.IsIndexed(c.Name())
×
4456
                if err != nil {
×
4457
                        return nil, err
×
4458
                }
×
4459
                if indexed {
×
4460
                        index = "YES"
×
4461
                }
×
4462

4463
                if table.PrimaryIndex().IncludesCol(c.ID()) {
×
4464
                        index = "PRIMARY KEY"
×
4465
                }
×
4466

4467
                var unique bool
×
4468
                for _, index := range table.GetIndexesByColID(c.ID()) {
×
4469
                        if index.IsUnique() && len(index.Cols()) == 1 {
×
4470
                                unique = true
×
4471
                                break
×
4472
                        }
4473
                }
4474

4475
                var maxLen string
×
4476

×
4477
                if c.MaxLen() > 0 && (c.Type() == VarcharType || c.Type() == BLOBType) {
×
4478
                        maxLen = fmt.Sprintf("(%d)", c.MaxLen())
×
4479
                }
×
4480

4481
                values[i] = []ValueExp{
×
4482
                        &Varchar{val: c.colName},
×
4483
                        &Varchar{val: c.Type() + maxLen},
×
4484
                        &Bool{val: c.IsNullable()},
×
4485
                        &Varchar{val: index},
×
4486
                        &Bool{val: c.IsAutoIncremental()},
×
4487
                        &Bool{val: unique},
×
4488
                }
×
4489
        }
4490

4491
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
×
4492
}
4493

4494
func (stmt *FnDataSourceStmt) resolveListUsers(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (rowReader RowReader, err error) {
7✔
4495
        if len(stmt.fnCall.params) > 0 {
7✔
4496
                return nil, fmt.Errorf("%w: function '%s' expect no parameters but %d were provided", ErrIllegalArguments, UsersFnCall, len(stmt.fnCall.params))
×
4497
        }
×
4498

4499
        cols := make([]ColDescriptor, 2)
7✔
4500
        cols[0] = ColDescriptor{
7✔
4501
                Column: "name",
7✔
4502
                Type:   VarcharType,
7✔
4503
        }
7✔
4504
        cols[1] = ColDescriptor{
7✔
4505
                Column: "permission",
7✔
4506
                Type:   VarcharType,
7✔
4507
        }
7✔
4508

7✔
4509
        var users []User
7✔
4510

7✔
4511
        if tx.engine.multidbHandler == nil {
7✔
4512
                return nil, ErrUnspecifiedMultiDBHandler
×
4513
        } else {
7✔
4514
                users, err = tx.engine.multidbHandler.ListUsers(ctx)
7✔
4515
                if err != nil {
7✔
4516
                        return nil, err
×
4517
                }
×
4518
        }
4519

4520
        values := make([][]ValueExp, len(users))
7✔
4521

7✔
4522
        for i, user := range users {
21✔
4523
                var perm string
14✔
4524

14✔
4525
                switch user.Permission() {
14✔
4526
                case 1:
4✔
4527
                        {
8✔
4528
                                perm = "READ"
4✔
4529
                        }
4✔
4530
                case 2:
2✔
4531
                        {
4✔
4532
                                perm = "READ/WRITE"
2✔
4533
                        }
2✔
4534
                case 254:
3✔
4535
                        {
6✔
4536
                                perm = "ADMIN"
3✔
4537
                        }
3✔
4538
                default:
5✔
4539
                        {
10✔
4540
                                perm = "SYSADMIN"
5✔
4541
                        }
5✔
4542
                }
4543

4544
                values[i] = []ValueExp{
14✔
4545
                        &Varchar{val: user.Username()},
14✔
4546
                        &Varchar{val: perm},
14✔
4547
                }
14✔
4548
        }
4549

4550
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
7✔
4551
}
4552

4553
func (stmt *FnDataSourceStmt) resolveListColumns(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (RowReader, error) {
3✔
4554
        if len(stmt.fnCall.params) != 1 {
3✔
4555
                return nil, fmt.Errorf("%w: function '%s' expect table name as parameter", ErrIllegalArguments, ColumnsFnCall)
×
4556
        }
×
4557

4558
        cols := []ColDescriptor{
3✔
4559
                {
3✔
4560
                        Column: "table",
3✔
4561
                        Type:   VarcharType,
3✔
4562
                },
3✔
4563
                {
3✔
4564
                        Column: "name",
3✔
4565
                        Type:   VarcharType,
3✔
4566
                },
3✔
4567
                {
3✔
4568
                        Column: "type",
3✔
4569
                        Type:   VarcharType,
3✔
4570
                },
3✔
4571
                {
3✔
4572
                        Column: "max_length",
3✔
4573
                        Type:   IntegerType,
3✔
4574
                },
3✔
4575
                {
3✔
4576
                        Column: "nullable",
3✔
4577
                        Type:   BooleanType,
3✔
4578
                },
3✔
4579
                {
3✔
4580
                        Column: "auto_increment",
3✔
4581
                        Type:   BooleanType,
3✔
4582
                },
3✔
4583
                {
3✔
4584
                        Column: "indexed",
3✔
4585
                        Type:   BooleanType,
3✔
4586
                },
3✔
4587
                {
3✔
4588
                        Column: "primary",
3✔
4589
                        Type:   BooleanType,
3✔
4590
                },
3✔
4591
                {
3✔
4592
                        Column: "unique",
3✔
4593
                        Type:   BooleanType,
3✔
4594
                },
3✔
4595
        }
3✔
4596

3✔
4597
        val, err := stmt.fnCall.params[0].substitute(params)
3✔
4598
        if err != nil {
3✔
4599
                return nil, err
×
4600
        }
×
4601

4602
        tableName, err := val.reduce(tx, nil, "")
3✔
4603
        if err != nil {
3✔
4604
                return nil, err
×
4605
        }
×
4606

4607
        if tableName.Type() != VarcharType {
3✔
4608
                return nil, fmt.Errorf("%w: expected '%s' for table name but type '%s' given instead", ErrIllegalArguments, VarcharType, tableName.Type())
×
4609
        }
×
4610

4611
        table, err := tx.catalog.GetTableByName(tableName.RawValue().(string))
3✔
4612
        if err != nil {
3✔
4613
                return nil, err
×
4614
        }
×
4615

4616
        values := make([][]ValueExp, len(table.cols))
3✔
4617

3✔
4618
        for i, c := range table.cols {
11✔
4619
                indexed, err := table.IsIndexed(c.Name())
8✔
4620
                if err != nil {
8✔
4621
                        return nil, err
×
4622
                }
×
4623

4624
                var unique bool
8✔
4625
                for _, index := range table.indexesByColID[c.id] {
16✔
4626
                        if index.IsUnique() && len(index.Cols()) == 1 {
11✔
4627
                                unique = true
3✔
4628
                                break
3✔
4629
                        }
4630
                }
4631

4632
                values[i] = []ValueExp{
8✔
4633
                        &Varchar{val: table.name},
8✔
4634
                        &Varchar{val: c.colName},
8✔
4635
                        &Varchar{val: c.colType},
8✔
4636
                        &Integer{val: int64(c.MaxLen())},
8✔
4637
                        &Bool{val: c.IsNullable()},
8✔
4638
                        &Bool{val: c.autoIncrement},
8✔
4639
                        &Bool{val: indexed},
8✔
4640
                        &Bool{val: table.PrimaryIndex().IncludesCol(c.ID())},
8✔
4641
                        &Bool{val: unique},
8✔
4642
                }
8✔
4643
        }
4644

4645
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
3✔
4646
}
4647

4648
func (stmt *FnDataSourceStmt) resolveListIndexes(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (RowReader, error) {
3✔
4649
        if len(stmt.fnCall.params) != 1 {
3✔
4650
                return nil, fmt.Errorf("%w: function '%s' expect table name as parameter", ErrIllegalArguments, IndexesFnCall)
×
4651
        }
×
4652

4653
        cols := []ColDescriptor{
3✔
4654
                {
3✔
4655
                        Column: "table",
3✔
4656
                        Type:   VarcharType,
3✔
4657
                },
3✔
4658
                {
3✔
4659
                        Column: "name",
3✔
4660
                        Type:   VarcharType,
3✔
4661
                },
3✔
4662
                {
3✔
4663
                        Column: "unique",
3✔
4664
                        Type:   BooleanType,
3✔
4665
                },
3✔
4666
                {
3✔
4667
                        Column: "primary",
3✔
4668
                        Type:   BooleanType,
3✔
4669
                },
3✔
4670
        }
3✔
4671

3✔
4672
        val, err := stmt.fnCall.params[0].substitute(params)
3✔
4673
        if err != nil {
3✔
4674
                return nil, err
×
4675
        }
×
4676

4677
        tableName, err := val.reduce(tx, nil, "")
3✔
4678
        if err != nil {
3✔
4679
                return nil, err
×
4680
        }
×
4681

4682
        if tableName.Type() != VarcharType {
3✔
4683
                return nil, fmt.Errorf("%w: expected '%s' for table name but type '%s' given instead", ErrIllegalArguments, VarcharType, tableName.Type())
×
4684
        }
×
4685

4686
        table, err := tx.catalog.GetTableByName(tableName.RawValue().(string))
3✔
4687
        if err != nil {
3✔
4688
                return nil, err
×
4689
        }
×
4690

4691
        values := make([][]ValueExp, len(table.indexes))
3✔
4692

3✔
4693
        for i, index := range table.indexes {
10✔
4694
                values[i] = []ValueExp{
7✔
4695
                        &Varchar{val: table.name},
7✔
4696
                        &Varchar{val: index.Name()},
7✔
4697
                        &Bool{val: index.unique},
7✔
4698
                        &Bool{val: index.IsPrimary()},
7✔
4699
                }
7✔
4700
        }
7✔
4701

4702
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
3✔
4703
}
4704

4705
// DropTableStmt represents a statement to delete a table.
4706
type DropTableStmt struct {
4707
        table string
4708
}
4709

4710
func NewDropTableStmt(table string) *DropTableStmt {
6✔
4711
        return &DropTableStmt{table: table}
6✔
4712
}
6✔
4713

4714
func (stmt *DropTableStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
4715
        return nil
1✔
4716
}
1✔
4717

4718
/*
4719
Exec executes the delete table statement.
4720
It the table exists, if not it does nothing.
4721
If the table exists, it deletes all the indexes and the table itself.
4722
Note that this is a soft delete of the index and table key,
4723
the data is not deleted, but the metadata is updated.
4724
*/
4725
func (stmt *DropTableStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
7✔
4726
        if !tx.catalog.ExistTable(stmt.table) {
8✔
4727
                return nil, ErrTableDoesNotExist
1✔
4728
        }
1✔
4729

4730
        table, err := tx.catalog.GetTableByName(stmt.table)
6✔
4731
        if err != nil {
6✔
4732
                return nil, err
×
4733
        }
×
4734

4735
        // delete table
4736
        mappedKey := MapKey(
6✔
4737
                tx.sqlPrefix(),
6✔
4738
                catalogTablePrefix,
6✔
4739
                EncodeID(DatabaseID),
6✔
4740
                EncodeID(table.id),
6✔
4741
        )
6✔
4742
        err = tx.delete(ctx, mappedKey)
6✔
4743
        if err != nil {
6✔
4744
                return nil, err
×
4745
        }
×
4746

4747
        // delete columns
4748
        cols := table.ColumnsByID()
6✔
4749
        for _, col := range cols {
26✔
4750
                mappedKey := MapKey(
20✔
4751
                        tx.sqlPrefix(),
20✔
4752
                        catalogColumnPrefix,
20✔
4753
                        EncodeID(DatabaseID),
20✔
4754
                        EncodeID(col.table.id),
20✔
4755
                        EncodeID(col.id),
20✔
4756
                        []byte(col.colType),
20✔
4757
                )
20✔
4758
                err = tx.delete(ctx, mappedKey)
20✔
4759
                if err != nil {
20✔
4760
                        return nil, err
×
4761
                }
×
4762
        }
4763

4764
        // delete indexes
4765
        for _, index := range table.indexes {
13✔
4766
                mappedKey := MapKey(
7✔
4767
                        tx.sqlPrefix(),
7✔
4768
                        catalogIndexPrefix,
7✔
4769
                        EncodeID(DatabaseID),
7✔
4770
                        EncodeID(table.id),
7✔
4771
                        EncodeID(index.id),
7✔
4772
                )
7✔
4773
                err = tx.delete(ctx, mappedKey)
7✔
4774
                if err != nil {
7✔
4775
                        return nil, err
×
4776
                }
×
4777

4778
                indexKey := MapKey(
7✔
4779
                        tx.sqlPrefix(),
7✔
4780
                        MappedPrefix,
7✔
4781
                        EncodeID(table.id),
7✔
4782
                        EncodeID(index.id),
7✔
4783
                )
7✔
4784
                err = tx.addOnCommittedCallback(func(sqlTx *SQLTx) error {
14✔
4785
                        return sqlTx.engine.store.DeleteIndex(indexKey)
7✔
4786
                })
7✔
4787
                if err != nil {
7✔
4788
                        return nil, err
×
4789
                }
×
4790
        }
4791

4792
        err = tx.catalog.deleteTable(table)
6✔
4793
        if err != nil {
6✔
4794
                return nil, err
×
4795
        }
×
4796

4797
        tx.mutatedCatalog = true
6✔
4798

6✔
4799
        return tx, nil
6✔
4800
}
4801

4802
// DropIndexStmt represents a statement to delete a table.
4803
type DropIndexStmt struct {
4804
        table string
4805
        cols  []string
4806
}
4807

4808
func NewDropIndexStmt(table string, cols []string) *DropIndexStmt {
4✔
4809
        return &DropIndexStmt{table: table, cols: cols}
4✔
4810
}
4✔
4811

4812
func (stmt *DropIndexStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
4813
        return nil
1✔
4814
}
1✔
4815

4816
/*
4817
Exec executes the delete index statement.
4818
If the index exists, it deletes it. Note that this is a soft delete of the index
4819
the data is not deleted, but the metadata is updated.
4820
*/
4821
func (stmt *DropIndexStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
6✔
4822
        if !tx.catalog.ExistTable(stmt.table) {
7✔
4823
                return nil, ErrTableDoesNotExist
1✔
4824
        }
1✔
4825

4826
        table, err := tx.catalog.GetTableByName(stmt.table)
5✔
4827
        if err != nil {
5✔
4828
                return nil, err
×
4829
        }
×
4830

4831
        cols := make([]*Column, len(stmt.cols))
5✔
4832

5✔
4833
        for i, colName := range stmt.cols {
10✔
4834
                col, err := table.GetColumnByName(colName)
5✔
4835
                if err != nil {
5✔
4836
                        return nil, err
×
4837
                }
×
4838

4839
                cols[i] = col
5✔
4840
        }
4841

4842
        index, err := table.GetIndexByName(indexName(table.name, cols))
5✔
4843
        if err != nil {
5✔
4844
                return nil, err
×
4845
        }
×
4846

4847
        // delete index
4848
        mappedKey := MapKey(
5✔
4849
                tx.sqlPrefix(),
5✔
4850
                catalogIndexPrefix,
5✔
4851
                EncodeID(DatabaseID),
5✔
4852
                EncodeID(table.id),
5✔
4853
                EncodeID(index.id),
5✔
4854
        )
5✔
4855
        err = tx.delete(ctx, mappedKey)
5✔
4856
        if err != nil {
5✔
4857
                return nil, err
×
4858
        }
×
4859

4860
        indexKey := MapKey(
5✔
4861
                tx.sqlPrefix(),
5✔
4862
                MappedPrefix,
5✔
4863
                EncodeID(table.id),
5✔
4864
                EncodeID(index.id),
5✔
4865
        )
5✔
4866

5✔
4867
        err = tx.addOnCommittedCallback(func(sqlTx *SQLTx) error {
9✔
4868
                return sqlTx.engine.store.DeleteIndex(indexKey)
4✔
4869
        })
4✔
4870
        if err != nil {
5✔
4871
                return nil, err
×
4872
        }
×
4873

4874
        err = table.deleteIndex(index)
5✔
4875
        if err != nil {
6✔
4876
                return nil, err
1✔
4877
        }
1✔
4878

4879
        tx.mutatedCatalog = true
4✔
4880

4✔
4881
        return tx, nil
4✔
4882
}
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