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

codenotary / immudb / 6562442758

18 Oct 2023 02:33PM UTC coverage: 89.595% (-0.003%) from 89.598%
6562442758

push

gh-ci

jeroiraz
feat(embedded/sql): table renaming

Signed-off-by: Jeronimo Irazabal <jeronimo.irazabal@gmail.com>

175 of 175 new or added lines in 3 files covered. (100.0%)

33546 of 37442 relevant lines covered (89.59%)

145176.5 hits per line

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

85.57
/embedded/sql/stmt.go
1
/*
2
Copyright 2022 Codenotary Inc. All rights reserved.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
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
        http://www.apache.org/licenses/LICENSE-2.0
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
        "errors"
24
        "fmt"
25
        "math"
26
        "regexp"
27
        "strings"
28
        "time"
29

30
        "github.com/codenotary/immudb/embedded/store"
31
        "github.com/google/uuid"
32
)
33

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

40
        RowPrefix = "R." // (key=R.{1}{tableID}{0}({null}({pkVal}{padding}{pkValLen})?)+, value={count (colID valLen val)+})
41

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

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

48
const (
49
        nullableFlag      byte = 1 << iota
50
        autoIncrementFlag byte = 1 << iota
51
)
52

53
const revCol = "_rev"
54

55
type SQLValueType = string
56

57
const (
58
        IntegerType   SQLValueType = "INTEGER"
59
        BooleanType   SQLValueType = "BOOLEAN"
60
        VarcharType   SQLValueType = "VARCHAR"
61
        UUIDType      SQLValueType = "UUID"
62
        BLOBType      SQLValueType = "BLOB"
63
        Float64Type   SQLValueType = "FLOAT"
64
        TimestampType SQLValueType = "TIMESTAMP"
65
        AnyType       SQLValueType = "ANY"
66
)
67

68
func IsNumericType(t SQLValueType) bool {
52✔
69
        return t == IntegerType || t == Float64Type
52✔
70
}
52✔
71

72
type AggregateFn = string
73

74
const (
75
        COUNT AggregateFn = "COUNT"
76
        SUM   AggregateFn = "SUM"
77
        MAX   AggregateFn = "MAX"
78
        MIN   AggregateFn = "MIN"
79
        AVG   AggregateFn = "AVG"
80
)
81

82
type CmpOperator = int
83

84
const (
85
        EQ CmpOperator = iota
86
        NE
87
        LT
88
        LE
89
        GT
90
        GE
91
)
92

93
type LogicOperator = int
94

95
const (
96
        AND LogicOperator = iota
97
        OR
98
)
99

100
type NumOperator = int
101

102
const (
103
        ADDOP NumOperator = iota
104
        SUBSOP
105
        DIVOP
106
        MULTOP
107
)
108

109
type JoinType = int
110

111
const (
112
        InnerJoin JoinType = iota
113
        LeftJoin
114
        RightJoin
115
)
116

117
const (
118
        NowFnCall       string = "NOW"
119
        UUIDFnCall      string = "RANDOM_UUID"
120
        DatabasesFnCall string = "DATABASES"
121
        TablesFnCall    string = "TABLES"
122
        ColumnsFnCall   string = "COLUMNS"
123
        IndexesFnCall   string = "INDEXES"
124
)
125

126
type SQLStmt interface {
127
        execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error)
128
        inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error
129
}
130

131
type BeginTransactionStmt struct {
132
}
133

134
func (stmt *BeginTransactionStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
3✔
135
        return nil
3✔
136
}
3✔
137

138
func (stmt *BeginTransactionStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
54✔
139
        if tx.IsExplicitCloseRequired() {
55✔
140
                return nil, ErrNestedTxNotSupported
1✔
141
        }
1✔
142

143
        err := tx.RequireExplicitClose()
53✔
144
        if err == nil {
105✔
145
                // current tx can be reused as no changes were already made
52✔
146
                return tx, nil
52✔
147
        }
52✔
148

149
        // commit current transaction and start a fresh one
150

151
        err = tx.Commit(ctx)
1✔
152
        if err != nil {
1✔
153
                return nil, err
×
154
        }
×
155

156
        return tx.engine.NewTx(ctx, tx.opts.WithExplicitClose(true))
1✔
157
}
158

159
type CommitStmt struct {
160
}
161

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

166
func (stmt *CommitStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
159✔
167
        if !tx.IsExplicitCloseRequired() {
160✔
168
                return nil, ErrNoOngoingTx
1✔
169
        }
1✔
170

171
        return nil, tx.Commit(ctx)
158✔
172
}
173

174
type RollbackStmt struct {
175
}
176

177
func (stmt *RollbackStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
178
        return nil
1✔
179
}
1✔
180

181
func (stmt *RollbackStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
1✔
182
        if !tx.IsExplicitCloseRequired() {
2✔
183
                return nil, ErrNoOngoingTx
1✔
184
        }
1✔
185

186
        return nil, tx.Cancel()
×
187
}
188

189
type CreateDatabaseStmt struct {
190
        DB          string
191
        ifNotExists bool
192
}
193

194
func (stmt *CreateDatabaseStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
4✔
195
        return nil
4✔
196
}
4✔
197

198
func (stmt *CreateDatabaseStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
13✔
199
        if tx.IsExplicitCloseRequired() {
14✔
200
                return nil, fmt.Errorf("%w: database creation can not be done within a transaction", ErrNonTransactionalStmt)
1✔
201
        }
1✔
202

203
        if tx.engine.multidbHandler == nil {
14✔
204
                return nil, ErrUnspecifiedMultiDBHandler
2✔
205
        }
2✔
206

207
        return nil, tx.engine.multidbHandler.CreateDatabase(ctx, stmt.DB, stmt.ifNotExists)
10✔
208
}
209

210
type UseDatabaseStmt struct {
211
        DB string
212
}
213

214
func (stmt *UseDatabaseStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
215
        return nil
1✔
216
}
1✔
217

218
func (stmt *UseDatabaseStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
9✔
219
        if stmt.DB == "" {
9✔
220
                return nil, fmt.Errorf("%w: no database name was provided", ErrIllegalArguments)
×
221
        }
×
222

223
        if tx.IsExplicitCloseRequired() {
10✔
224
                return nil, fmt.Errorf("%w: database selection can NOT be executed within a transaction block", ErrNonTransactionalStmt)
1✔
225
        }
1✔
226

227
        if tx.engine.multidbHandler == nil {
9✔
228
                return nil, ErrUnspecifiedMultiDBHandler
1✔
229
        }
1✔
230

231
        return tx, tx.engine.multidbHandler.UseDatabase(ctx, stmt.DB)
7✔
232
}
233

234
type UseSnapshotStmt struct {
235
        period period
236
}
237

238
func (stmt *UseSnapshotStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
239
        return nil
1✔
240
}
1✔
241

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

246
type CreateTableStmt struct {
247
        table       string
248
        ifNotExists bool
249
        colsSpec    []*ColSpec
250
        pkColNames  []string
251
}
252

253
func NewCreateTableStmt(table string, ifNotExists bool, colsSpec []*ColSpec, pkColNames []string) *CreateTableStmt {
38✔
254
        return &CreateTableStmt{table: table, ifNotExists: ifNotExists, colsSpec: colsSpec, pkColNames: pkColNames}
38✔
255
}
38✔
256

257
func (stmt *CreateTableStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
4✔
258
        return nil
4✔
259
}
4✔
260

261
func (stmt *CreateTableStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
206✔
262
        if stmt.ifNotExists && tx.catalog.ExistTable(stmt.table) {
207✔
263
                return tx, nil
1✔
264
        }
1✔
265

266
        colSpecs := make(map[uint32]*ColSpec, len(stmt.colsSpec))
205✔
267
        for i, cs := range stmt.colsSpec {
853✔
268
                colSpecs[uint32(i)+1] = cs
648✔
269
        }
648✔
270

271
        table, err := tx.catalog.newTable(stmt.table, colSpecs, uint32(len(colSpecs)))
205✔
272
        if err != nil {
211✔
273
                return nil, err
6✔
274
        }
6✔
275

276
        createIndexStmt := &CreateIndexStmt{unique: true, table: table.name, cols: stmt.pkColNames}
199✔
277
        _, err = createIndexStmt.execAt(ctx, tx, params)
199✔
278
        if err != nil {
203✔
279
                return nil, err
4✔
280
        }
4✔
281

282
        for _, col := range table.cols {
827✔
283
                if col.autoIncrement {
700✔
284
                        if len(table.primaryIndex.cols) > 1 || col.id != table.primaryIndex.cols[0].id {
69✔
285
                                return nil, ErrLimitedAutoIncrement
1✔
286
                        }
1✔
287
                }
288

289
                err := persistColumn(tx, col)
631✔
290
                if err != nil {
631✔
291
                        return nil, err
×
292
                }
×
293
        }
294

295
        mappedKey := MapKey(tx.sqlPrefix(), catalogTablePrefix, EncodeID(DatabaseID), EncodeID(table.id))
194✔
296

194✔
297
        err = tx.set(mappedKey, nil, []byte(table.name))
194✔
298
        if err != nil {
194✔
299
                return nil, err
×
300
        }
×
301

302
        tx.mutatedCatalog = true
194✔
303

194✔
304
        return tx, nil
194✔
305
}
306

307
func persistColumn(tx *SQLTx, col *Column) error {
651✔
308
        //{auto_incremental | nullable}{maxLen}{colNAME})
651✔
309
        v := make([]byte, 1+4+len(col.colName))
651✔
310

651✔
311
        if col.autoIncrement {
718✔
312
                v[0] = v[0] | autoIncrementFlag
67✔
313
        }
67✔
314

315
        if col.notNull {
695✔
316
                v[0] = v[0] | nullableFlag
44✔
317
        }
44✔
318

319
        binary.BigEndian.PutUint32(v[1:], uint32(col.MaxLen()))
651✔
320

651✔
321
        copy(v[5:], []byte(col.Name()))
651✔
322

651✔
323
        mappedKey := MapKey(
651✔
324
                tx.sqlPrefix(),
651✔
325
                catalogColumnPrefix,
651✔
326
                EncodeID(DatabaseID),
651✔
327
                EncodeID(col.table.id),
651✔
328
                EncodeID(col.id),
651✔
329
                []byte(col.colType),
651✔
330
        )
651✔
331

651✔
332
        return tx.set(mappedKey, nil, v)
651✔
333
}
334

335
type ColSpec struct {
336
        colName       string
337
        colType       SQLValueType
338
        maxLen        int
339
        autoIncrement bool
340
        notNull       bool
341
}
342

343
func NewColSpec(name string, colType SQLValueType, maxLen int, autoIncrement bool, notNull bool) *ColSpec {
188✔
344
        return &ColSpec{
188✔
345
                colName:       name,
188✔
346
                colType:       colType,
188✔
347
                maxLen:        maxLen,
188✔
348
                autoIncrement: autoIncrement,
188✔
349
                notNull:       notNull,
188✔
350
        }
188✔
351
}
188✔
352

353
type CreateIndexStmt struct {
354
        unique      bool
355
        ifNotExists bool
356
        table       string
357
        cols        []string
358
}
359

360
func NewCreateIndexStmt(table string, cols []string, isUnique bool) *CreateIndexStmt {
72✔
361
        return &CreateIndexStmt{unique: isUnique, table: table, cols: cols}
72✔
362
}
72✔
363

364
func (stmt *CreateIndexStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
365
        return nil
1✔
366
}
1✔
367

368
func (stmt *CreateIndexStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
343✔
369
        if len(stmt.cols) < 1 {
344✔
370
                return nil, ErrIllegalArguments
1✔
371
        }
1✔
372

373
        if len(stmt.cols) > MaxNumberOfColumnsInIndex {
343✔
374
                return nil, ErrMaxNumberOfColumnsInIndexExceeded
1✔
375
        }
1✔
376

377
        table, err := tx.catalog.GetTableByName(stmt.table)
341✔
378
        if err != nil {
343✔
379
                return nil, err
2✔
380
        }
2✔
381

382
        colIDs := make([]uint32, len(stmt.cols))
339✔
383

339✔
384
        indexKeyLen := 0
339✔
385

339✔
386
        for i, colName := range stmt.cols {
694✔
387
                col, err := table.GetColumnByName(colName)
355✔
388
                if err != nil {
360✔
389
                        return nil, err
5✔
390
                }
5✔
391

392
                if variableSizedType(col.colType) && !tx.engine.lazyIndexConstraintValidation && (col.MaxLen() == 0 || col.MaxLen() > MaxKeyLen) {
352✔
393
                        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✔
394
                }
2✔
395

396
                indexKeyLen += col.MaxLen()
348✔
397

348✔
398
                colIDs[i] = col.id
348✔
399
        }
400

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

405
        if stmt.unique && table.primaryIndex != nil {
352✔
406
                // check table is empty
20✔
407
                pkPrefix := MapKey(tx.sqlPrefix(), MappedPrefix, EncodeID(table.id), EncodeID(table.primaryIndex.id))
20✔
408
                _, _, err := tx.getWithPrefix(ctx, pkPrefix, nil)
20✔
409
                if errors.Is(err, store.ErrIndexNotFound) {
20✔
410
                        return nil, ErrTableDoesNotExist
×
411
                }
×
412
                if err == nil {
21✔
413
                        return nil, ErrLimitedIndexCreation
1✔
414
                } else if !errors.Is(err, store.ErrKeyNotFound) {
20✔
415
                        return nil, err
×
416
                }
×
417
        }
418

419
        index, err := table.newIndex(stmt.unique, colIDs)
331✔
420
        if errors.Is(err, ErrIndexAlreadyExists) && stmt.ifNotExists {
333✔
421
                return tx, nil
2✔
422
        }
2✔
423
        if err != nil {
333✔
424
                return nil, err
4✔
425
        }
4✔
426

427
        // v={unique {colID1}(ASC|DESC)...{colIDN}(ASC|DESC)}
428
        // TODO: currently only ASC order is supported
429
        colSpecLen := EncIDLen + 1
325✔
430

325✔
431
        encodedValues := make([]byte, 1+len(index.cols)*colSpecLen)
325✔
432

325✔
433
        if index.IsUnique() {
538✔
434
                encodedValues[0] = 1
213✔
435
        }
213✔
436

437
        for i, col := range index.cols {
666✔
438
                copy(encodedValues[1+i*colSpecLen:], EncodeID(col.id))
341✔
439
        }
341✔
440

441
        mappedKey := MapKey(tx.sqlPrefix(), catalogIndexPrefix, EncodeID(DatabaseID), EncodeID(table.id), EncodeID(index.id))
325✔
442

325✔
443
        err = tx.set(mappedKey, nil, encodedValues)
325✔
444
        if err != nil {
325✔
445
                return nil, err
×
446
        }
×
447

448
        tx.mutatedCatalog = true
325✔
449

325✔
450
        return tx, nil
325✔
451
}
452

453
type AddColumnStmt struct {
454
        table   string
455
        colSpec *ColSpec
456
}
457

458
func NewAddColumnStmt(table string, colSpec *ColSpec) *AddColumnStmt {
6✔
459
        return &AddColumnStmt{table: table, colSpec: colSpec}
6✔
460
}
6✔
461

462
func (stmt *AddColumnStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
463
        return nil
1✔
464
}
1✔
465

466
func (stmt *AddColumnStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
19✔
467
        table, err := tx.catalog.GetTableByName(stmt.table)
19✔
468
        if err != nil {
20✔
469
                return nil, err
1✔
470
        }
1✔
471

472
        col, err := table.newColumn(stmt.colSpec)
18✔
473
        if err != nil {
24✔
474
                return nil, err
6✔
475
        }
6✔
476

477
        err = persistColumn(tx, col)
12✔
478
        if err != nil {
12✔
479
                return nil, err
×
480
        }
×
481

482
        tx.mutatedCatalog = true
12✔
483

12✔
484
        return tx, nil
12✔
485
}
486

487
type RenameTableStmt struct {
488
        oldName string
489
        newName string
490
}
491

492
func (stmt *RenameTableStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
×
493
        return nil
×
494
}
×
495

496
func (stmt *RenameTableStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
5✔
497
        table, err := tx.catalog.renameTable(stmt.oldName, stmt.newName)
5✔
498
        if err != nil {
8✔
499
                return nil, err
3✔
500
        }
3✔
501

502
        // update table name
503
        mappedKey := MapKey(
2✔
504
                tx.sqlPrefix(),
2✔
505
                catalogTablePrefix,
2✔
506
                EncodeID(DatabaseID),
2✔
507
                EncodeID(table.id),
2✔
508
        )
2✔
509
        err = tx.set(mappedKey, nil, []byte(stmt.newName))
2✔
510
        if err != nil {
2✔
511
                return nil, err
×
512
        }
×
513

514
        tx.mutatedCatalog = true
2✔
515

2✔
516
        return tx, nil
2✔
517
}
518

519
type RenameColumnStmt struct {
520
        table   string
521
        oldName string
522
        newName string
523
}
524

525
func NewRenameColumnStmt(table, oldName, newName string) *RenameColumnStmt {
3✔
526
        return &RenameColumnStmt{table: table, oldName: oldName, newName: newName}
3✔
527
}
3✔
528

529
func (stmt *RenameColumnStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
530
        return nil
1✔
531
}
1✔
532

533
func (stmt *RenameColumnStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
10✔
534
        table, err := tx.catalog.GetTableByName(stmt.table)
10✔
535
        if err != nil {
11✔
536
                return nil, err
1✔
537
        }
1✔
538

539
        col, err := table.renameColumn(stmt.oldName, stmt.newName)
9✔
540
        if err != nil {
12✔
541
                return nil, err
3✔
542
        }
3✔
543

544
        err = persistColumn(tx, col)
6✔
545
        if err != nil {
6✔
546
                return nil, err
×
547
        }
×
548

549
        tx.mutatedCatalog = true
6✔
550

6✔
551
        return tx, nil
6✔
552
}
553

554
type DropColumnStmt struct {
555
        table   string
556
        colName string
557
}
558

559
func NewDropColumnStmt(table, colName string) *DropColumnStmt {
8✔
560
        return &DropColumnStmt{table: table, colName: colName}
8✔
561
}
8✔
562

563
func (stmt *DropColumnStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
×
564
        return nil
×
565
}
×
566

567
func (stmt *DropColumnStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
16✔
568
        table, err := tx.catalog.GetTableByName(stmt.table)
16✔
569
        if err != nil {
17✔
570
                return nil, err
1✔
571
        }
1✔
572

573
        col, err := table.GetColumnByName(stmt.colName)
15✔
574
        if err != nil {
19✔
575
                return nil, err
4✔
576
        }
4✔
577

578
        err = table.deleteColumn(col)
11✔
579
        if err != nil {
15✔
580
                return nil, err
4✔
581
        }
4✔
582

583
        err = persistColumnDeletion(ctx, tx, col)
7✔
584
        if err != nil {
7✔
585
                return nil, err
×
586
        }
×
587

588
        tx.mutatedCatalog = true
7✔
589

7✔
590
        return tx, nil
7✔
591
}
592

593
func persistColumnDeletion(ctx context.Context, tx *SQLTx, col *Column) error {
8✔
594
        mappedKey := MapKey(
8✔
595
                tx.sqlPrefix(),
8✔
596
                catalogColumnPrefix,
8✔
597
                EncodeID(DatabaseID),
8✔
598
                EncodeID(col.table.id),
8✔
599
                EncodeID(col.id),
8✔
600
                []byte(col.colType),
8✔
601
        )
8✔
602

8✔
603
        return tx.delete(ctx, mappedKey)
8✔
604
}
8✔
605

606
type UpsertIntoStmt struct {
607
        isInsert   bool
608
        tableRef   *tableRef
609
        cols       []string
610
        rows       []*RowSpec
611
        onConflict *OnConflictDo
612
}
613

614
func NewUpserIntoStmt(table string, cols []string, rows []*RowSpec, isInsert bool, onConflict *OnConflictDo) *UpsertIntoStmt {
120✔
615
        return &UpsertIntoStmt{
120✔
616
                isInsert:   isInsert,
120✔
617
                tableRef:   NewTableRef(table, ""),
120✔
618
                cols:       cols,
120✔
619
                rows:       rows,
120✔
620
                onConflict: onConflict,
120✔
621
        }
120✔
622
}
120✔
623

624
type RowSpec struct {
625
        Values []ValueExp
626
}
627

628
func NewRowSpec(values []ValueExp) *RowSpec {
129✔
629
        return &RowSpec{
129✔
630
                Values: values,
129✔
631
        }
129✔
632
}
129✔
633

634
type OnConflictDo struct {
635
}
636

637
func (stmt *UpsertIntoStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
11✔
638
        for _, row := range stmt.rows {
23✔
639
                if len(stmt.cols) != len(row.Values) {
13✔
640
                        return ErrInvalidNumberOfValues
1✔
641
                }
1✔
642

643
                for i, val := range row.Values {
36✔
644
                        table, err := stmt.tableRef.referencedTable(tx)
25✔
645
                        if err != nil {
26✔
646
                                return err
1✔
647
                        }
1✔
648

649
                        col, err := table.GetColumnByName(stmt.cols[i])
24✔
650
                        if err != nil {
25✔
651
                                return err
1✔
652
                        }
1✔
653

654
                        err = val.requiresType(col.colType, make(map[string]ColDescriptor), params, table.name)
23✔
655
                        if err != nil {
25✔
656
                                return err
2✔
657
                        }
2✔
658
                }
659
        }
660

661
        return nil
6✔
662
}
663

664
func (stmt *UpsertIntoStmt) validate(table *Table) (map[uint32]int, error) {
830✔
665
        selPosByColID := make(map[uint32]int, len(stmt.cols))
830✔
666

830✔
667
        for i, c := range stmt.cols {
2,817✔
668
                col, err := table.GetColumnByName(c)
1,987✔
669
                if err != nil {
1,989✔
670
                        return nil, err
2✔
671
                }
2✔
672

673
                _, duplicated := selPosByColID[col.id]
1,985✔
674
                if duplicated {
1,986✔
675
                        return nil, fmt.Errorf("%w (%s)", ErrDuplicatedColumn, col.colName)
1✔
676
                }
1✔
677

678
                selPosByColID[col.id] = i
1,984✔
679
        }
680

681
        return selPosByColID, nil
827✔
682
}
683

684
func (stmt *UpsertIntoStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
833✔
685
        table, err := stmt.tableRef.referencedTable(tx)
833✔
686
        if err != nil {
836✔
687
                return nil, err
3✔
688
        }
3✔
689

690
        selPosByColID, err := stmt.validate(table)
830✔
691
        if err != nil {
833✔
692
                return nil, err
3✔
693
        }
3✔
694

695
        for _, row := range stmt.rows {
1,726✔
696
                if len(row.Values) != len(stmt.cols) {
901✔
697
                        return nil, ErrInvalidNumberOfValues
2✔
698
                }
2✔
699

700
                valuesByColID := make(map[uint32]TypedValue)
897✔
701

897✔
702
                var pkMustExist bool
897✔
703

897✔
704
                for colID, col := range table.colsByID {
3,559✔
705
                        colPos, specified := selPosByColID[colID]
2,662✔
706
                        if !specified {
3,188✔
707
                                // TODO: Default values
526✔
708
                                if col.notNull && !col.autoIncrement {
527✔
709
                                        return nil, fmt.Errorf("%w (%s)", ErrNotNullableColumnCannotBeNull, col.colName)
1✔
710
                                }
1✔
711

712
                                // inject auto-incremental pk value
713
                                if stmt.isInsert && col.autoIncrement {
972✔
714
                                        // current implementation assumes only PK can be set as autoincremental
447✔
715
                                        table.maxPK++
447✔
716

447✔
717
                                        pkCol := table.primaryIndex.cols[0]
447✔
718
                                        valuesByColID[pkCol.id] = &Integer{val: table.maxPK}
447✔
719

447✔
720
                                        if _, ok := tx.firstInsertedPKs[table.name]; !ok {
832✔
721
                                                tx.firstInsertedPKs[table.name] = table.maxPK
385✔
722
                                        }
385✔
723
                                        tx.lastInsertedPKs[table.name] = table.maxPK
447✔
724
                                }
725

726
                                continue
525✔
727
                        }
728

729
                        // value was specified
730
                        cVal := row.Values[colPos]
2,136✔
731

2,136✔
732
                        val, err := cVal.substitute(params)
2,136✔
733
                        if err != nil {
2,139✔
734
                                return nil, err
3✔
735
                        }
3✔
736

737
                        rval, err := val.reduce(tx, nil, table.name)
2,133✔
738
                        if err != nil {
2,140✔
739
                                return nil, err
7✔
740
                        }
7✔
741

742
                        if rval.IsNull() {
2,200✔
743
                                if col.notNull || col.autoIncrement {
74✔
744
                                        return nil, fmt.Errorf("%w (%s)", ErrNotNullableColumnCannotBeNull, col.colName)
×
745
                                }
×
746

747
                                continue
74✔
748
                        }
749

750
                        if col.autoIncrement {
2,061✔
751
                                // validate specified value
9✔
752
                                nl, isNumber := rval.RawValue().(int64)
9✔
753
                                if !isNumber {
9✔
754
                                        return nil, fmt.Errorf("%w (expecting numeric value)", ErrInvalidValue)
×
755
                                }
×
756

757
                                pkMustExist = nl <= table.maxPK
9✔
758

9✔
759
                                if _, ok := tx.firstInsertedPKs[table.name]; !ok {
18✔
760
                                        tx.firstInsertedPKs[table.name] = nl
9✔
761
                                }
9✔
762
                                tx.lastInsertedPKs[table.name] = nl
9✔
763
                        }
764

765
                        valuesByColID[colID] = rval
2,052✔
766
                }
767

768
                pkEncVals, err := encodedKey(table.primaryIndex, valuesByColID)
886✔
769
                if err != nil {
891✔
770
                        return nil, err
5✔
771
                }
5✔
772

773
                // pk entry
774
                mappedPKey := MapKey(tx.sqlPrefix(), MappedPrefix, EncodeID(table.id), EncodeID(table.primaryIndex.id), pkEncVals, pkEncVals)
881✔
775

881✔
776
                _, err = tx.get(ctx, mappedPKey)
881✔
777
                if err != nil && !errors.Is(err, store.ErrKeyNotFound) {
881✔
778
                        return nil, err
×
779
                }
×
780

781
                if errors.Is(err, store.ErrKeyNotFound) && pkMustExist {
883✔
782
                        return nil, fmt.Errorf("%w: specified value must be greater than current one", ErrInvalidValue)
2✔
783
                }
2✔
784

785
                if stmt.isInsert {
1,577✔
786
                        if err == nil && stmt.onConflict == nil {
702✔
787
                                return nil, store.ErrKeyAlreadyExists
4✔
788
                        }
4✔
789

790
                        if err == nil && stmt.onConflict != nil {
697✔
791
                                // TODO: conflict resolution may be extended. Currently only supports "ON CONFLICT DO NOTHING"
3✔
792
                                continue
3✔
793
                        }
794
                }
795

796
                err = tx.doUpsert(ctx, pkEncVals, valuesByColID, table, !stmt.isInsert)
872✔
797
                if err != nil {
883✔
798
                        return nil, err
11✔
799
                }
11✔
800
        }
801

802
        return tx, nil
792✔
803
}
804

805
func (tx *SQLTx) encodeRowValue(valuesByColID map[uint32]TypedValue, table *Table) ([]byte, error) {
942✔
806
        valbuf := bytes.Buffer{}
942✔
807

942✔
808
        // null values are not serialized
942✔
809
        encodedVals := 0
942✔
810
        for _, v := range valuesByColID {
3,641✔
811
                if !v.IsNull() {
5,380✔
812
                        encodedVals++
2,681✔
813
                }
2,681✔
814
        }
815

816
        b := make([]byte, EncLenLen)
942✔
817
        binary.BigEndian.PutUint32(b, uint32(encodedVals))
942✔
818

942✔
819
        _, err := valbuf.Write(b)
942✔
820
        if err != nil {
942✔
821
                return nil, err
×
822
        }
×
823

824
        for _, col := range table.cols {
3,769✔
825
                rval, specified := valuesByColID[col.id]
2,827✔
826
                if !specified || rval.IsNull() {
2,979✔
827
                        continue
152✔
828
                }
829

830
                b := make([]byte, EncIDLen)
2,675✔
831
                binary.BigEndian.PutUint32(b, uint32(col.id))
2,675✔
832

2,675✔
833
                _, err = valbuf.Write(b)
2,675✔
834
                if err != nil {
2,675✔
835
                        return nil, fmt.Errorf("%w: table: %s, column: %s", err, table.name, col.colName)
×
836
                }
×
837

838
                encVal, err := EncodeValue(rval, col.colType, col.MaxLen())
2,675✔
839
                if err != nil {
2,681✔
840
                        return nil, fmt.Errorf("%w: table: %s, column: %s", err, table.name, col.colName)
6✔
841
                }
6✔
842

843
                _, err = valbuf.Write(encVal)
2,669✔
844
                if err != nil {
2,669✔
845
                        return nil, fmt.Errorf("%w: table: %s, column: %s", err, table.name, col.colName)
×
846
                }
×
847
        }
848

849
        return valbuf.Bytes(), nil
936✔
850
}
851

852
func (tx *SQLTx) doUpsert(ctx context.Context, pkEncVals []byte, valuesByColID map[uint32]TypedValue, table *Table, reuseIndex bool) error {
884✔
853
        var reusableIndexEntries map[uint32]struct{}
884✔
854

884✔
855
        if reuseIndex && len(table.indexes) > 1 {
941✔
856
                currPKRow, err := tx.fetchPKRow(ctx, table, valuesByColID)
57✔
857
                if err == nil {
94✔
858
                        currValuesByColID := make(map[uint32]TypedValue, len(currPKRow.ValuesBySelector))
37✔
859

37✔
860
                        for _, col := range table.cols {
166✔
861
                                encSel := EncodeSelector("", table.name, col.colName)
129✔
862
                                currValuesByColID[col.id] = currPKRow.ValuesBySelector[encSel]
129✔
863
                        }
129✔
864

865
                        reusableIndexEntries, err = tx.deprecateIndexEntries(pkEncVals, currValuesByColID, valuesByColID, table)
37✔
866
                        if err != nil {
37✔
867
                                return err
×
868
                        }
×
869
                } else if !errors.Is(err, ErrNoMoreRows) {
20✔
870
                        return err
×
871
                }
×
872
        }
873

874
        rowKey := MapKey(tx.sqlPrefix(), RowPrefix, EncodeID(DatabaseID), EncodeID(table.id), EncodeID(PKIndexID), pkEncVals)
884✔
875

884✔
876
        encodedRowValue, err := tx.encodeRowValue(valuesByColID, table)
884✔
877
        if err != nil {
890✔
878
                return err
6✔
879
        }
6✔
880

881
        err = tx.set(rowKey, nil, encodedRowValue)
878✔
882
        if err != nil {
878✔
883
                return err
×
884
        }
×
885

886
        // create in-memory and validate entries for secondary indexes
887
        for _, index := range table.indexes {
2,594✔
888
                if index.IsPrimary() {
2,594✔
889
                        continue
878✔
890
                }
891

892
                if reusableIndexEntries != nil {
918✔
893
                        _, reusable := reusableIndexEntries[index.id]
80✔
894
                        if reusable {
133✔
895
                                continue
53✔
896
                        }
897
                }
898

899
                encodedValues := make([][]byte, 2+len(index.cols))
785✔
900
                encodedValues[0] = EncodeID(table.id)
785✔
901
                encodedValues[1] = EncodeID(index.id)
785✔
902

785✔
903
                indexKeyLen := 0
785✔
904

785✔
905
                for i, col := range index.cols {
1,627✔
906
                        rval, specified := valuesByColID[col.id]
842✔
907
                        if !specified {
881✔
908
                                rval = &NullValue{t: col.colType}
39✔
909
                        }
39✔
910

911
                        encVal, n, err := EncodeValueAsKey(rval, col.colType, col.MaxLen())
842✔
912
                        if err != nil {
842✔
913
                                return fmt.Errorf("%w: index on '%s' and column '%s'", err, index.Name(), col.colName)
×
914
                        }
×
915

916
                        if n > MaxKeyLen {
842✔
917
                                return fmt.Errorf("%w: can not index entry for column '%s'. Max key length for variable columns is %d", ErrLimitedKeyType, col.colName, MaxKeyLen)
×
918
                        }
×
919

920
                        indexKeyLen += n
842✔
921

842✔
922
                        encodedValues[i+2] = encVal
842✔
923
                }
924

925
                if indexKeyLen > MaxKeyLen {
785✔
926
                        return fmt.Errorf("%w: can not index entry using columns '%v'. Max key length is %d", ErrLimitedKeyType, index.cols, MaxKeyLen)
×
927
                }
×
928

929
                smkey := MapKey(tx.sqlPrefix(), MappedPrefix, encodedValues...)
785✔
930

785✔
931
                // no other equivalent entry should be already indexed
785✔
932
                if index.IsUnique() {
862✔
933
                        _, valRef, err := tx.getWithPrefix(ctx, smkey, nil)
77✔
934
                        if err == nil && (valRef.KVMetadata() == nil || !valRef.KVMetadata().Deleted()) {
82✔
935
                                return store.ErrKeyAlreadyExists
5✔
936
                        } else if !errors.Is(err, store.ErrKeyNotFound) {
77✔
937
                                return err
×
938
                        }
×
939
                }
940

941
                err = tx.setTransient(smkey, nil, encodedRowValue) // only-indexable
780✔
942
                if err != nil {
780✔
943
                        return err
×
944
                }
×
945
        }
946

947
        tx.updatedRows++
873✔
948

873✔
949
        return nil
873✔
950
}
951

952
func encodedKey(index *Index, valuesByColID map[uint32]TypedValue) ([]byte, error) {
3,591✔
953
        valbuf := bytes.Buffer{}
3,591✔
954

3,591✔
955
        indexKeyLen := 0
3,591✔
956

3,591✔
957
        for _, col := range index.cols {
7,190✔
958
                rval, specified := valuesByColID[col.id]
3,599✔
959
                if !specified || rval.IsNull() {
3,602✔
960
                        return nil, ErrPKCanNotBeNull
3✔
961
                }
3✔
962

963
                encVal, n, err := EncodeValueAsKey(rval, col.colType, col.MaxLen())
3,596✔
964
                if err != nil {
3,598✔
965
                        return nil, fmt.Errorf("%w: index of table '%s' and column '%s'", err, index.table.name, col.colName)
2✔
966
                }
2✔
967

968
                if n > MaxKeyLen {
3,594✔
969
                        return nil, fmt.Errorf("%w: invalid key entry for column '%s'. Max key length for variable columns is %d", ErrLimitedKeyType, col.colName, MaxKeyLen)
×
970
                }
×
971

972
                indexKeyLen += n
3,594✔
973

3,594✔
974
                _, err = valbuf.Write(encVal)
3,594✔
975
                if err != nil {
3,594✔
976
                        return nil, err
×
977
                }
×
978
        }
979

980
        if indexKeyLen > MaxKeyLen {
3,586✔
981
                return nil, fmt.Errorf("%w: invalid key entry using columns '%v'. Max key length is %d", ErrLimitedKeyType, index.cols, MaxKeyLen)
×
982
        }
×
983

984
        return valbuf.Bytes(), nil
3,586✔
985
}
986

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

57✔
990
        for _, pkCol := range table.primaryIndex.cols {
114✔
991
                pkVal := valuesByColID[pkCol.id]
57✔
992

57✔
993
                pkRanges[pkCol.id] = &typedValueRange{
57✔
994
                        lRange: &typedValueSemiRange{val: pkVal, inclusive: true},
57✔
995
                        hRange: &typedValueSemiRange{val: pkVal, inclusive: true},
57✔
996
                }
57✔
997
        }
57✔
998

999
        scanSpecs := &ScanSpecs{
57✔
1000
                Index:         table.primaryIndex,
57✔
1001
                rangesByColID: pkRanges,
57✔
1002
        }
57✔
1003

57✔
1004
        r, err := newRawRowReader(tx, nil, table, period{}, table.name, scanSpecs)
57✔
1005
        if err != nil {
57✔
1006
                return nil, err
×
1007
        }
×
1008

1009
        defer func() {
114✔
1010
                r.Close()
57✔
1011
        }()
57✔
1012

1013
        return r.Read(ctx)
57✔
1014
}
1015

1016
// deprecateIndexEntries mark previous index entries as deleted
1017
func (tx *SQLTx) deprecateIndexEntries(
1018
        pkEncVals []byte,
1019
        currValuesByColID, newValuesByColID map[uint32]TypedValue,
1020
        table *Table) (reusableIndexEntries map[uint32]struct{}, err error) {
37✔
1021

37✔
1022
        encodedRowValue, err := tx.encodeRowValue(currValuesByColID, table)
37✔
1023
        if err != nil {
37✔
1024
                return nil, err
×
1025
        }
×
1026

1027
        reusableIndexEntries = make(map[uint32]struct{})
37✔
1028

37✔
1029
        for _, index := range table.indexes {
154✔
1030
                if index.IsPrimary() {
154✔
1031
                        continue
37✔
1032
                }
1033

1034
                encodedValues := make([][]byte, 2+len(index.cols)+1)
80✔
1035
                encodedValues[0] = EncodeID(table.id)
80✔
1036
                encodedValues[1] = EncodeID(index.id)
80✔
1037
                encodedValues[len(encodedValues)-1] = pkEncVals
80✔
1038

80✔
1039
                // existent index entry is deleted only if it differs from existent one
80✔
1040
                sameIndexKey := true
80✔
1041

80✔
1042
                for i, col := range index.cols {
165✔
1043
                        currVal, specified := currValuesByColID[col.id]
85✔
1044
                        if !specified {
85✔
1045
                                currVal = &NullValue{t: col.colType}
×
1046
                        }
×
1047

1048
                        newVal, specified := newValuesByColID[col.id]
85✔
1049
                        if !specified {
89✔
1050
                                newVal = &NullValue{t: col.colType}
4✔
1051
                        }
4✔
1052

1053
                        r, err := currVal.Compare(newVal)
85✔
1054
                        if err != nil {
85✔
1055
                                return nil, err
×
1056
                        }
×
1057

1058
                        sameIndexKey = sameIndexKey && r == 0
85✔
1059

85✔
1060
                        encVal, _, _ := EncodeValueAsKey(currVal, col.colType, col.MaxLen())
85✔
1061

85✔
1062
                        encodedValues[i+3] = encVal
85✔
1063
                }
1064

1065
                // mark existent index entry as deleted
1066
                if sameIndexKey {
133✔
1067
                        reusableIndexEntries[index.id] = struct{}{}
53✔
1068
                } else {
80✔
1069
                        md := store.NewKVMetadata()
27✔
1070

27✔
1071
                        md.AsDeleted(true)
27✔
1072

27✔
1073
                        err = tx.set(MapKey(tx.sqlPrefix(), MappedPrefix, encodedValues...), md, encodedRowValue)
27✔
1074
                        if err != nil {
27✔
1075
                                return nil, err
×
1076
                        }
×
1077
                }
1078
        }
1079

1080
        return reusableIndexEntries, nil
37✔
1081
}
1082

1083
type UpdateStmt struct {
1084
        tableRef *tableRef
1085
        where    ValueExp
1086
        updates  []*colUpdate
1087
        indexOn  []string
1088
        limit    ValueExp
1089
        offset   ValueExp
1090
}
1091

1092
type colUpdate struct {
1093
        col string
1094
        op  CmpOperator
1095
        val ValueExp
1096
}
1097

1098
func (stmt *UpdateStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
1099
        selectStmt := &SelectStmt{
1✔
1100
                ds:    stmt.tableRef,
1✔
1101
                where: stmt.where,
1✔
1102
        }
1✔
1103

1✔
1104
        err := selectStmt.inferParameters(ctx, tx, params)
1✔
1105
        if err != nil {
1✔
1106
                return err
×
1107
        }
×
1108

1109
        table, err := stmt.tableRef.referencedTable(tx)
1✔
1110
        if err != nil {
1✔
1111
                return err
×
1112
        }
×
1113

1114
        for _, update := range stmt.updates {
2✔
1115
                col, err := table.GetColumnByName(update.col)
1✔
1116
                if err != nil {
1✔
1117
                        return err
×
1118
                }
×
1119

1120
                err = update.val.requiresType(col.colType, make(map[string]ColDescriptor), params, table.name)
1✔
1121
                if err != nil {
1✔
1122
                        return err
×
1123
                }
×
1124
        }
1125

1126
        return nil
1✔
1127
}
1128

1129
func (stmt *UpdateStmt) validate(table *Table) error {
16✔
1130
        colIDs := make(map[uint32]struct{}, len(stmt.updates))
16✔
1131

16✔
1132
        for _, update := range stmt.updates {
32✔
1133
                if update.op != EQ {
16✔
1134
                        return ErrIllegalArguments
×
1135
                }
×
1136

1137
                col, err := table.GetColumnByName(update.col)
16✔
1138
                if err != nil {
17✔
1139
                        return err
1✔
1140
                }
1✔
1141

1142
                if table.PrimaryIndex().IncludesCol(col.id) {
15✔
1143
                        return ErrPKCanNotBeUpdated
×
1144
                }
×
1145

1146
                _, duplicated := colIDs[col.id]
15✔
1147
                if duplicated {
15✔
1148
                        return ErrDuplicatedColumn
×
1149
                }
×
1150

1151
                colIDs[col.id] = struct{}{}
15✔
1152
        }
1153

1154
        return nil
15✔
1155
}
1156

1157
func (stmt *UpdateStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
17✔
1158
        selectStmt := &SelectStmt{
17✔
1159
                ds:      stmt.tableRef,
17✔
1160
                where:   stmt.where,
17✔
1161
                indexOn: stmt.indexOn,
17✔
1162
                limit:   stmt.limit,
17✔
1163
                offset:  stmt.offset,
17✔
1164
        }
17✔
1165

17✔
1166
        rowReader, err := selectStmt.Resolve(ctx, tx, params, nil)
17✔
1167
        if err != nil {
18✔
1168
                return nil, err
1✔
1169
        }
1✔
1170
        defer rowReader.Close()
16✔
1171

16✔
1172
        table := rowReader.ScanSpecs().Index.table
16✔
1173

16✔
1174
        err = stmt.validate(table)
16✔
1175
        if err != nil {
17✔
1176
                return nil, err
1✔
1177
        }
1✔
1178

1179
        cols, err := rowReader.colsBySelector(ctx)
15✔
1180
        if err != nil {
15✔
1181
                return nil, err
×
1182
        }
×
1183

1184
        for {
42✔
1185
                row, err := rowReader.Read(ctx)
27✔
1186
                if errors.Is(err, ErrNoMoreRows) {
41✔
1187
                        break
14✔
1188
                } else if err != nil {
14✔
1189
                        return nil, err
1✔
1190
                }
1✔
1191

1192
                valuesByColID := make(map[uint32]TypedValue, len(row.ValuesBySelector))
12✔
1193

12✔
1194
                for _, col := range table.cols {
45✔
1195
                        encSel := EncodeSelector("", table.name, col.colName)
33✔
1196
                        valuesByColID[col.id] = row.ValuesBySelector[encSel]
33✔
1197
                }
33✔
1198

1199
                for _, update := range stmt.updates {
24✔
1200
                        col, err := table.GetColumnByName(update.col)
12✔
1201
                        if err != nil {
12✔
1202
                                return nil, err
×
1203
                        }
×
1204

1205
                        sval, err := update.val.substitute(params)
12✔
1206
                        if err != nil {
12✔
1207
                                return nil, err
×
1208
                        }
×
1209

1210
                        rval, err := sval.reduce(tx, row, table.name)
12✔
1211
                        if err != nil {
12✔
1212
                                return nil, err
×
1213
                        }
×
1214

1215
                        err = rval.requiresType(col.colType, cols, nil, table.name)
12✔
1216
                        if err != nil {
12✔
1217
                                return nil, err
×
1218
                        }
×
1219

1220
                        valuesByColID[col.id] = rval
12✔
1221
                }
1222

1223
                pkEncVals, err := encodedKey(table.primaryIndex, valuesByColID)
12✔
1224
                if err != nil {
12✔
1225
                        return nil, err
×
1226
                }
×
1227

1228
                // primary index entry
1229
                mkey := MapKey(tx.sqlPrefix(), MappedPrefix, EncodeID(table.id), EncodeID(table.primaryIndex.id), pkEncVals, pkEncVals)
12✔
1230

12✔
1231
                // mkey must exist
12✔
1232
                _, err = tx.get(ctx, mkey)
12✔
1233
                if err != nil {
12✔
1234
                        return nil, err
×
1235
                }
×
1236

1237
                err = tx.doUpsert(ctx, pkEncVals, valuesByColID, table, true)
12✔
1238
                if err != nil {
12✔
1239
                        return nil, err
×
1240
                }
×
1241
        }
1242

1243
        return tx, nil
14✔
1244
}
1245

1246
type DeleteFromStmt struct {
1247
        tableRef *tableRef
1248
        where    ValueExp
1249
        indexOn  []string
1250
        orderBy  []*OrdCol
1251
        limit    ValueExp
1252
        offset   ValueExp
1253
}
1254

1255
func NewDeleteFromStmt(table string, where ValueExp, orderBy []*OrdCol, limit ValueExp) *DeleteFromStmt {
4✔
1256
        return &DeleteFromStmt{
4✔
1257
                tableRef: NewTableRef(table, ""),
4✔
1258
                where:    where,
4✔
1259
                orderBy:  orderBy,
4✔
1260
                limit:    limit,
4✔
1261
        }
4✔
1262
}
4✔
1263

1264
func (stmt *DeleteFromStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
1265
        selectStmt := &SelectStmt{
1✔
1266
                ds:      stmt.tableRef,
1✔
1267
                where:   stmt.where,
1✔
1268
                orderBy: stmt.orderBy,
1✔
1269
        }
1✔
1270
        return selectStmt.inferParameters(ctx, tx, params)
1✔
1271
}
1✔
1272

1273
func (stmt *DeleteFromStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
14✔
1274
        selectStmt := &SelectStmt{
14✔
1275
                ds:      stmt.tableRef,
14✔
1276
                where:   stmt.where,
14✔
1277
                indexOn: stmt.indexOn,
14✔
1278
                orderBy: stmt.orderBy,
14✔
1279
                limit:   stmt.limit,
14✔
1280
                offset:  stmt.offset,
14✔
1281
        }
14✔
1282

14✔
1283
        rowReader, err := selectStmt.Resolve(ctx, tx, params, nil)
14✔
1284
        if err != nil {
16✔
1285
                return nil, err
2✔
1286
        }
2✔
1287
        defer rowReader.Close()
12✔
1288

12✔
1289
        table := rowReader.ScanSpecs().Index.table
12✔
1290

12✔
1291
        for {
45✔
1292
                row, err := rowReader.Read(ctx)
33✔
1293
                if errors.Is(err, ErrNoMoreRows) {
44✔
1294
                        break
11✔
1295
                }
1296
                if err != nil {
23✔
1297
                        return nil, err
1✔
1298
                }
1✔
1299

1300
                valuesByColID := make(map[uint32]TypedValue, len(row.ValuesBySelector))
21✔
1301

21✔
1302
                for _, col := range table.cols {
106✔
1303
                        encSel := EncodeSelector("", table.name, col.colName)
85✔
1304
                        valuesByColID[col.id] = row.ValuesBySelector[encSel]
85✔
1305
                }
85✔
1306

1307
                pkEncVals, err := encodedKey(table.primaryIndex, valuesByColID)
21✔
1308
                if err != nil {
21✔
1309
                        return nil, err
×
1310
                }
×
1311

1312
                err = tx.deleteIndexEntries(pkEncVals, valuesByColID, table)
21✔
1313
                if err != nil {
21✔
1314
                        return nil, err
×
1315
                }
×
1316

1317
                tx.updatedRows++
21✔
1318
        }
1319

1320
        return tx, nil
11✔
1321
}
1322

1323
func (tx *SQLTx) deleteIndexEntries(pkEncVals []byte, valuesByColID map[uint32]TypedValue, table *Table) error {
21✔
1324
        encodedRowValue, err := tx.encodeRowValue(valuesByColID, table)
21✔
1325
        if err != nil {
21✔
1326
                return err
×
1327
        }
×
1328

1329
        for _, index := range table.indexes {
91✔
1330
                if !index.IsPrimary() {
119✔
1331
                        continue
49✔
1332
                }
1333

1334
                encodedValues := make([][]byte, 3+len(index.cols))
21✔
1335
                encodedValues[0] = EncodeID(DatabaseID)
21✔
1336
                encodedValues[1] = EncodeID(table.id)
21✔
1337
                encodedValues[2] = EncodeID(index.id)
21✔
1338

21✔
1339
                for i, col := range index.cols {
42✔
1340
                        val, specified := valuesByColID[col.id]
21✔
1341
                        if !specified {
21✔
1342
                                val = &NullValue{t: col.colType}
×
1343
                        }
×
1344

1345
                        encVal, _, _ := EncodeValueAsKey(val, col.colType, col.MaxLen())
21✔
1346

21✔
1347
                        encodedValues[i+3] = encVal
21✔
1348
                }
1349

1350
                md := store.NewKVMetadata()
21✔
1351

21✔
1352
                md.AsDeleted(true)
21✔
1353

21✔
1354
                err := tx.set(MapKey(tx.sqlPrefix(), RowPrefix, encodedValues...), md, encodedRowValue)
21✔
1355
                if err != nil {
21✔
1356
                        return err
×
1357
                }
×
1358
        }
1359

1360
        return nil
21✔
1361
}
1362

1363
type ValueExp interface {
1364
        inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error)
1365
        requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error
1366
        substitute(params map[string]interface{}) (ValueExp, error)
1367
        reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error)
1368
        reduceSelectors(row *Row, implicitTable string) ValueExp
1369
        isConstant() bool
1370
        selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error
1371
}
1372

1373
type typedValueRange struct {
1374
        lRange *typedValueSemiRange
1375
        hRange *typedValueSemiRange
1376
}
1377

1378
type typedValueSemiRange struct {
1379
        val       TypedValue
1380
        inclusive bool
1381
}
1382

1383
func (r *typedValueRange) unitary() bool {
7✔
1384
        // TODO: this simplified implementation doesn't cover all unitary cases e.g. 3<=v<4
7✔
1385
        if r.lRange == nil || r.hRange == nil {
7✔
1386
                return false
×
1387
        }
×
1388

1389
        res, _ := r.lRange.val.Compare(r.hRange.val)
7✔
1390
        return res == 0 && r.lRange.inclusive && r.hRange.inclusive
7✔
1391
}
1392

1393
func (r *typedValueRange) refineWith(refiningRange *typedValueRange) error {
3✔
1394
        if r.lRange == nil {
4✔
1395
                r.lRange = refiningRange.lRange
1✔
1396
        } else if r.lRange != nil && refiningRange.lRange != nil {
4✔
1397
                maxRange, err := maxSemiRange(r.lRange, refiningRange.lRange)
1✔
1398
                if err != nil {
1✔
1399
                        return err
×
1400
                }
×
1401
                r.lRange = maxRange
1✔
1402
        }
1403

1404
        if r.hRange == nil {
4✔
1405
                r.hRange = refiningRange.hRange
1✔
1406
        } else if r.hRange != nil && refiningRange.hRange != nil {
5✔
1407
                minRange, err := minSemiRange(r.hRange, refiningRange.hRange)
2✔
1408
                if err != nil {
2✔
1409
                        return err
×
1410
                }
×
1411
                r.hRange = minRange
2✔
1412
        }
1413

1414
        return nil
3✔
1415
}
1416

1417
func (r *typedValueRange) extendWith(extendingRange *typedValueRange) error {
5✔
1418
        if r.lRange == nil || extendingRange.lRange == nil {
7✔
1419
                r.lRange = nil
2✔
1420
        } else {
5✔
1421
                minRange, err := minSemiRange(r.lRange, extendingRange.lRange)
3✔
1422
                if err != nil {
3✔
1423
                        return err
×
1424
                }
×
1425
                r.lRange = minRange
3✔
1426
        }
1427

1428
        if r.hRange == nil || extendingRange.hRange == nil {
8✔
1429
                r.hRange = nil
3✔
1430
        } else {
5✔
1431
                maxRange, err := maxSemiRange(r.hRange, extendingRange.hRange)
2✔
1432
                if err != nil {
2✔
1433
                        return err
×
1434
                }
×
1435
                r.hRange = maxRange
2✔
1436
        }
1437

1438
        return nil
5✔
1439
}
1440

1441
func maxSemiRange(or1, or2 *typedValueSemiRange) (*typedValueSemiRange, error) {
3✔
1442
        r, err := or1.val.Compare(or2.val)
3✔
1443
        if err != nil {
3✔
1444
                return nil, err
×
1445
        }
×
1446

1447
        maxVal := or1.val
3✔
1448
        if r < 0 {
5✔
1449
                maxVal = or2.val
2✔
1450
        }
2✔
1451

1452
        return &typedValueSemiRange{
3✔
1453
                val:       maxVal,
3✔
1454
                inclusive: or1.inclusive && or2.inclusive,
3✔
1455
        }, nil
3✔
1456
}
1457

1458
func minSemiRange(or1, or2 *typedValueSemiRange) (*typedValueSemiRange, error) {
5✔
1459
        r, err := or1.val.Compare(or2.val)
5✔
1460
        if err != nil {
5✔
1461
                return nil, err
×
1462
        }
×
1463

1464
        minVal := or1.val
5✔
1465
        if r > 0 {
9✔
1466
                minVal = or2.val
4✔
1467
        }
4✔
1468

1469
        return &typedValueSemiRange{
5✔
1470
                val:       minVal,
5✔
1471
                inclusive: or1.inclusive || or2.inclusive,
5✔
1472
        }, nil
5✔
1473
}
1474

1475
type TypedValue interface {
1476
        ValueExp
1477
        Type() SQLValueType
1478
        RawValue() interface{}
1479
        Compare(val TypedValue) (int, error)
1480
        IsNull() bool
1481
}
1482

1483
func NewNull(t SQLValueType) *NullValue {
15✔
1484
        return &NullValue{t: t}
15✔
1485
}
15✔
1486

1487
type NullValue struct {
1488
        t SQLValueType
1489
}
1490

1491
func (n *NullValue) Type() SQLValueType {
36✔
1492
        return n.t
36✔
1493
}
36✔
1494

1495
func (n *NullValue) RawValue() interface{} {
131✔
1496
        return nil
131✔
1497
}
131✔
1498

1499
func (n *NullValue) IsNull() bool {
329✔
1500
        return true
329✔
1501
}
329✔
1502

1503
func (n *NullValue) Compare(val TypedValue) (int, error) {
49✔
1504
        if n.t != AnyType && val.Type() != AnyType && n.t != val.Type() {
49✔
1505
                return 0, ErrNotComparableValues
×
1506
        }
×
1507

1508
        if val.RawValue() == nil {
71✔
1509
                return 0, nil
22✔
1510
        }
22✔
1511

1512
        return -1, nil
27✔
1513
}
1514

1515
func (v *NullValue) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
5✔
1516
        return v.t, nil
5✔
1517
}
5✔
1518

1519
func (v *NullValue) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
8✔
1520
        if v.t == t {
13✔
1521
                return nil
5✔
1522
        }
5✔
1523

1524
        if v.t != AnyType {
4✔
1525
                return ErrInvalidTypes
1✔
1526
        }
1✔
1527

1528
        v.t = t
2✔
1529

2✔
1530
        return nil
2✔
1531
}
1532

1533
func (v *NullValue) substitute(params map[string]interface{}) (ValueExp, error) {
259✔
1534
        return v, nil
259✔
1535
}
259✔
1536

1537
func (v *NullValue) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
285✔
1538
        return v, nil
285✔
1539
}
285✔
1540

1541
func (v *NullValue) reduceSelectors(row *Row, implicitTable string) ValueExp {
10✔
1542
        return v
10✔
1543
}
10✔
1544

1545
func (v *NullValue) isConstant() bool {
12✔
1546
        return true
12✔
1547
}
12✔
1548

1549
func (v *NullValue) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1550
        return nil
1✔
1551
}
1✔
1552

1553
type Integer struct {
1554
        val int64
1555
}
1556

1557
func NewInteger(val int64) *Integer {
290✔
1558
        return &Integer{val: val}
290✔
1559
}
290✔
1560

1561
func (v *Integer) Type() SQLValueType {
2,647✔
1562
        return IntegerType
2,647✔
1563
}
2,647✔
1564

1565
func (v *Integer) IsNull() bool {
7,040✔
1566
        return false
7,040✔
1567
}
7,040✔
1568

1569
func (v *Integer) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
18✔
1570
        return IntegerType, nil
18✔
1571
}
18✔
1572

1573
func (v *Integer) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
22✔
1574
        if t != IntegerType {
26✔
1575
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
4✔
1576
        }
4✔
1577

1578
        return nil
18✔
1579
}
1580

1581
func (v *Integer) substitute(params map[string]interface{}) (ValueExp, error) {
1,897✔
1582
        return v, nil
1,897✔
1583
}
1,897✔
1584

1585
func (v *Integer) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
2,151✔
1586
        return v, nil
2,151✔
1587
}
2,151✔
1588

1589
func (v *Integer) reduceSelectors(row *Row, implicitTable string) ValueExp {
6✔
1590
        return v
6✔
1591
}
6✔
1592

1593
func (v *Integer) isConstant() bool {
100✔
1594
        return true
100✔
1595
}
100✔
1596

1597
func (v *Integer) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1598
        return nil
1✔
1599
}
1✔
1600

1601
func (v *Integer) RawValue() interface{} {
8,007✔
1602
        return v.val
8,007✔
1603
}
8,007✔
1604

1605
func (v *Integer) Compare(val TypedValue) (int, error) {
1,144✔
1606
        if val.IsNull() {
1,187✔
1607
                return 1, nil
43✔
1608
        }
43✔
1609

1610
        if val.Type() == Float64Type {
1,101✔
1611
                r, err := val.Compare(v)
×
1612
                return r * -1, err
×
1613
        }
×
1614

1615
        if val.Type() != IntegerType {
1,108✔
1616
                return 0, ErrNotComparableValues
7✔
1617
        }
7✔
1618

1619
        rval := val.RawValue().(int64)
1,094✔
1620

1,094✔
1621
        if v.val == rval {
1,311✔
1622
                return 0, nil
217✔
1623
        }
217✔
1624

1625
        if v.val > rval {
1,410✔
1626
                return 1, nil
533✔
1627
        }
533✔
1628

1629
        return -1, nil
344✔
1630
}
1631

1632
type Timestamp struct {
1633
        val time.Time
1634
}
1635

1636
func (v *Timestamp) Type() SQLValueType {
114✔
1637
        return TimestampType
114✔
1638
}
114✔
1639

1640
func (v *Timestamp) IsNull() bool {
548✔
1641
        return false
548✔
1642
}
548✔
1643

1644
func (v *Timestamp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
1645
        return TimestampType, nil
1✔
1646
}
1✔
1647

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

1653
        return nil
1✔
1654
}
1655

1656
func (v *Timestamp) substitute(params map[string]interface{}) (ValueExp, error) {
60✔
1657
        return v, nil
60✔
1658
}
60✔
1659

1660
func (v *Timestamp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
170✔
1661
        return v, nil
170✔
1662
}
170✔
1663

1664
func (v *Timestamp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
1665
        return v
1✔
1666
}
1✔
1667

1668
func (v *Timestamp) isConstant() bool {
1✔
1669
        return true
1✔
1670
}
1✔
1671

1672
func (v *Timestamp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1673
        return nil
1✔
1674
}
1✔
1675

1676
func (v *Timestamp) RawValue() interface{} {
547✔
1677
        return v.val
547✔
1678
}
547✔
1679

1680
func (v *Timestamp) Compare(val TypedValue) (int, error) {
71✔
1681
        if val.IsNull() {
73✔
1682
                return 1, nil
2✔
1683
        }
2✔
1684

1685
        if val.Type() != TimestampType {
70✔
1686
                return 0, ErrNotComparableValues
1✔
1687
        }
1✔
1688

1689
        rval := val.RawValue().(time.Time)
68✔
1690

68✔
1691
        if v.val.Before(rval) {
101✔
1692
                return -1, nil
33✔
1693
        }
33✔
1694

1695
        if v.val.After(rval) {
38✔
1696
                return 1, nil
3✔
1697
        }
3✔
1698

1699
        return 0, nil
32✔
1700
}
1701

1702
type Varchar struct {
1703
        val string
1704
}
1705

1706
func NewVarchar(val string) *Varchar {
138✔
1707
        return &Varchar{val: val}
138✔
1708
}
138✔
1709

1710
func (v *Varchar) Type() SQLValueType {
478✔
1711
        return VarcharType
478✔
1712
}
478✔
1713

1714
func (v *Varchar) IsNull() bool {
1,841✔
1715
        return false
1,841✔
1716
}
1,841✔
1717

1718
func (v *Varchar) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
15✔
1719
        return VarcharType, nil
15✔
1720
}
15✔
1721

1722
func (v *Varchar) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
53✔
1723
        if t != VarcharType {
55✔
1724
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
2✔
1725
        }
2✔
1726

1727
        return nil
51✔
1728
}
1729

1730
func (v *Varchar) substitute(params map[string]interface{}) (ValueExp, error) {
839✔
1731
        return v, nil
839✔
1732
}
839✔
1733

1734
func (v *Varchar) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
950✔
1735
        return v, nil
950✔
1736
}
950✔
1737

1738
func (v *Varchar) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
1739
        return v
×
1740
}
×
1741

1742
func (v *Varchar) isConstant() bool {
36✔
1743
        return true
36✔
1744
}
36✔
1745

1746
func (v *Varchar) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1747
        return nil
1✔
1748
}
1✔
1749

1750
func (v *Varchar) RawValue() interface{} {
1,881✔
1751
        return v.val
1,881✔
1752
}
1,881✔
1753

1754
func (v *Varchar) Compare(val TypedValue) (int, error) {
372✔
1755
        if val.IsNull() {
473✔
1756
                return 1, nil
101✔
1757
        }
101✔
1758

1759
        if val.Type() != VarcharType {
272✔
1760
                return 0, ErrNotComparableValues
1✔
1761
        }
1✔
1762

1763
        rval := val.RawValue().(string)
270✔
1764

270✔
1765
        return bytes.Compare([]byte(v.val), []byte(rval)), nil
270✔
1766
}
1767

1768
type UUID struct {
1769
        val uuid.UUID
1770
}
1771

1772
func NewUUID(val uuid.UUID) *UUID {
1✔
1773
        return &UUID{val: val}
1✔
1774
}
1✔
1775

1776
func (v *UUID) Type() SQLValueType {
5✔
1777
        return UUIDType
5✔
1778
}
5✔
1779

1780
func (v *UUID) IsNull() bool {
20✔
1781
        return false
20✔
1782
}
20✔
1783

1784
func (v *UUID) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
1785
        return UUIDType, nil
1✔
1786
}
1✔
1787

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

1793
        return nil
2✔
1794
}
1795

1796
func (v *UUID) substitute(params map[string]interface{}) (ValueExp, error) {
2✔
1797
        return v, nil
2✔
1798
}
2✔
1799

1800
func (v *UUID) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1✔
1801
        return v, nil
1✔
1802
}
1✔
1803

1804
func (v *UUID) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
1805
        return v
1✔
1806
}
1✔
1807

1808
func (v *UUID) isConstant() bool {
1✔
1809
        return true
1✔
1810
}
1✔
1811

1812
func (v *UUID) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
1813
        return nil
1✔
1814
}
1✔
1815

1816
func (v *UUID) RawValue() interface{} {
13✔
1817
        return v.val
13✔
1818
}
13✔
1819

1820
func (v *UUID) Compare(val TypedValue) (int, error) {
5✔
1821
        if val.IsNull() {
7✔
1822
                return 1, nil
2✔
1823
        }
2✔
1824

1825
        if val.Type() != UUIDType {
4✔
1826
                return 0, ErrNotComparableValues
1✔
1827
        }
1✔
1828

1829
        rval := val.RawValue().(uuid.UUID)
2✔
1830

2✔
1831
        return bytes.Compare(v.val[:], rval[:]), nil
2✔
1832
}
1833

1834
type Bool struct {
1835
        val bool
1836
}
1837

1838
func NewBool(val bool) *Bool {
2✔
1839
        return &Bool{val: val}
2✔
1840
}
2✔
1841

1842
func (v *Bool) Type() SQLValueType {
152✔
1843
        return BooleanType
152✔
1844
}
152✔
1845

1846
func (v *Bool) IsNull() bool {
637✔
1847
        return false
637✔
1848
}
637✔
1849

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

1854
func (v *Bool) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
48✔
1855
        if t != BooleanType {
53✔
1856
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
5✔
1857
        }
5✔
1858

1859
        return nil
43✔
1860
}
1861

1862
func (v *Bool) substitute(params map[string]interface{}) (ValueExp, error) {
285✔
1863
        return v, nil
285✔
1864
}
285✔
1865

1866
func (v *Bool) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
324✔
1867
        return v, nil
324✔
1868
}
324✔
1869

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

1874
func (v *Bool) isConstant() bool {
3✔
1875
        return true
3✔
1876
}
3✔
1877

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

1882
func (v *Bool) RawValue() interface{} {
622✔
1883
        return v.val
622✔
1884
}
622✔
1885

1886
func (v *Bool) Compare(val TypedValue) (int, error) {
97✔
1887
        if val.IsNull() {
119✔
1888
                return 1, nil
22✔
1889
        }
22✔
1890

1891
        if val.Type() != BooleanType {
76✔
1892
                return 0, ErrNotComparableValues
1✔
1893
        }
1✔
1894

1895
        rval := val.RawValue().(bool)
74✔
1896

74✔
1897
        if v.val == rval {
127✔
1898
                return 0, nil
53✔
1899
        }
53✔
1900

1901
        if v.val {
27✔
1902
                return 1, nil
6✔
1903
        }
6✔
1904

1905
        return -1, nil
15✔
1906
}
1907

1908
type Blob struct {
1909
        val []byte
1910
}
1911

1912
func NewBlob(val []byte) *Blob {
286✔
1913
        return &Blob{val: val}
286✔
1914
}
286✔
1915

1916
func (v *Blob) Type() SQLValueType {
58✔
1917
        return BLOBType
58✔
1918
}
58✔
1919

1920
func (v *Blob) IsNull() bool {
2,160✔
1921
        return false
2,160✔
1922
}
2,160✔
1923

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

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

1933
        return nil
1✔
1934
}
1935

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

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

1944
func (v *Blob) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
1945
        return v
×
1946
}
×
1947

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

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

1956
func (v *Blob) RawValue() interface{} {
2,277✔
1957
        return v.val
2,277✔
1958
}
2,277✔
1959

1960
func (v *Blob) Compare(val TypedValue) (int, error) {
39✔
1961
        if val.IsNull() {
50✔
1962
                return 1, nil
11✔
1963
        }
11✔
1964

1965
        if val.Type() != BLOBType {
28✔
1966
                return 0, ErrNotComparableValues
×
1967
        }
×
1968

1969
        rval := val.RawValue().([]byte)
28✔
1970

28✔
1971
        return bytes.Compare(v.val, rval), nil
28✔
1972
}
1973

1974
type Float64 struct {
1975
        val float64
1976
}
1977

1978
func NewFloat64(val float64) *Float64 {
34✔
1979
        return &Float64{val: val}
34✔
1980
}
34✔
1981

1982
func (v *Float64) Type() SQLValueType {
81✔
1983
        return Float64Type
81✔
1984
}
81✔
1985

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

1990
func (v *Float64) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
1991
        return Float64Type, nil
1✔
1992
}
1✔
1993

1994
func (v *Float64) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
1995
        if t != Float64Type {
3✔
1996
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, Float64Type, t)
1✔
1997
        }
1✔
1998

1999
        return nil
1✔
2000
}
2001

2002
func (v *Float64) substitute(params map[string]interface{}) (ValueExp, error) {
76✔
2003
        return v, nil
76✔
2004
}
76✔
2005

2006
func (v *Float64) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
200✔
2007
        return v, nil
200✔
2008
}
200✔
2009

2010
func (v *Float64) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
2011
        return v
1✔
2012
}
1✔
2013

2014
func (v *Float64) isConstant() bool {
5✔
2015
        return true
5✔
2016
}
5✔
2017

2018
func (v *Float64) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
2019
        return nil
1✔
2020
}
1✔
2021

2022
func (v *Float64) RawValue() interface{} {
759✔
2023
        return v.val
759✔
2024
}
759✔
2025

2026
func (v *Float64) Compare(val TypedValue) (int, error) {
40✔
2027
        convVal, err := mayApplyImplicitConversion(val.RawValue(), Float64Type)
40✔
2028
        if err != nil {
41✔
2029
                return 0, err
1✔
2030
        }
1✔
2031

2032
        if convVal == nil {
42✔
2033
                return 1, nil
3✔
2034
        }
3✔
2035

2036
        rval, ok := convVal.(float64)
36✔
2037
        if !ok {
36✔
2038
                return 0, ErrNotComparableValues
×
2039
        }
×
2040

2041
        if v.val == rval {
44✔
2042
                return 0, nil
8✔
2043
        }
8✔
2044

2045
        if v.val > rval {
40✔
2046
                return 1, nil
12✔
2047
        }
12✔
2048

2049
        return -1, nil
16✔
2050
}
2051

2052
type FnCall struct {
2053
        fn     string
2054
        params []ValueExp
2055
}
2056

2057
func (v *FnCall) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
15✔
2058
        if strings.ToUpper(v.fn) == NowFnCall {
29✔
2059
                return TimestampType, nil
14✔
2060
        }
14✔
2061

2062
        if strings.ToUpper(v.fn) == UUIDFnCall {
1✔
2063
                return UUIDType, nil
×
2064
        }
×
2065

2066
        return AnyType, fmt.Errorf("%w: unknown function %s", ErrIllegalArguments, v.fn)
1✔
2067
}
2068

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

2075
                return nil
1✔
2076
        }
2077

2078
        if strings.ToUpper(v.fn) == UUIDFnCall {
2✔
2079
                if t != UUIDType {
×
2080
                        return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, UUIDType, t)
×
2081
                }
×
2082

2083
                return nil
×
2084
        }
2085

2086
        return fmt.Errorf("%w: unkown function %s", ErrIllegalArguments, v.fn)
2✔
2087
}
2088

2089
func (v *FnCall) substitute(params map[string]interface{}) (val ValueExp, err error) {
69✔
2090
        ps := make([]ValueExp, len(v.params))
69✔
2091

69✔
2092
        for i, p := range v.params {
69✔
2093
                ps[i], err = p.substitute(params)
×
2094
                if err != nil {
×
2095
                        return nil, err
×
2096
                }
×
2097
        }
2098

2099
        return &FnCall{
69✔
2100
                fn:     v.fn,
69✔
2101
                params: ps,
69✔
2102
        }, nil
69✔
2103
}
2104

2105
func (v *FnCall) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
69✔
2106
        if strings.ToUpper(v.fn) == NowFnCall {
134✔
2107
                if len(v.params) > 0 {
65✔
2108
                        return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, NowFnCall, len(v.params))
×
2109
                }
×
2110
                return &Timestamp{val: tx.Timestamp().Truncate(time.Microsecond).UTC()}, nil
65✔
2111
        }
2112

2113
        if strings.ToUpper(v.fn) == UUIDFnCall {
7✔
2114
                if len(v.params) > 0 {
3✔
2115
                        return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, UUIDFnCall, len(v.params))
×
2116
                }
×
2117
                return &UUID{val: uuid.New()}, nil
3✔
2118
        }
2119

2120
        return nil, fmt.Errorf("%w: unkown function %s", ErrIllegalArguments, v.fn)
1✔
2121
}
2122

2123
func (v *FnCall) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2124
        return v
×
2125
}
×
2126

2127
func (v *FnCall) isConstant() bool {
11✔
2128
        return false
11✔
2129
}
11✔
2130

2131
func (v *FnCall) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
×
2132
        return nil
×
2133
}
×
2134

2135
type Cast struct {
2136
        val ValueExp
2137
        t   SQLValueType
2138
}
2139

2140
func (c *Cast) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
11✔
2141
        _, err := c.val.inferType(cols, params, implicitTable)
11✔
2142
        if err != nil {
12✔
2143
                return AnyType, err
1✔
2144
        }
1✔
2145

2146
        // val type may be restricted by compatible conversions, but multiple types may be compatible...
2147

2148
        return c.t, nil
10✔
2149
}
2150

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

2156
        return nil
×
2157
}
2158

2159
func (c *Cast) substitute(params map[string]interface{}) (ValueExp, error) {
48✔
2160
        val, err := c.val.substitute(params)
48✔
2161
        if err != nil {
48✔
2162
                return nil, err
×
2163
        }
×
2164
        c.val = val
48✔
2165
        return c, nil
48✔
2166
}
2167

2168
func (c *Cast) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
48✔
2169
        val, err := c.val.reduce(tx, row, implicitTable)
48✔
2170
        if err != nil {
48✔
2171
                return nil, err
×
2172
        }
×
2173

2174
        conv, err := getConverter(val.Type(), c.t)
48✔
2175
        if conv == nil {
51✔
2176
                return nil, err
3✔
2177
        }
3✔
2178

2179
        return conv(val)
45✔
2180
}
2181

2182
func (c *Cast) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2183
        return &Cast{
×
2184
                val: c.val.reduceSelectors(row, implicitTable),
×
2185
                t:   c.t,
×
2186
        }
×
2187
}
×
2188

2189
func (c *Cast) isConstant() bool {
7✔
2190
        return c.val.isConstant()
7✔
2191
}
7✔
2192

2193
func (c *Cast) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
×
2194
        return nil
×
2195
}
×
2196

2197
type Param struct {
2198
        id  string
2199
        pos int
2200
}
2201

2202
func (v *Param) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
59✔
2203
        t, ok := params[v.id]
59✔
2204
        if !ok {
116✔
2205
                params[v.id] = AnyType
57✔
2206
                return AnyType, nil
57✔
2207
        }
57✔
2208

2209
        return t, nil
2✔
2210
}
2211

2212
func (v *Param) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
76✔
2213
        currT, ok := params[v.id]
76✔
2214
        if ok && currT != t && currT != AnyType {
80✔
2215
                return ErrInferredMultipleTypes
4✔
2216
        }
4✔
2217

2218
        params[v.id] = t
72✔
2219

72✔
2220
        return nil
72✔
2221
}
2222

2223
func (p *Param) substitute(params map[string]interface{}) (ValueExp, error) {
745✔
2224
        val, ok := params[p.id]
745✔
2225
        if !ok {
807✔
2226
                return nil, fmt.Errorf("%w(%s)", ErrMissingParameter, p.id)
62✔
2227
        }
62✔
2228

2229
        if val == nil {
709✔
2230
                return &NullValue{t: AnyType}, nil
26✔
2231
        }
26✔
2232

2233
        switch v := val.(type) {
657✔
2234
        case bool:
39✔
2235
                {
78✔
2236
                        return &Bool{val: v}, nil
39✔
2237
                }
39✔
2238
        case string:
112✔
2239
                {
224✔
2240
                        return &Varchar{val: v}, nil
112✔
2241
                }
112✔
2242
        case int:
118✔
2243
                {
236✔
2244
                        return &Integer{val: int64(v)}, nil
118✔
2245
                }
118✔
2246
        case uint:
×
2247
                {
×
2248
                        return &Integer{val: int64(v)}, nil
×
2249
                }
×
2250
        case uint64:
34✔
2251
                {
68✔
2252
                        return &Integer{val: int64(v)}, nil
34✔
2253
                }
34✔
2254
        case int64:
105✔
2255
                {
210✔
2256
                        return &Integer{val: v}, nil
105✔
2257
                }
105✔
2258
        case []byte:
12✔
2259
                {
24✔
2260
                        return &Blob{val: v}, nil
12✔
2261
                }
12✔
2262
        case time.Time:
111✔
2263
                {
222✔
2264
                        return &Timestamp{val: v.Truncate(time.Microsecond).UTC()}, nil
111✔
2265
                }
111✔
2266
        case float64:
125✔
2267
                {
250✔
2268
                        return &Float64{val: v}, nil
125✔
2269
                }
125✔
2270
        }
2271

2272
        return nil, ErrUnsupportedParameter
1✔
2273
}
2274

2275
func (p *Param) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
×
2276
        return nil, ErrUnexpected
×
2277
}
×
2278

2279
func (p *Param) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
2280
        return p
×
2281
}
×
2282

2283
func (p *Param) isConstant() bool {
129✔
2284
        return true
129✔
2285
}
129✔
2286

2287
func (v *Param) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
5✔
2288
        return nil
5✔
2289
}
5✔
2290

2291
type Comparison int
2292

2293
const (
2294
        EqualTo Comparison = iota
2295
        LowerThan
2296
        LowerOrEqualTo
2297
        GreaterThan
2298
        GreaterOrEqualTo
2299
)
2300

2301
type DataSource interface {
2302
        SQLStmt
2303
        Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, scanSpecs *ScanSpecs) (RowReader, error)
2304
        Alias() string
2305
}
2306

2307
type SelectStmt struct {
2308
        distinct  bool
2309
        selectors []Selector
2310
        ds        DataSource
2311
        indexOn   []string
2312
        joins     []*JoinSpec
2313
        where     ValueExp
2314
        groupBy   []*ColSelector
2315
        having    ValueExp
2316
        orderBy   []*OrdCol
2317
        limit     ValueExp
2318
        offset    ValueExp
2319
        as        string
2320
}
2321

2322
func NewSelectStmt(
2323
        selectors []Selector,
2324
        ds DataSource,
2325
        where ValueExp,
2326
        orderBy []*OrdCol,
2327
        limit ValueExp,
2328
        offset ValueExp,
2329
) *SelectStmt {
71✔
2330
        return &SelectStmt{
71✔
2331
                selectors: selectors,
71✔
2332
                ds:        ds,
71✔
2333
                where:     where,
71✔
2334
                orderBy:   orderBy,
71✔
2335
                limit:     limit,
71✔
2336
                offset:    offset,
71✔
2337
        }
71✔
2338
}
71✔
2339

2340
func (stmt *SelectStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
52✔
2341
        _, err := stmt.execAt(ctx, tx, nil)
52✔
2342
        if err != nil {
52✔
2343
                return err
×
2344
        }
×
2345

2346
        // TODO (jeroiraz) may be optimized so to resolve the query statement just once
2347
        rowReader, err := stmt.Resolve(ctx, tx, nil, nil)
52✔
2348
        if err != nil {
52✔
2349
                return err
×
2350
        }
×
2351
        defer rowReader.Close()
52✔
2352

52✔
2353
        return rowReader.InferParameters(ctx, params)
52✔
2354
}
2355

2356
func (stmt *SelectStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
465✔
2357
        if stmt.groupBy == nil && stmt.having != nil {
466✔
2358
                return nil, ErrHavingClauseRequiresGroupClause
1✔
2359
        }
1✔
2360

2361
        if len(stmt.groupBy) > 1 {
464✔
2362
                return nil, ErrLimitedGroupBy
×
2363
        }
×
2364

2365
        if len(stmt.orderBy) > 1 {
465✔
2366
                return nil, ErrLimitedOrderBy
1✔
2367
        }
1✔
2368

2369
        if len(stmt.orderBy) > 0 {
561✔
2370
                tableRef, ok := stmt.ds.(*tableRef)
98✔
2371
                if !ok {
100✔
2372
                        return nil, ErrLimitedOrderBy
2✔
2373
                }
2✔
2374

2375
                table, err := tableRef.referencedTable(tx)
96✔
2376
                if err != nil {
97✔
2377
                        return nil, err
1✔
2378
                }
1✔
2379

2380
                colName := stmt.orderBy[0].sel.col
95✔
2381

95✔
2382
                indexed, err := table.IsIndexed(colName)
95✔
2383
                if err != nil {
96✔
2384
                        return nil, err
1✔
2385
                }
1✔
2386

2387
                if !indexed {
96✔
2388
                        return nil, ErrLimitedOrderBy
2✔
2389
                }
2✔
2390
        }
2391

2392
        return tx, nil
457✔
2393
}
2394

2395
func (stmt *SelectStmt) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (ret RowReader, err error) {
577✔
2396
        scanSpecs, err := stmt.genScanSpecs(tx, params)
577✔
2397
        if err != nil {
593✔
2398
                return nil, err
16✔
2399
        }
16✔
2400

2401
        rowReader, err := stmt.ds.Resolve(ctx, tx, params, scanSpecs)
561✔
2402
        if err != nil {
562✔
2403
                return nil, err
1✔
2404
        }
1✔
2405
        defer func() {
1,120✔
2406
                if err != nil {
564✔
2407
                        rowReader.Close()
4✔
2408
                }
4✔
2409
        }()
2410

2411
        if stmt.joins != nil {
571✔
2412
                jointRowReader, err := newJointRowReader(rowReader, stmt.joins)
11✔
2413
                if err != nil {
12✔
2414
                        return nil, err
1✔
2415
                }
1✔
2416
                rowReader = jointRowReader
10✔
2417
        }
2418

2419
        if stmt.where != nil {
848✔
2420
                rowReader = newConditionalRowReader(rowReader, stmt.where)
289✔
2421
        }
289✔
2422

2423
        containsAggregations := false
559✔
2424
        for _, sel := range stmt.selectors {
1,237✔
2425
                _, containsAggregations = sel.(*AggColSelector)
678✔
2426
                if containsAggregations {
732✔
2427
                        break
54✔
2428
                }
2429
        }
2430

2431
        if containsAggregations {
613✔
2432
                var groupBy []*ColSelector
54✔
2433
                if stmt.groupBy != nil {
63✔
2434
                        groupBy = stmt.groupBy
9✔
2435
                }
9✔
2436

2437
                groupedRowReader, err := newGroupedRowReader(rowReader, stmt.selectors, groupBy)
54✔
2438
                if err != nil {
55✔
2439
                        return nil, err
1✔
2440
                }
1✔
2441
                rowReader = groupedRowReader
53✔
2442

53✔
2443
                if stmt.having != nil {
58✔
2444
                        rowReader = newConditionalRowReader(rowReader, stmt.having)
5✔
2445
                }
5✔
2446
        }
2447

2448
        projectedRowReader, err := newProjectedRowReader(ctx, rowReader, stmt.as, stmt.selectors)
558✔
2449
        if err != nil {
559✔
2450
                return nil, err
1✔
2451
        }
1✔
2452
        rowReader = projectedRowReader
557✔
2453

557✔
2454
        if stmt.distinct {
565✔
2455
                distinctRowReader, err := newDistinctRowReader(ctx, rowReader)
8✔
2456
                if err != nil {
9✔
2457
                        return nil, err
1✔
2458
                }
1✔
2459
                rowReader = distinctRowReader
7✔
2460
        }
2461

2462
        if stmt.offset != nil {
606✔
2463
                offset, err := evalExpAsInt(tx, stmt.offset, params)
50✔
2464
                if err != nil {
50✔
2465
                        return nil, fmt.Errorf("%w: invalid offset", err)
×
2466
                }
×
2467

2468
                rowReader = newOffsetRowReader(rowReader, offset)
50✔
2469
        }
2470

2471
        if stmt.limit != nil {
650✔
2472
                limit, err := evalExpAsInt(tx, stmt.limit, params)
94✔
2473
                if err != nil {
94✔
2474
                        return nil, fmt.Errorf("%w: invalid limit", err)
×
2475
                }
×
2476

2477
                if limit < 0 {
94✔
2478
                        return nil, fmt.Errorf("%w: invalid limit", ErrIllegalArguments)
×
2479
                }
×
2480

2481
                if limit > 0 {
134✔
2482
                        rowReader = newLimitRowReader(rowReader, limit)
40✔
2483
                }
40✔
2484
        }
2485

2486
        return rowReader, nil
556✔
2487
}
2488

2489
func evalExpAsInt(tx *SQLTx, exp ValueExp, params map[string]interface{}) (int, error) {
144✔
2490
        offset, err := exp.substitute(params)
144✔
2491
        if err != nil {
144✔
2492
                return 0, err
×
2493
        }
×
2494

2495
        texp, err := offset.reduce(tx, nil, "")
144✔
2496
        if err != nil {
144✔
2497
                return 0, err
×
2498
        }
×
2499

2500
        convVal, err := mayApplyImplicitConversion(texp.RawValue(), IntegerType)
144✔
2501
        if err != nil {
144✔
2502
                return 0, ErrInvalidValue
×
2503
        }
×
2504

2505
        num, ok := convVal.(int64)
144✔
2506
        if !ok {
144✔
2507
                return 0, ErrInvalidValue
×
2508
        }
×
2509

2510
        if num > math.MaxInt32 {
144✔
2511
                return 0, ErrInvalidValue
×
2512
        }
×
2513

2514
        return int(num), nil
144✔
2515
}
2516

2517
func (stmt *SelectStmt) Alias() string {
2✔
2518
        if stmt.as == "" {
3✔
2519
                return stmt.ds.Alias()
1✔
2520
        }
1✔
2521

2522
        return stmt.as
1✔
2523
}
2524

2525
func (stmt *SelectStmt) genScanSpecs(tx *SQLTx, params map[string]interface{}) (*ScanSpecs, error) {
577✔
2526
        tableRef, isTableRef := stmt.ds.(*tableRef)
577✔
2527
        if !isTableRef {
618✔
2528
                return nil, nil
41✔
2529
        }
41✔
2530

2531
        table, err := tableRef.referencedTable(tx)
536✔
2532
        if err != nil {
547✔
2533
                return nil, err
11✔
2534
        }
11✔
2535

2536
        rangesByColID := make(map[uint32]*typedValueRange)
525✔
2537
        if stmt.where != nil {
803✔
2538
                err = stmt.where.selectorRanges(table, tableRef.Alias(), params, rangesByColID)
278✔
2539
                if err != nil {
280✔
2540
                        return nil, err
2✔
2541
                }
2✔
2542
        }
2543

2544
        var preferredIndex *Index
523✔
2545

523✔
2546
        if len(stmt.indexOn) > 0 {
548✔
2547
                cols := make([]*Column, len(stmt.indexOn))
25✔
2548

25✔
2549
                for i, colName := range stmt.indexOn {
64✔
2550
                        col, err := table.GetColumnByName(colName)
39✔
2551
                        if err != nil {
39✔
2552
                                return nil, err
×
2553
                        }
×
2554

2555
                        cols[i] = col
39✔
2556
                }
2557

2558
                index, err := table.GetIndexByName(indexName(table.name, cols))
25✔
2559
                if err != nil {
25✔
2560
                        return nil, err
×
2561
                }
×
2562

2563
                preferredIndex = index
25✔
2564
        }
2565

2566
        var sortingIndex *Index
523✔
2567
        var descOrder bool
523✔
2568

523✔
2569
        if stmt.orderBy == nil {
954✔
2570
                if preferredIndex == nil {
852✔
2571
                        sortingIndex = table.primaryIndex
421✔
2572
                } else {
431✔
2573
                        sortingIndex = preferredIndex
10✔
2574
                }
10✔
2575
        }
2576

2577
        if len(stmt.orderBy) > 0 {
615✔
2578
                col, err := table.GetColumnByName(stmt.orderBy[0].sel.col)
92✔
2579
                if err != nil {
92✔
2580
                        return nil, err
×
2581
                }
×
2582

2583
                for _, idx := range table.indexesByColID[col.id] {
196✔
2584
                        if idx.sortableUsing(col.id, rangesByColID) {
200✔
2585
                                if preferredIndex == nil || idx.id == preferredIndex.id {
185✔
2586
                                        sortingIndex = idx
89✔
2587
                                        break
89✔
2588
                                }
2589
                        }
2590
                }
2591

2592
                descOrder = stmt.orderBy[0].descOrder
92✔
2593
        }
2594

2595
        if sortingIndex == nil {
526✔
2596
                return nil, ErrNoAvailableIndex
3✔
2597
        }
3✔
2598

2599
        if tableRef.history && !sortingIndex.IsPrimary() {
520✔
2600
                return nil, fmt.Errorf("%w: historical queries are supported over primary index", ErrIllegalArguments)
×
2601
        }
×
2602

2603
        return &ScanSpecs{
520✔
2604
                Index:          sortingIndex,
520✔
2605
                rangesByColID:  rangesByColID,
520✔
2606
                IncludeHistory: tableRef.history,
520✔
2607
                DescOrder:      descOrder,
520✔
2608
        }, nil
520✔
2609
}
2610

2611
type UnionStmt struct {
2612
        distinct    bool
2613
        left, right DataSource
2614
}
2615

2616
func (stmt *UnionStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
2617
        err := stmt.left.inferParameters(ctx, tx, params)
1✔
2618
        if err != nil {
1✔
2619
                return err
×
2620
        }
×
2621

2622
        return stmt.right.inferParameters(ctx, tx, params)
1✔
2623
}
2624

2625
func (stmt *UnionStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
9✔
2626
        _, err := stmt.left.execAt(ctx, tx, params)
9✔
2627
        if err != nil {
9✔
2628
                return tx, err
×
2629
        }
×
2630

2631
        return stmt.right.execAt(ctx, tx, params)
9✔
2632
}
2633

2634
func (stmt *UnionStmt) resolveUnionAll(ctx context.Context, tx *SQLTx, params map[string]interface{}) (ret RowReader, err error) {
11✔
2635
        leftRowReader, err := stmt.left.Resolve(ctx, tx, params, nil)
11✔
2636
        if err != nil {
12✔
2637
                return nil, err
1✔
2638
        }
1✔
2639
        defer func() {
20✔
2640
                if err != nil {
14✔
2641
                        leftRowReader.Close()
4✔
2642
                }
4✔
2643
        }()
2644

2645
        rightRowReader, err := stmt.right.Resolve(ctx, tx, params, nil)
10✔
2646
        if err != nil {
11✔
2647
                return nil, err
1✔
2648
        }
1✔
2649
        defer func() {
18✔
2650
                if err != nil {
12✔
2651
                        rightRowReader.Close()
3✔
2652
                }
3✔
2653
        }()
2654

2655
        rowReader, err := newUnionRowReader(ctx, []RowReader{leftRowReader, rightRowReader})
9✔
2656
        if err != nil {
12✔
2657
                return nil, err
3✔
2658
        }
3✔
2659

2660
        return rowReader, nil
6✔
2661
}
2662

2663
func (stmt *UnionStmt) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (ret RowReader, err error) {
11✔
2664
        rowReader, err := stmt.resolveUnionAll(ctx, tx, params)
11✔
2665
        if err != nil {
16✔
2666
                return nil, err
5✔
2667
        }
5✔
2668
        defer func() {
12✔
2669
                if err != nil {
7✔
2670
                        rowReader.Close()
1✔
2671
                }
1✔
2672
        }()
2673

2674
        if stmt.distinct {
11✔
2675
                distinctReader, err := newDistinctRowReader(ctx, rowReader)
5✔
2676
                if err != nil {
6✔
2677
                        return nil, err
1✔
2678
                }
1✔
2679
                rowReader = distinctReader
4✔
2680
        }
2681

2682
        return rowReader, nil
5✔
2683
}
2684

2685
func (stmt *UnionStmt) Alias() string {
×
2686
        return ""
×
2687
}
×
2688

2689
func NewTableRef(table string, as string) *tableRef {
179✔
2690
        return &tableRef{
179✔
2691
                table: table,
179✔
2692
                as:    as,
179✔
2693
        }
179✔
2694
}
179✔
2695

2696
type tableRef struct {
2697
        table   string
2698
        history bool
2699
        period  period
2700
        as      string
2701
}
2702

2703
type period struct {
2704
        start *openPeriod
2705
        end   *openPeriod
2706
}
2707

2708
type openPeriod struct {
2709
        inclusive bool
2710
        instant   periodInstant
2711
}
2712

2713
type periodInstant struct {
2714
        exp         ValueExp
2715
        instantType instantType
2716
}
2717

2718
type instantType = int
2719

2720
const (
2721
        txInstant instantType = iota
2722
        timeInstant
2723
)
2724

2725
func (i periodInstant) resolve(tx *SQLTx, params map[string]interface{}, asc, inclusive bool) (uint64, error) {
81✔
2726
        exp, err := i.exp.substitute(params)
81✔
2727
        if err != nil {
81✔
2728
                return 0, err
×
2729
        }
×
2730

2731
        instantVal, err := exp.reduce(tx, nil, "")
81✔
2732
        if err != nil {
83✔
2733
                return 0, err
2✔
2734
        }
2✔
2735

2736
        if i.instantType == txInstant {
124✔
2737
                txID, ok := instantVal.RawValue().(int64)
45✔
2738
                if !ok {
45✔
2739
                        return 0, fmt.Errorf("%w: invalid tx range, tx ID must be a positive integer, %s given", ErrIllegalArguments, instantVal.Type())
×
2740
                }
×
2741

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

2746
                if inclusive {
61✔
2747
                        return uint64(txID), nil
23✔
2748
                }
23✔
2749

2750
                if asc {
26✔
2751
                        return uint64(txID + 1), nil
11✔
2752
                }
11✔
2753

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

2758
                return uint64(txID - 1), nil
3✔
2759
        } else {
34✔
2760

34✔
2761
                var ts time.Time
34✔
2762

34✔
2763
                if instantVal.Type() == TimestampType {
67✔
2764
                        ts = instantVal.RawValue().(time.Time)
33✔
2765
                } else {
34✔
2766
                        conv, err := getConverter(instantVal.Type(), TimestampType)
1✔
2767
                        if err != nil {
1✔
2768
                                return 0, err
×
2769
                        }
×
2770

2771
                        tval, err := conv(instantVal)
1✔
2772
                        if err != nil {
1✔
2773
                                return 0, err
×
2774
                        }
×
2775

2776
                        ts = tval.RawValue().(time.Time)
1✔
2777
                }
2778

2779
                sts := ts
34✔
2780

34✔
2781
                if asc {
57✔
2782
                        if !inclusive {
34✔
2783
                                sts = sts.Add(1 * time.Second)
11✔
2784
                        }
11✔
2785

2786
                        txHdr, err := tx.engine.store.FirstTxSince(sts)
23✔
2787
                        if err != nil {
34✔
2788
                                return 0, err
11✔
2789
                        }
11✔
2790

2791
                        return txHdr.ID, nil
12✔
2792
                }
2793

2794
                if !inclusive {
11✔
2795
                        sts = sts.Add(-1 * time.Second)
×
2796
                }
×
2797

2798
                txHdr, err := tx.engine.store.LastTxUntil(sts)
11✔
2799
                if err != nil {
11✔
2800
                        return 0, err
×
2801
                }
×
2802

2803
                return txHdr.ID, nil
11✔
2804
        }
2805
}
2806

2807
func (stmt *tableRef) referencedTable(tx *SQLTx) (*Table, error) {
2,024✔
2808
        table, err := tx.catalog.GetTableByName(stmt.table)
2,024✔
2809
        if err != nil {
2,040✔
2810
                return nil, err
16✔
2811
        }
16✔
2812

2813
        return table, nil
2,008✔
2814
}
2815

2816
func (stmt *tableRef) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
1✔
2817
        return nil
1✔
2818
}
1✔
2819

2820
func (stmt *tableRef) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
×
2821
        return tx, nil
×
2822
}
×
2823

2824
func (stmt *tableRef) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, scanSpecs *ScanSpecs) (RowReader, error) {
533✔
2825
        if tx == nil {
533✔
2826
                return nil, ErrIllegalArguments
×
2827
        }
×
2828

2829
        table, err := stmt.referencedTable(tx)
533✔
2830
        if err != nil {
533✔
2831
                return nil, err
×
2832
        }
×
2833

2834
        return newRawRowReader(tx, params, table, stmt.period, stmt.as, scanSpecs)
533✔
2835
}
2836

2837
func (stmt *tableRef) Alias() string {
279✔
2838
        if stmt.as == "" {
513✔
2839
                return stmt.table
234✔
2840
        }
234✔
2841
        return stmt.as
45✔
2842
}
2843

2844
type JoinSpec struct {
2845
        joinType JoinType
2846
        ds       DataSource
2847
        cond     ValueExp
2848
        indexOn  []string
2849
}
2850

2851
type OrdCol struct {
2852
        sel       *ColSelector
2853
        descOrder bool
2854
}
2855

2856
func NewOrdCol(table string, col string, descOrder bool) *OrdCol {
1✔
2857
        return &OrdCol{
1✔
2858
                sel:       NewColSelector(table, col),
1✔
2859
                descOrder: descOrder,
1✔
2860
        }
1✔
2861
}
1✔
2862

2863
type Selector interface {
2864
        ValueExp
2865
        resolve(implicitTable string) (aggFn, table, col string)
2866
        alias() string
2867
        setAlias(alias string)
2868
}
2869

2870
type ColSelector struct {
2871
        table string
2872
        col   string
2873
        as    string
2874
}
2875

2876
func NewColSelector(table, col string) *ColSelector {
125✔
2877
        return &ColSelector{
125✔
2878
                table: table,
125✔
2879
                col:   col,
125✔
2880
        }
125✔
2881
}
125✔
2882

2883
func (sel *ColSelector) resolve(implicitTable string) (aggFn, table, col string) {
5,118✔
2884
        table = implicitTable
5,118✔
2885
        if sel.table != "" {
8,290✔
2886
                table = sel.table
3,172✔
2887
        }
3,172✔
2888

2889
        return "", table, sel.col
5,118✔
2890
}
2891

2892
func (sel *ColSelector) alias() string {
6,108✔
2893
        if sel.as == "" {
12,130✔
2894
                return sel.col
6,022✔
2895
        }
6,022✔
2896

2897
        return sel.as
86✔
2898
}
2899

2900
func (sel *ColSelector) setAlias(alias string) {
634✔
2901
        sel.as = alias
634✔
2902
}
634✔
2903

2904
func (sel *ColSelector) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
62✔
2905
        _, table, col := sel.resolve(implicitTable)
62✔
2906
        encSel := EncodeSelector("", table, col)
62✔
2907

62✔
2908
        desc, ok := cols[encSel]
62✔
2909
        if !ok {
64✔
2910
                return AnyType, fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, col)
2✔
2911
        }
2✔
2912

2913
        return desc.Type, nil
60✔
2914
}
2915

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

15✔
2920
        desc, ok := cols[encSel]
15✔
2921
        if !ok {
17✔
2922
                return fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, col)
2✔
2923
        }
2✔
2924

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

2929
        return nil
10✔
2930
}
2931

2932
func (sel *ColSelector) substitute(params map[string]interface{}) (ValueExp, error) {
1,508✔
2933
        return sel, nil
1,508✔
2934
}
1,508✔
2935

2936
func (sel *ColSelector) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1,508✔
2937
        if row == nil {
1,509✔
2938
                return nil, fmt.Errorf("%w: no row to evaluate in current context", ErrInvalidValue)
1✔
2939
        }
1✔
2940

2941
        aggFn, table, col := sel.resolve(implicitTable)
1,507✔
2942

1,507✔
2943
        v, ok := row.ValuesBySelector[EncodeSelector(aggFn, table, col)]
1,507✔
2944
        if !ok {
1,510✔
2945
                return nil, fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, col)
3✔
2946
        }
3✔
2947

2948
        return v, nil
1,504✔
2949
}
2950

2951
func (sel *ColSelector) reduceSelectors(row *Row, implicitTable string) ValueExp {
139✔
2952
        aggFn, table, col := sel.resolve(implicitTable)
139✔
2953

139✔
2954
        v, ok := row.ValuesBySelector[EncodeSelector(aggFn, table, col)]
139✔
2955
        if !ok {
203✔
2956
                return sel
64✔
2957
        }
64✔
2958

2959
        return v
75✔
2960
}
2961

2962
func (sel *ColSelector) isConstant() bool {
12✔
2963
        return false
12✔
2964
}
12✔
2965

2966
func (sel *ColSelector) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
11✔
2967
        return nil
11✔
2968
}
11✔
2969

2970
type AggColSelector struct {
2971
        aggFn AggregateFn
2972
        table string
2973
        col   string
2974
        as    string
2975
}
2976

2977
func NewAggColSelector(aggFn AggregateFn, table, col string) *AggColSelector {
16✔
2978
        return &AggColSelector{
16✔
2979
                aggFn: aggFn,
16✔
2980
                table: table,
16✔
2981
                col:   col,
16✔
2982
        }
16✔
2983
}
16✔
2984

2985
func EncodeSelector(aggFn, table, col string) string {
25,001✔
2986
        return aggFn + "(" + table + "." + col + ")"
25,001✔
2987
}
25,001✔
2988

2989
func (sel *AggColSelector) resolve(implicitTable string) (aggFn, table, col string) {
247✔
2990
        table = implicitTable
247✔
2991
        if sel.table != "" {
280✔
2992
                table = sel.table
33✔
2993
        }
33✔
2994

2995
        return sel.aggFn, table, sel.col
247✔
2996
}
2997

2998
func (sel *AggColSelector) alias() string {
113✔
2999
        return sel.as
113✔
3000
}
113✔
3001

3002
func (sel *AggColSelector) setAlias(alias string) {
63✔
3003
        sel.as = alias
63✔
3004
}
63✔
3005

3006
func (sel *AggColSelector) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
3007
        if sel.aggFn == COUNT {
8✔
3008
                return IntegerType, nil
2✔
3009
        }
2✔
3010

3011
        colSelector := &ColSelector{table: sel.table, col: sel.col}
4✔
3012

4✔
3013
        if sel.aggFn == SUM || sel.aggFn == AVG {
6✔
3014
                t, err := colSelector.inferType(cols, params, implicitTable)
2✔
3015
                if err != nil {
2✔
3016
                        return AnyType, err
×
3017
                }
×
3018

3019
                if t != IntegerType && t != Float64Type {
2✔
3020
                        return AnyType, fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, t)
×
3021

×
3022
                }
×
3023

3024
                return t, nil
2✔
3025
        }
3026

3027
        return colSelector.inferType(cols, params, implicitTable)
2✔
3028
}
3029

3030
func (sel *AggColSelector) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
8✔
3031
        if sel.aggFn == COUNT {
10✔
3032
                if t != IntegerType {
3✔
3033
                        return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
1✔
3034
                }
1✔
3035
                return nil
1✔
3036
        }
3037

3038
        colSelector := &ColSelector{table: sel.table, col: sel.col}
6✔
3039

6✔
3040
        if sel.aggFn == SUM || sel.aggFn == AVG {
10✔
3041
                if t != IntegerType && t != Float64Type {
5✔
3042
                        return fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, t)
1✔
3043
                }
1✔
3044
        }
3045

3046
        return colSelector.requiresType(t, cols, params, implicitTable)
5✔
3047
}
3048

3049
func (sel *AggColSelector) substitute(params map[string]interface{}) (ValueExp, error) {
25✔
3050
        return sel, nil
25✔
3051
}
25✔
3052

3053
func (sel *AggColSelector) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
24✔
3054
        if row == nil {
25✔
3055
                return nil, fmt.Errorf("%w: no row to evaluate aggregation (%s) in current context", ErrInvalidValue, sel.aggFn)
1✔
3056
        }
1✔
3057

3058
        v, ok := row.ValuesBySelector[EncodeSelector(sel.resolve(implicitTable))]
23✔
3059
        if !ok {
24✔
3060
                return nil, fmt.Errorf("%w (%s)", ErrColumnDoesNotExist, sel.col)
1✔
3061
        }
1✔
3062
        return v, nil
22✔
3063
}
3064

3065
func (sel *AggColSelector) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
3066
        return sel
×
3067
}
×
3068

3069
func (sel *AggColSelector) isConstant() bool {
1✔
3070
        return false
1✔
3071
}
1✔
3072

3073
func (sel *AggColSelector) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
×
3074
        return nil
×
3075
}
×
3076

3077
type NumExp struct {
3078
        op          NumOperator
3079
        left, right ValueExp
3080
}
3081

3082
func (bexp *NumExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
3083
        // First step - check if we can infer the type of sub-expressions
6✔
3084
        tleft, err := bexp.left.inferType(cols, params, implicitTable)
6✔
3085
        if err != nil {
6✔
3086
                return AnyType, err
×
3087
        }
×
3088
        if tleft != AnyType && tleft != IntegerType && tleft != Float64Type {
6✔
3089
                return AnyType, fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, tleft)
×
3090
        }
×
3091

3092
        tright, err := bexp.right.inferType(cols, params, implicitTable)
6✔
3093
        if err != nil {
6✔
3094
                return AnyType, err
×
3095
        }
×
3096
        if tright != AnyType && tright != IntegerType && tright != Float64Type {
8✔
3097
                return AnyType, fmt.Errorf("%w: %v or %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, Float64Type, tright)
2✔
3098
        }
2✔
3099

3100
        if tleft == IntegerType && tright == IntegerType {
6✔
3101
                // Both sides are integer types - the result is also integer
2✔
3102
                return IntegerType, nil
2✔
3103
        }
2✔
3104

3105
        if tleft != AnyType && tright != AnyType {
2✔
3106
                // Both sides have concrete types but at least one of them is float
×
3107
                return Float64Type, nil
×
3108
        }
×
3109

3110
        // Both sides are ambiguous
3111
        return AnyType, nil
2✔
3112
}
3113

3114
func copyParams(params map[string]SQLValueType) map[string]SQLValueType {
11✔
3115
        ret := make(map[string]SQLValueType, len(params))
11✔
3116
        for k, v := range params {
15✔
3117
                ret[k] = v
4✔
3118
        }
4✔
3119
        return ret
11✔
3120
}
3121

3122
func restoreParams(params, restore map[string]SQLValueType) {
2✔
3123
        for k := range params {
2✔
3124
                delete(params, k)
×
3125
        }
×
3126
        for k, v := range restore {
2✔
3127
                params[k] = v
×
3128
        }
×
3129
}
3130

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

3136
        floatArgs := 2
6✔
3137
        paramsOrig := copyParams(params)
6✔
3138
        err := bexp.left.requiresType(t, cols, params, implicitTable)
6✔
3139
        if err != nil && t == Float64Type {
7✔
3140
                restoreParams(params, paramsOrig)
1✔
3141
                floatArgs--
1✔
3142
                err = bexp.left.requiresType(IntegerType, cols, params, implicitTable)
1✔
3143
        }
1✔
3144
        if err != nil {
7✔
3145
                return err
1✔
3146
        }
1✔
3147

3148
        paramsOrig = copyParams(params)
5✔
3149
        err = bexp.right.requiresType(t, cols, params, implicitTable)
5✔
3150
        if err != nil && t == Float64Type {
6✔
3151
                restoreParams(params, paramsOrig)
1✔
3152
                floatArgs--
1✔
3153
                err = bexp.right.requiresType(IntegerType, cols, params, implicitTable)
1✔
3154
        }
1✔
3155
        if err != nil {
7✔
3156
                return err
2✔
3157
        }
2✔
3158

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

3164
        return nil
3✔
3165
}
3166

3167
func (bexp *NumExp) substitute(params map[string]interface{}) (ValueExp, error) {
42✔
3168
        rlexp, err := bexp.left.substitute(params)
42✔
3169
        if err != nil {
42✔
3170
                return nil, err
×
3171
        }
×
3172

3173
        rrexp, err := bexp.right.substitute(params)
42✔
3174
        if err != nil {
42✔
3175
                return nil, err
×
3176
        }
×
3177

3178
        bexp.left = rlexp
42✔
3179
        bexp.right = rrexp
42✔
3180

42✔
3181
        return bexp, nil
42✔
3182
}
3183

3184
func (bexp *NumExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
42✔
3185
        vl, err := bexp.left.reduce(tx, row, implicitTable)
42✔
3186
        if err != nil {
42✔
3187
                return nil, err
×
3188
        }
×
3189

3190
        vr, err := bexp.right.reduce(tx, row, implicitTable)
42✔
3191
        if err != nil {
42✔
3192
                return nil, err
×
3193
        }
×
3194

3195
        return applyNumOperator(bexp.op, vl, vr)
42✔
3196
}
3197

3198
func (bexp *NumExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
3199
        return &NumExp{
1✔
3200
                op:    bexp.op,
1✔
3201
                left:  bexp.left.reduceSelectors(row, implicitTable),
1✔
3202
                right: bexp.right.reduceSelectors(row, implicitTable),
1✔
3203
        }
1✔
3204
}
1✔
3205

3206
func (bexp *NumExp) isConstant() bool {
3✔
3207
        return bexp.left.isConstant() && bexp.right.isConstant()
3✔
3208
}
3✔
3209

3210
func (bexp *NumExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
3✔
3211
        return nil
3✔
3212
}
3✔
3213

3214
type NotBoolExp struct {
3215
        exp ValueExp
3216
}
3217

3218
func (bexp *NotBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
2✔
3219
        err := bexp.exp.requiresType(BooleanType, cols, params, implicitTable)
2✔
3220
        if err != nil {
2✔
3221
                return AnyType, err
×
3222
        }
×
3223

3224
        return BooleanType, nil
2✔
3225
}
3226

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

3232
        return bexp.exp.requiresType(BooleanType, cols, params, implicitTable)
5✔
3233
}
3234

3235
func (bexp *NotBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
22✔
3236
        rexp, err := bexp.exp.substitute(params)
22✔
3237
        if err != nil {
22✔
3238
                return nil, err
×
3239
        }
×
3240

3241
        bexp.exp = rexp
22✔
3242

22✔
3243
        return bexp, nil
22✔
3244
}
3245

3246
func (bexp *NotBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
22✔
3247
        v, err := bexp.exp.reduce(tx, row, implicitTable)
22✔
3248
        if err != nil {
22✔
3249
                return nil, err
×
3250
        }
×
3251

3252
        r, isBool := v.RawValue().(bool)
22✔
3253
        if !isBool {
22✔
3254
                return nil, ErrInvalidCondition
×
3255
        }
×
3256

3257
        return &Bool{val: !r}, nil
22✔
3258
}
3259

3260
func (bexp *NotBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
×
3261
        return &NotBoolExp{
×
3262
                exp: bexp.exp.reduceSelectors(row, implicitTable),
×
3263
        }
×
3264
}
×
3265

3266
func (bexp *NotBoolExp) isConstant() bool {
1✔
3267
        return bexp.exp.isConstant()
1✔
3268
}
1✔
3269

3270
func (bexp *NotBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
7✔
3271
        return nil
7✔
3272
}
7✔
3273

3274
type LikeBoolExp struct {
3275
        val     ValueExp
3276
        notLike bool
3277
        pattern ValueExp
3278
}
3279

3280
func NewLikeBoolExp(val ValueExp, notLike bool, pattern ValueExp) *LikeBoolExp {
3✔
3281
        return &LikeBoolExp{
3✔
3282
                val:     val,
3✔
3283
                notLike: notLike,
3✔
3284
                pattern: pattern,
3✔
3285
        }
3✔
3286
}
3✔
3287

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

3293
        err := bexp.pattern.requiresType(VarcharType, cols, params, implicitTable)
2✔
3294
        if err != nil {
3✔
3295
                return AnyType, fmt.Errorf("error in 'LIKE' clause: %w", err)
1✔
3296
        }
1✔
3297

3298
        return BooleanType, nil
1✔
3299
}
3300

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

3306
        if t != BooleanType {
7✔
3307
                return fmt.Errorf("error using the value of the LIKE operator as %s: %w", t, ErrInvalidTypes)
2✔
3308
        }
2✔
3309

3310
        err := bexp.pattern.requiresType(VarcharType, cols, params, implicitTable)
3✔
3311
        if err != nil {
4✔
3312
                return fmt.Errorf("error in 'LIKE' clause: %w", err)
1✔
3313
        }
1✔
3314

3315
        return nil
2✔
3316
}
3317

3318
func (bexp *LikeBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
35✔
3319
        if bexp.val == nil || bexp.pattern == nil {
36✔
3320
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", ErrInvalidCondition)
1✔
3321
        }
1✔
3322

3323
        val, err := bexp.val.substitute(params)
34✔
3324
        if err != nil {
34✔
3325
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3326
        }
×
3327

3328
        pattern, err := bexp.pattern.substitute(params)
34✔
3329
        if err != nil {
34✔
3330
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3331
        }
×
3332

3333
        return &LikeBoolExp{
34✔
3334
                val:     val,
34✔
3335
                notLike: bexp.notLike,
34✔
3336
                pattern: pattern,
34✔
3337
        }, nil
34✔
3338
}
3339

3340
func (bexp *LikeBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
36✔
3341
        if bexp.val == nil || bexp.pattern == nil {
37✔
3342
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", ErrInvalidCondition)
1✔
3343
        }
1✔
3344

3345
        rval, err := bexp.val.reduce(tx, row, implicitTable)
35✔
3346
        if err != nil {
35✔
3347
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3348
        }
×
3349

3350
        if rval.Type() != VarcharType {
36✔
3351
                return nil, fmt.Errorf("error in 'LIKE' clause: %w (expecting %s)", ErrInvalidTypes, VarcharType)
1✔
3352
        }
1✔
3353

3354
        if rval.IsNull() {
35✔
3355
                return &Bool{val: false}, nil
1✔
3356
        }
1✔
3357

3358
        rpattern, err := bexp.pattern.reduce(tx, row, implicitTable)
33✔
3359
        if err != nil {
33✔
3360
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3361
        }
×
3362

3363
        if rpattern.Type() != VarcharType {
33✔
3364
                return nil, fmt.Errorf("error evaluating 'LIKE' clause: %w", ErrInvalidTypes)
×
3365
        }
×
3366

3367
        matched, err := regexp.MatchString(rpattern.RawValue().(string), rval.RawValue().(string))
33✔
3368
        if err != nil {
33✔
3369
                return nil, fmt.Errorf("error in 'LIKE' clause: %w", err)
×
3370
        }
×
3371

3372
        return &Bool{val: matched != bexp.notLike}, nil
33✔
3373
}
3374

3375
func (bexp *LikeBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
3376
        return bexp
1✔
3377
}
1✔
3378

3379
func (bexp *LikeBoolExp) isConstant() bool {
2✔
3380
        return false
2✔
3381
}
2✔
3382

3383
func (bexp *LikeBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
7✔
3384
        return nil
7✔
3385
}
7✔
3386

3387
type CmpBoolExp struct {
3388
        op          CmpOperator
3389
        left, right ValueExp
3390
}
3391

3392
func NewCmpBoolExp(op CmpOperator, left, right ValueExp) *CmpBoolExp {
66✔
3393
        return &CmpBoolExp{
66✔
3394
                op:    op,
66✔
3395
                left:  left,
66✔
3396
                right: right,
66✔
3397
        }
66✔
3398
}
66✔
3399

3400
func (bexp *CmpBoolExp) Left() ValueExp {
×
3401
        return bexp.left
×
3402
}
×
3403

3404
func (bexp *CmpBoolExp) Right() ValueExp {
×
3405
        return bexp.right
×
3406
}
×
3407

3408
func (bexp *CmpBoolExp) OP() CmpOperator {
×
3409
        return bexp.op
×
3410
}
×
3411

3412
func (bexp *CmpBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
59✔
3413
        tleft, err := bexp.left.inferType(cols, params, implicitTable)
59✔
3414
        if err != nil {
59✔
3415
                return AnyType, err
×
3416
        }
×
3417

3418
        tright, err := bexp.right.inferType(cols, params, implicitTable)
59✔
3419
        if err != nil {
62✔
3420
                return AnyType, err
3✔
3421
        }
3✔
3422

3423
        // unification step
3424

3425
        if tleft == tright {
65✔
3426
                return BooleanType, nil
9✔
3427
        }
9✔
3428

3429
        if tleft != AnyType && tright != AnyType {
51✔
3430
                return AnyType, fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, tleft, tright)
4✔
3431
        }
4✔
3432

3433
        if tleft == AnyType {
47✔
3434
                err = bexp.left.requiresType(tright, cols, params, implicitTable)
4✔
3435
                if err != nil {
4✔
3436
                        return AnyType, err
×
3437
                }
×
3438
        }
3439

3440
        if tright == AnyType {
82✔
3441
                err = bexp.right.requiresType(tleft, cols, params, implicitTable)
39✔
3442
                if err != nil {
39✔
3443
                        return AnyType, err
×
3444
                }
×
3445
        }
3446

3447
        return BooleanType, nil
43✔
3448
}
3449

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

3455
        _, err := bexp.inferType(cols, params, implicitTable)
40✔
3456

40✔
3457
        return err
40✔
3458
}
3459

3460
func (bexp *CmpBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
1,465✔
3461
        rlexp, err := bexp.left.substitute(params)
1,465✔
3462
        if err != nil {
1,465✔
3463
                return nil, err
×
3464
        }
×
3465

3466
        rrexp, err := bexp.right.substitute(params)
1,465✔
3467
        if err != nil {
1,466✔
3468
                return nil, err
1✔
3469
        }
1✔
3470

3471
        bexp.left = rlexp
1,464✔
3472
        bexp.right = rrexp
1,464✔
3473

1,464✔
3474
        return bexp, nil
1,464✔
3475
}
3476

3477
func (bexp *CmpBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1,464✔
3478
        vl, err := bexp.left.reduce(tx, row, implicitTable)
1,464✔
3479
        if err != nil {
1,465✔
3480
                return nil, err
1✔
3481
        }
1✔
3482

3483
        vr, err := bexp.right.reduce(tx, row, implicitTable)
1,463✔
3484
        if err != nil {
1,465✔
3485
                return nil, err
2✔
3486
        }
2✔
3487

3488
        r, err := vl.Compare(vr)
1,461✔
3489
        if err != nil {
1,465✔
3490
                return nil, err
4✔
3491
        }
4✔
3492

3493
        return &Bool{val: cmpSatisfiesOp(r, bexp.op)}, nil
1,457✔
3494
}
3495

3496
func (bexp *CmpBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
67✔
3497
        return &CmpBoolExp{
67✔
3498
                op:    bexp.op,
67✔
3499
                left:  bexp.left.reduceSelectors(row, implicitTable),
67✔
3500
                right: bexp.right.reduceSelectors(row, implicitTable),
67✔
3501
        }
67✔
3502
}
67✔
3503

3504
func (bexp *CmpBoolExp) isConstant() bool {
2✔
3505
        return bexp.left.isConstant() && bexp.right.isConstant()
2✔
3506
}
2✔
3507

3508
func (bexp *CmpBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
365✔
3509
        matchingFunc := func(left, right ValueExp) (*ColSelector, ValueExp, bool) {
819✔
3510
                s, isSel := bexp.left.(*ColSelector)
454✔
3511
                if isSel && s.col != revCol && bexp.right.isConstant() {
730✔
3512
                        return s, right, true
276✔
3513
                }
276✔
3514
                return nil, nil, false
178✔
3515
        }
3516

3517
        sel, c, ok := matchingFunc(bexp.left, bexp.right)
365✔
3518
        if !ok {
454✔
3519
                sel, c, ok = matchingFunc(bexp.right, bexp.left)
89✔
3520
        }
89✔
3521

3522
        if !ok {
454✔
3523
                return nil
89✔
3524
        }
89✔
3525

3526
        aggFn, t, col := sel.resolve(table.name)
276✔
3527
        if aggFn != "" || t != asTable {
288✔
3528
                return nil
12✔
3529
        }
12✔
3530

3531
        column, err := table.GetColumnByName(col)
264✔
3532
        if err != nil {
265✔
3533
                return err
1✔
3534
        }
1✔
3535

3536
        val, err := c.substitute(params)
263✔
3537
        if errors.Is(err, ErrMissingParameter) {
322✔
3538
                // TODO: not supported when parameters are not provided during query resolution
59✔
3539
                return nil
59✔
3540
        }
59✔
3541
        if err != nil {
204✔
3542
                return err
×
3543
        }
×
3544

3545
        rval, err := val.reduce(nil, nil, table.name)
204✔
3546
        if err != nil {
205✔
3547
                return err
1✔
3548
        }
1✔
3549

3550
        return updateRangeFor(column.id, rval, bexp.op, rangesByColID)
203✔
3551
}
3552

3553
func updateRangeFor(colID uint32, val TypedValue, cmp CmpOperator, rangesByColID map[uint32]*typedValueRange) error {
203✔
3554
        currRange, ranged := rangesByColID[colID]
203✔
3555
        var newRange *typedValueRange
203✔
3556

203✔
3557
        switch cmp {
203✔
3558
        case EQ:
136✔
3559
                {
272✔
3560
                        newRange = &typedValueRange{
136✔
3561
                                lRange: &typedValueSemiRange{
136✔
3562
                                        val:       val,
136✔
3563
                                        inclusive: true,
136✔
3564
                                },
136✔
3565
                                hRange: &typedValueSemiRange{
136✔
3566
                                        val:       val,
136✔
3567
                                        inclusive: true,
136✔
3568
                                },
136✔
3569
                        }
136✔
3570
                }
136✔
3571
        case LT:
12✔
3572
                {
24✔
3573
                        newRange = &typedValueRange{
12✔
3574
                                hRange: &typedValueSemiRange{
12✔
3575
                                        val: val,
12✔
3576
                                },
12✔
3577
                        }
12✔
3578
                }
12✔
3579
        case LE:
10✔
3580
                {
20✔
3581
                        newRange = &typedValueRange{
10✔
3582
                                hRange: &typedValueSemiRange{
10✔
3583
                                        val:       val,
10✔
3584
                                        inclusive: true,
10✔
3585
                                },
10✔
3586
                        }
10✔
3587
                }
10✔
3588
        case GT:
18✔
3589
                {
36✔
3590
                        newRange = &typedValueRange{
18✔
3591
                                lRange: &typedValueSemiRange{
18✔
3592
                                        val: val,
18✔
3593
                                },
18✔
3594
                        }
18✔
3595
                }
18✔
3596
        case GE:
16✔
3597
                {
32✔
3598
                        newRange = &typedValueRange{
16✔
3599
                                lRange: &typedValueSemiRange{
16✔
3600
                                        val:       val,
16✔
3601
                                        inclusive: true,
16✔
3602
                                },
16✔
3603
                        }
16✔
3604
                }
16✔
3605
        case NE:
11✔
3606
                {
22✔
3607
                        return nil
11✔
3608
                }
11✔
3609
        }
3610

3611
        if !ranged {
381✔
3612
                rangesByColID[colID] = newRange
189✔
3613
                return nil
189✔
3614
        }
189✔
3615

3616
        return currRange.refineWith(newRange)
3✔
3617
}
3618

3619
func cmpSatisfiesOp(cmp int, op CmpOperator) bool {
1,457✔
3620
        switch cmp {
1,457✔
3621
        case 0:
286✔
3622
                {
572✔
3623
                        return op == EQ || op == LE || op == GE
286✔
3624
                }
286✔
3625
        case -1:
407✔
3626
                {
814✔
3627
                        return op == NE || op == LT || op == LE
407✔
3628
                }
407✔
3629
        case 1:
764✔
3630
                {
1,528✔
3631
                        return op == NE || op == GT || op == GE
764✔
3632
                }
764✔
3633
        }
3634
        return false
×
3635
}
3636

3637
type BinBoolExp struct {
3638
        op          LogicOperator
3639
        left, right ValueExp
3640
}
3641

3642
func NewBinBoolExp(op LogicOperator, lrexp, rrexp ValueExp) *BinBoolExp {
18✔
3643
        bexp := &BinBoolExp{
18✔
3644
                op: op,
18✔
3645
        }
18✔
3646

18✔
3647
        bexp.left = lrexp
18✔
3648
        bexp.right = rrexp
18✔
3649

18✔
3650
        return bexp
18✔
3651
}
18✔
3652

3653
func (bexp *BinBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
19✔
3654
        err := bexp.left.requiresType(BooleanType, cols, params, implicitTable)
19✔
3655
        if err != nil {
19✔
3656
                return AnyType, err
×
3657
        }
×
3658

3659
        err = bexp.right.requiresType(BooleanType, cols, params, implicitTable)
19✔
3660
        if err != nil {
21✔
3661
                return AnyType, err
2✔
3662
        }
2✔
3663

3664
        return BooleanType, nil
17✔
3665
}
3666

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

3672
        err := bexp.left.requiresType(BooleanType, cols, params, implicitTable)
19✔
3673
        if err != nil {
20✔
3674
                return err
1✔
3675
        }
1✔
3676

3677
        err = bexp.right.requiresType(BooleanType, cols, params, implicitTable)
18✔
3678
        if err != nil {
18✔
3679
                return err
×
3680
        }
×
3681

3682
        return nil
18✔
3683
}
3684

3685
func (bexp *BinBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
342✔
3686
        rlexp, err := bexp.left.substitute(params)
342✔
3687
        if err != nil {
342✔
3688
                return nil, err
×
3689
        }
×
3690

3691
        rrexp, err := bexp.right.substitute(params)
342✔
3692
        if err != nil {
342✔
3693
                return nil, err
×
3694
        }
×
3695

3696
        bexp.left = rlexp
342✔
3697
        bexp.right = rrexp
342✔
3698

342✔
3699
        return bexp, nil
342✔
3700
}
3701

3702
func (bexp *BinBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
342✔
3703
        vl, err := bexp.left.reduce(tx, row, implicitTable)
342✔
3704
        if err != nil {
342✔
3705
                return nil, err
×
3706
        }
×
3707

3708
        vr, err := bexp.right.reduce(tx, row, implicitTable)
342✔
3709
        if err != nil {
343✔
3710
                return nil, err
1✔
3711
        }
1✔
3712

3713
        bl, isBool := vl.(*Bool)
341✔
3714
        if !isBool {
341✔
3715
                return nil, fmt.Errorf("%w (expecting boolean value)", ErrInvalidValue)
×
3716
        }
×
3717

3718
        br, isBool := vr.(*Bool)
341✔
3719
        if !isBool {
341✔
3720
                return nil, fmt.Errorf("%w (expecting boolean value)", ErrInvalidValue)
×
3721
        }
×
3722

3723
        switch bexp.op {
341✔
3724
        case AND:
319✔
3725
                {
638✔
3726
                        return &Bool{val: bl.val && br.val}, nil
319✔
3727
                }
319✔
3728
        case OR:
22✔
3729
                {
44✔
3730
                        return &Bool{val: bl.val || br.val}, nil
22✔
3731
                }
22✔
3732
        }
3733

3734
        return nil, ErrUnexpected
×
3735
}
3736

3737
func (bexp *BinBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
15✔
3738
        return &BinBoolExp{
15✔
3739
                op:    bexp.op,
15✔
3740
                left:  bexp.left.reduceSelectors(row, implicitTable),
15✔
3741
                right: bexp.right.reduceSelectors(row, implicitTable),
15✔
3742
        }
15✔
3743
}
15✔
3744

3745
func (bexp *BinBoolExp) isConstant() bool {
1✔
3746
        return bexp.left.isConstant() && bexp.right.isConstant()
1✔
3747
}
1✔
3748

3749
func (bexp *BinBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
146✔
3750
        if bexp.op == AND {
279✔
3751
                err := bexp.left.selectorRanges(table, asTable, params, rangesByColID)
133✔
3752
                if err != nil {
133✔
3753
                        return err
×
3754
                }
×
3755

3756
                return bexp.right.selectorRanges(table, asTable, params, rangesByColID)
133✔
3757
        }
3758

3759
        lRanges := make(map[uint32]*typedValueRange)
13✔
3760
        rRanges := make(map[uint32]*typedValueRange)
13✔
3761

13✔
3762
        err := bexp.left.selectorRanges(table, asTable, params, lRanges)
13✔
3763
        if err != nil {
13✔
3764
                return err
×
3765
        }
×
3766

3767
        err = bexp.right.selectorRanges(table, asTable, params, rRanges)
13✔
3768
        if err != nil {
13✔
3769
                return err
×
3770
        }
×
3771

3772
        for colID, lr := range lRanges {
20✔
3773
                rr, ok := rRanges[colID]
7✔
3774
                if !ok {
9✔
3775
                        continue
2✔
3776
                }
3777

3778
                err = lr.extendWith(rr)
5✔
3779
                if err != nil {
5✔
3780
                        return err
×
3781
                }
×
3782

3783
                rangesByColID[colID] = lr
5✔
3784
        }
3785

3786
        return nil
13✔
3787
}
3788

3789
type ExistsBoolExp struct {
3790
        q DataSource
3791
}
3792

3793
func (bexp *ExistsBoolExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
3794
        return AnyType, errors.New("not yet supported")
1✔
3795
}
1✔
3796

3797
func (bexp *ExistsBoolExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
1✔
3798
        return errors.New("not yet supported")
1✔
3799
}
1✔
3800

3801
func (bexp *ExistsBoolExp) substitute(params map[string]interface{}) (ValueExp, error) {
1✔
3802
        return bexp, nil
1✔
3803
}
1✔
3804

3805
func (bexp *ExistsBoolExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
1✔
3806
        return nil, errors.New("not yet supported")
1✔
3807
}
1✔
3808

3809
func (bexp *ExistsBoolExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
3810
        return bexp
1✔
3811
}
1✔
3812

3813
func (bexp *ExistsBoolExp) isConstant() bool {
2✔
3814
        return false
2✔
3815
}
2✔
3816

3817
func (bexp *ExistsBoolExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
3818
        return nil
1✔
3819
}
1✔
3820

3821
type InSubQueryExp struct {
3822
        val   ValueExp
3823
        notIn bool
3824
        q     *SelectStmt
3825
}
3826

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

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

3835
func (bexp *InSubQueryExp) substitute(params map[string]interface{}) (ValueExp, error) {
1✔
3836
        return bexp, nil
1✔
3837
}
1✔
3838

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

3843
func (bexp *InSubQueryExp) reduceSelectors(row *Row, implicitTable string) ValueExp {
1✔
3844
        return bexp
1✔
3845
}
1✔
3846

3847
func (bexp *InSubQueryExp) isConstant() bool {
1✔
3848
        return false
1✔
3849
}
1✔
3850

3851
func (bexp *InSubQueryExp) selectorRanges(table *Table, asTable string, params map[string]interface{}, rangesByColID map[uint32]*typedValueRange) error {
1✔
3852
        return nil
1✔
3853
}
1✔
3854

3855
// TODO: once InSubQueryExp is supported, this struct may become obsolete by creating a ListDataSource struct
3856
type InListExp struct {
3857
        val    ValueExp
3858
        notIn  bool
3859
        values []ValueExp
3860
}
3861

3862
func (bexp *InListExp) inferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
6✔
3863
        t, err := bexp.val.inferType(cols, params, implicitTable)
6✔
3864
        if err != nil {
7✔
3865
                return AnyType, fmt.Errorf("error inferring type in 'IN' clause: %w", err)
1✔
3866
        }
1✔
3867

3868
        for _, v := range bexp.values {
15✔
3869
                err = v.requiresType(t, cols, params, implicitTable)
10✔
3870
                if err != nil {
11✔
3871
                        return AnyType, fmt.Errorf("error inferring type in 'IN' clause: %w", err)
1✔
3872
                }
1✔
3873
        }
3874

3875
        return BooleanType, nil
4✔
3876
}
3877

3878
func (bexp *InListExp) requiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
3879
        _, err := bexp.inferType(cols, params, implicitTable)
2✔
3880
        if err != nil {
3✔
3881
                return err
1✔
3882
        }
1✔
3883

3884
        if t != BooleanType {
1✔
3885
                return fmt.Errorf("error inferring type in 'IN' clause: %w", ErrInvalidTypes)
×
3886
        }
×
3887

3888
        return nil
1✔
3889
}
3890

3891
func (bexp *InListExp) substitute(params map[string]interface{}) (ValueExp, error) {
115✔
3892
        val, err := bexp.val.substitute(params)
115✔
3893
        if err != nil {
115✔
3894
                return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
×
3895
        }
×
3896

3897
        values := make([]ValueExp, len(bexp.values))
115✔
3898

115✔
3899
        for i, val := range bexp.values {
245✔
3900
                values[i], err = val.substitute(params)
130✔
3901
                if err != nil {
130✔
3902
                        return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
×
3903
                }
×
3904
        }
3905

3906
        return &InListExp{
115✔
3907
                val:    val,
115✔
3908
                notIn:  bexp.notIn,
115✔
3909
                values: values,
115✔
3910
        }, nil
115✔
3911
}
3912

3913
func (bexp *InListExp) reduce(tx *SQLTx, row *Row, implicitTable string) (TypedValue, error) {
115✔
3914
        rval, err := bexp.val.reduce(tx, row, implicitTable)
115✔
3915
        if err != nil {
116✔
3916
                return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
1✔
3917
        }
1✔
3918

3919
        var found bool
114✔
3920

114✔
3921
        for _, v := range bexp.values {
241✔
3922
                rv, err := v.reduce(tx, row, implicitTable)
127✔
3923
                if err != nil {
128✔
3924
                        return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
1✔
3925
                }
1✔
3926

3927
                r, err := rval.Compare(rv)
126✔
3928
                if err != nil {
127✔
3929
                        return nil, fmt.Errorf("error evaluating 'IN' clause: %w", err)
1✔
3930
                }
1✔
3931

3932
                if r == 0 {
140✔
3933
                        // TODO: short-circuit evaluation may be preferred when upfront static type inference is in place
15✔
3934
                        found = found || true
15✔
3935
                }
15✔
3936
        }
3937

3938
        return &Bool{val: found != bexp.notIn}, nil
112✔
3939
}
3940

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

10✔
3944
        for i, val := range bexp.values {
20✔
3945
                values[i] = val.reduceSelectors(row, implicitTable)
10✔
3946
        }
10✔
3947

3948
        return &InListExp{
10✔
3949
                val:    bexp.val.reduceSelectors(row, implicitTable),
10✔
3950
                values: values,
10✔
3951
        }
10✔
3952
}
3953

3954
func (bexp *InListExp) isConstant() bool {
1✔
3955
        return false
1✔
3956
}
1✔
3957

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

3963
type FnDataSourceStmt struct {
3964
        fnCall *FnCall
3965
        as     string
3966
}
3967

3968
func (stmt *FnDataSourceStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
×
3969
        return tx, nil
×
3970
}
×
3971

3972
func (stmt *FnDataSourceStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
×
3973
        return nil
×
3974
}
×
3975

3976
func (stmt *FnDataSourceStmt) Alias() string {
13✔
3977
        if stmt.as != "" {
15✔
3978
                return stmt.as
2✔
3979
        }
2✔
3980

3981
        switch strings.ToUpper(stmt.fnCall.fn) {
11✔
3982
        case DatabasesFnCall:
2✔
3983
                {
4✔
3984
                        return "databases"
2✔
3985
                }
2✔
3986
        case TablesFnCall:
4✔
3987
                {
8✔
3988
                        return "tables"
4✔
3989
                }
4✔
3990
        case ColumnsFnCall:
3✔
3991
                {
6✔
3992
                        return "columns"
3✔
3993
                }
3✔
3994
        case IndexesFnCall:
2✔
3995
                {
4✔
3996
                        return "indexes"
2✔
3997
                }
2✔
3998
        }
3999

4000
        // not reachable
4001
        return ""
×
4002
}
4003

4004
func (stmt *FnDataSourceStmt) Resolve(ctx context.Context, tx *SQLTx, params map[string]interface{}, scanSpecs *ScanSpecs) (rowReader RowReader, err error) {
14✔
4005
        if stmt.fnCall == nil {
14✔
4006
                return nil, fmt.Errorf("%w: function is unspecified", ErrIllegalArguments)
×
4007
        }
×
4008

4009
        switch strings.ToUpper(stmt.fnCall.fn) {
14✔
4010
        case DatabasesFnCall:
4✔
4011
                {
8✔
4012
                        return stmt.resolveListDatabases(ctx, tx, params, scanSpecs)
4✔
4013
                }
4✔
4014
        case TablesFnCall:
4✔
4015
                {
8✔
4016
                        return stmt.resolveListTables(ctx, tx, params, scanSpecs)
4✔
4017
                }
4✔
4018
        case ColumnsFnCall:
3✔
4019
                {
6✔
4020
                        return stmt.resolveListColumns(ctx, tx, params, scanSpecs)
3✔
4021
                }
3✔
4022
        case IndexesFnCall:
3✔
4023
                {
6✔
4024
                        return stmt.resolveListIndexes(ctx, tx, params, scanSpecs)
3✔
4025
                }
3✔
4026
        }
4027

4028
        return nil, fmt.Errorf("%w (%s)", ErrFunctionDoesNotExist, stmt.fnCall.fn)
×
4029
}
4030

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

4036
        cols := make([]ColDescriptor, 1)
4✔
4037
        cols[0] = ColDescriptor{
4✔
4038
                Column: "name",
4✔
4039
                Type:   VarcharType,
4✔
4040
        }
4✔
4041

4✔
4042
        var dbs []string
4✔
4043

4✔
4044
        if tx.engine.multidbHandler == nil {
5✔
4045
                return nil, ErrUnspecifiedMultiDBHandler
1✔
4046
        } else {
4✔
4047
                dbs, err = tx.engine.multidbHandler.ListDatabases(ctx)
3✔
4048
                if err != nil {
3✔
4049
                        return nil, err
×
4050
                }
×
4051
        }
4052

4053
        values := make([][]ValueExp, len(dbs))
3✔
4054

3✔
4055
        for i, db := range dbs {
9✔
4056
                values[i] = []ValueExp{&Varchar{val: db}}
6✔
4057
        }
6✔
4058

4059
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
3✔
4060
}
4061

4062
func (stmt *FnDataSourceStmt) resolveListTables(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (rowReader RowReader, err error) {
4✔
4063
        if len(stmt.fnCall.params) > 0 {
4✔
4064
                return nil, fmt.Errorf("%w: function '%s' expect no parameters but %d were provided", ErrIllegalArguments, TablesFnCall, len(stmt.fnCall.params))
×
4065
        }
×
4066

4067
        cols := make([]ColDescriptor, 1)
4✔
4068
        cols[0] = ColDescriptor{
4✔
4069
                Column: "name",
4✔
4070
                Type:   VarcharType,
4✔
4071
        }
4✔
4072

4✔
4073
        tables := tx.catalog.GetTables()
4✔
4074

4✔
4075
        values := make([][]ValueExp, len(tables))
4✔
4076

4✔
4077
        for i, t := range tables {
11✔
4078
                values[i] = []ValueExp{&Varchar{val: t.name}}
7✔
4079
        }
7✔
4080

4081
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
4✔
4082
}
4083

4084
func (stmt *FnDataSourceStmt) resolveListColumns(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (RowReader, error) {
3✔
4085
        if len(stmt.fnCall.params) != 1 {
3✔
4086
                return nil, fmt.Errorf("%w: function '%s' expect table name as parameter", ErrIllegalArguments, ColumnsFnCall)
×
4087
        }
×
4088

4089
        cols := []ColDescriptor{
3✔
4090
                {
3✔
4091
                        Column: "table",
3✔
4092
                        Type:   VarcharType,
3✔
4093
                },
3✔
4094
                {
3✔
4095
                        Column: "name",
3✔
4096
                        Type:   VarcharType,
3✔
4097
                },
3✔
4098
                {
3✔
4099
                        Column: "type",
3✔
4100
                        Type:   VarcharType,
3✔
4101
                },
3✔
4102
                {
3✔
4103
                        Column: "max_length",
3✔
4104
                        Type:   IntegerType,
3✔
4105
                },
3✔
4106
                {
3✔
4107
                        Column: "nullable",
3✔
4108
                        Type:   BooleanType,
3✔
4109
                },
3✔
4110
                {
3✔
4111
                        Column: "auto_increment",
3✔
4112
                        Type:   BooleanType,
3✔
4113
                },
3✔
4114
                {
3✔
4115
                        Column: "indexed",
3✔
4116
                        Type:   BooleanType,
3✔
4117
                },
3✔
4118
                {
3✔
4119
                        Column: "primary",
3✔
4120
                        Type:   BooleanType,
3✔
4121
                },
3✔
4122
                {
3✔
4123
                        Column: "unique",
3✔
4124
                        Type:   BooleanType,
3✔
4125
                },
3✔
4126
        }
3✔
4127

3✔
4128
        val, err := stmt.fnCall.params[0].substitute(params)
3✔
4129
        if err != nil {
3✔
4130
                return nil, err
×
4131
        }
×
4132

4133
        tableName, err := val.reduce(tx, nil, "")
3✔
4134
        if err != nil {
3✔
4135
                return nil, err
×
4136
        }
×
4137

4138
        if tableName.Type() != VarcharType {
3✔
4139
                return nil, fmt.Errorf("%w: expected '%s' for table name but type '%s' given instead", ErrIllegalArguments, VarcharType, tableName.Type())
×
4140
        }
×
4141

4142
        table, err := tx.catalog.GetTableByName(tableName.RawValue().(string))
3✔
4143
        if err != nil {
3✔
4144
                return nil, err
×
4145
        }
×
4146

4147
        values := make([][]ValueExp, len(table.cols))
3✔
4148

3✔
4149
        for i, c := range table.cols {
11✔
4150
                indexed, err := table.IsIndexed(c.Name())
8✔
4151
                if err != nil {
8✔
4152
                        return nil, err
×
4153
                }
×
4154

4155
                var unique bool
8✔
4156
                for _, index := range table.indexesByColID[c.id] {
16✔
4157
                        if index.IsUnique() && len(index.Cols()) == 1 {
11✔
4158
                                unique = true
3✔
4159
                                break
3✔
4160
                        }
4161
                }
4162

4163
                values[i] = []ValueExp{
8✔
4164
                        &Varchar{val: table.name},
8✔
4165
                        &Varchar{val: c.colName},
8✔
4166
                        &Varchar{val: c.colType},
8✔
4167
                        &Integer{val: int64(c.MaxLen())},
8✔
4168
                        &Bool{val: c.IsNullable()},
8✔
4169
                        &Bool{val: c.autoIncrement},
8✔
4170
                        &Bool{val: indexed},
8✔
4171
                        &Bool{val: table.PrimaryIndex().IncludesCol(c.ID())},
8✔
4172
                        &Bool{val: unique},
8✔
4173
                }
8✔
4174
        }
4175

4176
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
3✔
4177
}
4178

4179
func (stmt *FnDataSourceStmt) resolveListIndexes(ctx context.Context, tx *SQLTx, params map[string]interface{}, _ *ScanSpecs) (RowReader, error) {
3✔
4180
        if len(stmt.fnCall.params) != 1 {
3✔
4181
                return nil, fmt.Errorf("%w: function '%s' expect table name as parameter", ErrIllegalArguments, IndexesFnCall)
×
4182
        }
×
4183

4184
        cols := []ColDescriptor{
3✔
4185
                {
3✔
4186
                        Column: "table",
3✔
4187
                        Type:   VarcharType,
3✔
4188
                },
3✔
4189
                {
3✔
4190
                        Column: "name",
3✔
4191
                        Type:   VarcharType,
3✔
4192
                },
3✔
4193
                {
3✔
4194
                        Column: "unique",
3✔
4195
                        Type:   BooleanType,
3✔
4196
                },
3✔
4197
                {
3✔
4198
                        Column: "primary",
3✔
4199
                        Type:   BooleanType,
3✔
4200
                },
3✔
4201
        }
3✔
4202

3✔
4203
        val, err := stmt.fnCall.params[0].substitute(params)
3✔
4204
        if err != nil {
3✔
4205
                return nil, err
×
4206
        }
×
4207

4208
        tableName, err := val.reduce(tx, nil, "")
3✔
4209
        if err != nil {
3✔
4210
                return nil, err
×
4211
        }
×
4212

4213
        if tableName.Type() != VarcharType {
3✔
4214
                return nil, fmt.Errorf("%w: expected '%s' for table name but type '%s' given instead", ErrIllegalArguments, VarcharType, tableName.Type())
×
4215
        }
×
4216

4217
        table, err := tx.catalog.GetTableByName(tableName.RawValue().(string))
3✔
4218
        if err != nil {
3✔
4219
                return nil, err
×
4220
        }
×
4221

4222
        values := make([][]ValueExp, len(table.indexes))
3✔
4223

3✔
4224
        for i, index := range table.indexes {
10✔
4225
                values[i] = []ValueExp{
7✔
4226
                        &Varchar{val: table.name},
7✔
4227
                        &Varchar{val: index.Name()},
7✔
4228
                        &Bool{val: index.unique},
7✔
4229
                        &Bool{val: index.IsPrimary()},
7✔
4230
                }
7✔
4231
        }
7✔
4232

4233
        return newValuesRowReader(tx, params, cols, stmt.Alias(), values)
3✔
4234
}
4235

4236
// DropTableStmt represents a statement to delete a table.
4237
type DropTableStmt struct {
4238
        table string
4239
}
4240

4241
func NewDropTableStmt(table string) *DropTableStmt {
6✔
4242
        return &DropTableStmt{table: table}
6✔
4243
}
6✔
4244

4245
func (stmt *DropTableStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
×
4246
        return nil
×
4247
}
×
4248

4249
/*
4250
Exec executes the delete table statement.
4251
It the table exists, if not it does nothing.
4252
If the table exists, it deletes all the indexes and the table itself.
4253
Note that this is a soft delete of the index and table key,
4254
the data is not deleted, but the metadata is updated.
4255
*/
4256
func (stmt *DropTableStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
6✔
4257
        if !tx.catalog.ExistTable(stmt.table) {
6✔
4258
                return nil, ErrTableDoesNotExist
×
4259
        }
×
4260

4261
        table, err := tx.catalog.GetTableByName(stmt.table)
6✔
4262
        if err != nil {
6✔
4263
                return nil, err
×
4264
        }
×
4265

4266
        // delete table
4267
        mappedKey := MapKey(
6✔
4268
                tx.sqlPrefix(),
6✔
4269
                catalogTablePrefix,
6✔
4270
                EncodeID(DatabaseID),
6✔
4271
                EncodeID(table.id),
6✔
4272
        )
6✔
4273
        err = tx.delete(ctx, mappedKey)
6✔
4274
        if err != nil {
6✔
4275
                return nil, err
×
4276
        }
×
4277

4278
        // delete columns
4279
        cols := table.ColumnsByID()
6✔
4280
        for _, col := range cols {
26✔
4281
                mappedKey := MapKey(
20✔
4282
                        tx.sqlPrefix(),
20✔
4283
                        catalogColumnPrefix,
20✔
4284
                        EncodeID(DatabaseID),
20✔
4285
                        EncodeID(col.table.id),
20✔
4286
                        EncodeID(col.id),
20✔
4287
                        []byte(col.colType),
20✔
4288
                )
20✔
4289
                err = tx.delete(ctx, mappedKey)
20✔
4290
                if err != nil {
20✔
4291
                        return nil, err
×
4292
                }
×
4293
        }
4294

4295
        // delete indexes
4296
        for _, index := range table.indexes {
13✔
4297
                mappedKey := MapKey(
7✔
4298
                        tx.sqlPrefix(),
7✔
4299
                        catalogIndexPrefix,
7✔
4300
                        EncodeID(DatabaseID),
7✔
4301
                        EncodeID(table.id),
7✔
4302
                        EncodeID(index.id),
7✔
4303
                )
7✔
4304
                err = tx.delete(ctx, mappedKey)
7✔
4305
                if err != nil {
7✔
4306
                        return nil, err
×
4307
                }
×
4308

4309
                indexKey := MapKey(
7✔
4310
                        tx.sqlPrefix(),
7✔
4311
                        MappedPrefix,
7✔
4312
                        EncodeID(table.id),
7✔
4313
                        EncodeID(index.id),
7✔
4314
                )
7✔
4315
                err = tx.addOnCommittedCallback(func(sqlTx *SQLTx) error {
14✔
4316
                        return sqlTx.engine.store.DeleteIndex(indexKey)
7✔
4317
                })
7✔
4318
                if err != nil {
7✔
4319
                        return nil, err
×
4320
                }
×
4321
        }
4322

4323
        err = tx.catalog.deleteTable(table)
6✔
4324
        if err != nil {
6✔
4325
                return nil, err
×
4326
        }
×
4327

4328
        tx.mutatedCatalog = true
6✔
4329

6✔
4330
        return tx, nil
6✔
4331
}
4332

4333
// DropIndexStmt represents a statement to delete a table.
4334
type DropIndexStmt struct {
4335
        table string
4336
        cols  []string
4337
}
4338

4339
func NewDropIndexStmt(table string, cols []string) *DropIndexStmt {
4✔
4340
        return &DropIndexStmt{table: table, cols: cols}
4✔
4341
}
4✔
4342

4343
func (stmt *DropIndexStmt) inferParameters(ctx context.Context, tx *SQLTx, params map[string]SQLValueType) error {
×
4344
        return nil
×
4345
}
×
4346

4347
/*
4348
Exec executes the delete index statement.
4349
If the index exists, it deletes it. Note that this is a soft delete of the index
4350
the data is not deleted, but the metadata is updated.
4351
*/
4352
func (stmt *DropIndexStmt) execAt(ctx context.Context, tx *SQLTx, params map[string]interface{}) (*SQLTx, error) {
5✔
4353
        if !tx.catalog.ExistTable(stmt.table) {
5✔
4354
                return nil, ErrTableDoesNotExist
×
4355
        }
×
4356

4357
        table, err := tx.catalog.GetTableByName(stmt.table)
5✔
4358
        if err != nil {
5✔
4359
                return nil, err
×
4360
        }
×
4361

4362
        cols := make([]*Column, len(stmt.cols))
5✔
4363

5✔
4364
        for i, colName := range stmt.cols {
10✔
4365
                col, err := table.GetColumnByName(colName)
5✔
4366
                if err != nil {
5✔
4367
                        return nil, err
×
4368
                }
×
4369

4370
                cols[i] = col
5✔
4371
        }
4372

4373
        index, err := table.GetIndexByName(indexName(table.name, cols))
5✔
4374
        if err != nil {
5✔
4375
                return nil, err
×
4376
        }
×
4377

4378
        // delete index
4379
        mappedKey := MapKey(
5✔
4380
                tx.sqlPrefix(),
5✔
4381
                catalogIndexPrefix,
5✔
4382
                EncodeID(DatabaseID),
5✔
4383
                EncodeID(table.id),
5✔
4384
                EncodeID(index.id),
5✔
4385
        )
5✔
4386
        err = tx.delete(ctx, mappedKey)
5✔
4387
        if err != nil {
5✔
4388
                return nil, err
×
4389
        }
×
4390

4391
        indexKey := MapKey(
5✔
4392
                tx.sqlPrefix(),
5✔
4393
                MappedPrefix,
5✔
4394
                EncodeID(table.id),
5✔
4395
                EncodeID(index.id),
5✔
4396
        )
5✔
4397

5✔
4398
        err = tx.addOnCommittedCallback(func(sqlTx *SQLTx) error {
9✔
4399
                return sqlTx.engine.store.DeleteIndex(indexKey)
4✔
4400
        })
4✔
4401
        if err != nil {
5✔
4402
                return nil, err
×
4403
        }
×
4404

4405
        err = table.deleteIndex(index)
5✔
4406
        if err != nil {
6✔
4407
                return nil, err
1✔
4408
        }
1✔
4409

4410
        tx.mutatedCatalog = true
4✔
4411

4✔
4412
        return tx, nil
4✔
4413
}
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