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

codenotary / immudb / 18752576117

23 Oct 2025 02:55PM UTC coverage: 89.257% (+0.01%) from 89.247%
18752576117

Pull #2076

gh-ci

els-tmiller
enable fargate credentials

Signed-off-by: Tim Miller <tim.miller@elsevier.com>
Pull Request #2076: S3 Storage - Fargate Credentials

452 of 493 new or added lines in 8 files covered. (91.68%)

412 existing lines in 4 files now uncovered.

37970 of 42540 relevant lines covered (89.26%)

149626.95 hits per line

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

83.21
/embedded/sql/parser.go
1
/*
2
Copyright 2025 Codenotary Inc. All rights reserved.
3

4
SPDX-License-Identifier: BUSL-1.1
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    https://mariadb.com/bsl11/
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package sql
18

19
import (
20
        "bytes"
21
        "encoding/hex"
22
        "errors"
23
        "fmt"
24
        "io"
25
        "strconv"
26
        "strings"
27
)
28

29
//go:generate go run golang.org/x/tools/cmd/goyacc -l -o sql_parser.go sql_grammar.y
30

31
var keywords = map[string]int{
32
        "CREATE":         CREATE,
33
        "DROP":           DROP,
34
        "USE":            USE,
35
        "DATABASE":       DATABASE,
36
        "SNAPSHOT":       SNAPSHOT,
37
        "HISTORY":        HISTORY,
38
        "OF":             OF,
39
        "SINCE":          SINCE,
40
        "AFTER":          AFTER,
41
        "BEFORE":         BEFORE,
42
        "UNTIL":          UNTIL,
43
        "TABLE":          TABLE,
44
        "PRIMARY":        PRIMARY,
45
        "KEY":            KEY,
46
        "UNIQUE":         UNIQUE,
47
        "INDEX":          INDEX,
48
        "ON":             ON,
49
        "ALTER":          ALTER,
50
        "ADD":            ADD,
51
        "RENAME":         RENAME,
52
        "TO":             TO,
53
        "COLUMN":         COLUMN,
54
        "INSERT":         INSERT,
55
        "CONFLICT":       CONFLICT,
56
        "DO":             DO,
57
        "NOTHING":        NOTHING,
58
        "RETURNING":      RETURNING,
59
        "UPSERT":         UPSERT,
60
        "INTO":           INTO,
61
        "VALUES":         VALUES,
62
        "UPDATE":         UPDATE,
63
        "SET":            SET,
64
        "DELETE":         DELETE,
65
        "BEGIN":          BEGIN,
66
        "TRANSACTION":    TRANSACTION,
67
        "COMMIT":         COMMIT,
68
        "ROLLBACK":       ROLLBACK,
69
        "SELECT":         SELECT,
70
        "DISTINCT":       DISTINCT,
71
        "FROM":           FROM,
72
        "UNION":          UNION,
73
        "ALL":            ALL,
74
        "TX":             TX,
75
        "JOIN":           JOIN,
76
        "HAVING":         HAVING,
77
        "WHERE":          WHERE,
78
        "GROUP":          GROUP,
79
        "BY":             BY,
80
        "LIMIT":          LIMIT,
81
        "OFFSET":         OFFSET,
82
        "ORDER":          ORDER,
83
        "AS":             AS,
84
        "ASC":            ASC,
85
        "DESC":           DESC,
86
        "AND":            AND,
87
        "OR":             OR,
88
        "NOT":            NOT,
89
        "LIKE":           LIKE,
90
        "EXISTS":         EXISTS,
91
        "BETWEEN":        BETWEEN,
92
        "IN":             IN,
93
        "AUTO_INCREMENT": AUTO_INCREMENT,
94
        "NULL":           NULL,
95
        "IF":             IF,
96
        "IS":             IS,
97
        "CAST":           CAST,
98
        "::":             SCAST,
99
        "SHOW":           SHOW,
100
        "DATABASES":      DATABASES,
101
        "TABLES":         TABLES,
102
        "USERS":          USERS,
103
        "USER":           USER,
104
        "WITH":           WITH,
105
        "PASSWORD":       PASSWORD,
106
        "READ":           READ,
107
        "READWRITE":      READWRITE,
108
        "ADMIN":          ADMIN,
109
        "GRANT":          GRANT,
110
        "REVOKE":         REVOKE,
111
        "GRANTS":         GRANTS,
112
        "FOR":            FOR,
113
        "PRIVILEGES":     PRIVILEGES,
114
        "CHECK":          CHECK,
115
        "CONSTRAINT":     CONSTRAINT,
116
        "CASE":           CASE,
117
        "WHEN":           WHEN,
118
        "THEN":           THEN,
119
        "ELSE":           ELSE,
120
        "END":            END,
121
        "EXTRACT":        EXTRACT,
122
        "INTEGER":        INTEGER_TYPE,
123
        "BOOLEAN":        BOOLEAN_TYPE,
124
        "VARCHAR":        VARCHAR_TYPE,
125
        "TIMESTAMP":      TIMESTAMP_TYPE,
126
        "FLOAT":          FLOAT_TYPE,
127
        "BLOB":           BLOB_TYPE,
128
        "UUID":           UUID_TYPE,
129
        "JSON":           JSON_TYPE,
130
        "YEAR":           YEAR,
131
        "MONTH":          MONTH,
132
        "DAY":            DAY,
133
        "HOUR":           HOUR,
134
        "MINUTE":         MINUTE,
135
        "SECOND":         SECOND,
136
}
137

138
var joinTypes = map[string]JoinType{
139
        "INNER": InnerJoin,
140
        "LEFT":  LeftJoin,
141
        "RIGHT": RightJoin,
142
}
143

144
var aggregateFns = map[string]AggregateFn{
145
        "COUNT": COUNT,
146
        "SUM":   SUM,
147
        "MAX":   MAX,
148
        "MIN":   MIN,
149
        "AVG":   AVG,
150
}
151

152
var boolValues = map[string]bool{
153
        "TRUE":  true,
154
        "FALSE": false,
155
}
156

157
var cmpOps = map[string]CmpOperator{
158
        "=":  EQ,
159
        "!=": NE,
160
        "<>": NE,
161
        "<":  LT,
162
        "<=": LE,
163
        ">":  GT,
164
        ">=": GE,
165
}
166

167
var ErrEitherNamedOrUnnamedParams = errors.New("either named or unnamed params")
168
var ErrEitherPosOrNonPosParams = errors.New("either positional or non-positional named params")
169
var ErrInvalidPositionalParameter = errors.New("invalid positional parameter")
170

171
type positionalParamType int
172

173
const (
174
        NamedNonPositionalParamType positionalParamType = iota + 1
175
        NamedPositionalParamType
176
        UnnamedParamType
177
)
178

179
type lexer struct {
180
        r               *aheadByteReader
181
        err             error
182
        namedParamsType positionalParamType
183
        paramsCount     int
184
        result          []SQLStmt
185
}
186

187
type aheadByteReader struct {
188
        nextChar  byte
189
        nextErr   error
190
        r         io.ByteReader
191
        readCount int
192
}
193

194
func newAheadByteReader(r io.ByteReader) *aheadByteReader {
4,308✔
195
        ar := &aheadByteReader{r: r}
4,308✔
196
        ar.nextChar, ar.nextErr = r.ReadByte()
4,308✔
197
        return ar
4,308✔
198
}
4,308✔
199

200
func (ar *aheadByteReader) ReadByte() (byte, error) {
310,754✔
201
        defer func() {
621,508✔
202
                if ar.nextErr == nil {
617,447✔
203
                        ar.nextChar, ar.nextErr = ar.r.ReadByte()
306,693✔
204
                }
306,693✔
205
        }()
206

207
        ar.readCount++
310,754✔
208

310,754✔
209
        return ar.nextChar, ar.nextErr
310,754✔
210
}
211

212
func (ar *aheadByteReader) ReadCount() int {
151✔
213
        return ar.readCount
151✔
214
}
151✔
215

216
func (ar *aheadByteReader) NextByte() (byte, error) {
246,911✔
217
        return ar.nextChar, ar.nextErr
246,911✔
218
}
246,911✔
219

220
func ParseSQLString(sql string) ([]SQLStmt, error) {
1,150✔
221
        return ParseSQL(strings.NewReader(sql))
1,150✔
222
}
1,150✔
223

224
func ParseSQL(r io.ByteReader) ([]SQLStmt, error) {
4,308✔
225
        lexer := newLexer(r)
4,308✔
226

4,308✔
227
        yyParse(lexer)
4,308✔
228

4,308✔
229
        return lexer.result, lexer.err
4,308✔
230
}
4,308✔
231

232
func ParseExpFromString(exp string) (ValueExp, error) {
216✔
233
        stmt := fmt.Sprintf("SELECT * FROM t WHERE %s", exp)
216✔
234

216✔
235
        res, err := ParseSQLString(stmt)
216✔
236
        if err != nil {
216✔
UNCOV
237
                return nil, err
×
UNCOV
238
        }
×
239

240
        s := res[0].(*SelectStmt)
216✔
241
        return s.where, nil
216✔
242
}
243

244
func newLexer(r io.ByteReader) *lexer {
4,308✔
245
        return &lexer{
4,308✔
246
                r:   newAheadByteReader(r),
4,308✔
247
                err: nil,
4,308✔
248
        }
4,308✔
249
}
4,308✔
250

251
func (l *lexer) Lex(lval *yySymType) int {
69,139✔
252
        var ch byte
69,139✔
253
        var err error
69,139✔
254

69,139✔
255
        for {
177,617✔
256
                ch, err = l.r.ReadByte()
108,478✔
257
                if err == io.EOF {
112,539✔
258
                        return 0
4,061✔
259
                }
4,061✔
260
                if err != nil {
104,417✔
UNCOV
261
                        lval.err = err
×
UNCOV
262
                        return ERROR
×
UNCOV
263
                }
×
264

265
                if ch == '\t' {
108,930✔
266
                        continue
4,513✔
267
                }
268

269
                if ch == '/' && l.r.nextChar == '*' {
99,907✔
270
                        l.r.ReadByte()
3✔
271

3✔
272
                        for {
102✔
273
                                ch, err := l.r.ReadByte()
99✔
274
                                if err == io.EOF {
99✔
UNCOV
275
                                        break
×
276
                                }
277
                                if err != nil {
99✔
UNCOV
278
                                        lval.err = err
×
279
                                        return ERROR
×
UNCOV
280
                                }
×
281

282
                                if ch == '*' && l.r.nextChar == '/' {
102✔
283
                                        l.r.ReadByte() // consume closing slash
3✔
284
                                        break
3✔
285
                                }
286
                        }
287

288
                        continue
3✔
289
                }
290

291
                if isLineBreak(ch) {
101,237✔
292
                        if ch == '\r' && l.r.nextChar == '\n' {
1,337✔
293
                                l.r.ReadByte()
1✔
294
                        }
1✔
295
                        continue
1,336✔
296
                }
297

298
                if !isSpace(ch) {
163,643✔
299
                        break
65,078✔
300
                }
301
        }
302

303
        if isSeparator(ch) {
65,559✔
304
                return STMT_SEPARATOR
481✔
305
        }
481✔
306

307
        if ch == '-' && l.r.nextChar == '>' {
64,655✔
308
                l.r.ReadByte()
58✔
309
                return ARROW
58✔
310
        }
58✔
311

312
        if isBLOBPrefix(ch) && isQuote(l.r.nextChar) {
64,633✔
313
                l.r.ReadByte() // consume starting quote
94✔
314

94✔
315
                tail, err := l.readString()
94✔
316
                if err != nil {
94✔
UNCOV
317
                        lval.err = err
×
UNCOV
318
                        return ERROR
×
UNCOV
319
                }
×
320

321
                val, err := hex.DecodeString(tail)
94✔
322
                if err != nil {
94✔
323
                        lval.err = err
×
UNCOV
324
                        return ERROR
×
UNCOV
325
                }
×
326

327
                lval.blob = val
94✔
328
                return BLOB_LIT
94✔
329
        }
330

331
        if isLetter(ch) {
95,901✔
332
                tail, err := l.readWord()
31,456✔
333
                if err != nil {
31,456✔
UNCOV
334
                        lval.err = err
×
UNCOV
335
                        return ERROR
×
UNCOV
336
                }
×
337

338
                w := fmt.Sprintf("%c%s", ch, tail)
31,456✔
339
                tid := strings.ToUpper(w)
31,456✔
340

31,456✔
341
                val, ok := boolValues[tid]
31,456✔
342
                if ok {
31,700✔
343
                        lval.boolean = val
244✔
344
                        return BOOLEAN_LIT
244✔
345
                }
244✔
346

347
                afn, ok := aggregateFns[tid]
31,212✔
348
                if ok {
31,345✔
349
                        lval.aggFn = afn
133✔
350
                        return AGGREGATE_FUNC
133✔
351
                }
133✔
352

353
                join, ok := joinTypes[tid]
31,079✔
354
                if ok {
31,100✔
355
                        lval.joinType = join
21✔
356
                        return JOINTYPE
21✔
357
                }
21✔
358

359
                tkn, ok := keywords[tid]
31,058✔
360
                if ok {
48,130✔
361
                        lval.keyword = w
17,072✔
362
                        return tkn
17,072✔
363
                }
17,072✔
364

365
                lval.id = strings.ToLower(w)
13,986✔
366
                return IDENTIFIER
13,986✔
367
        }
368

369
        if isDoubleQuote(ch) {
32,996✔
370
                tail, err := l.readWord()
7✔
371
                if err != nil {
7✔
372
                        lval.err = err
×
UNCOV
373
                        return ERROR
×
UNCOV
374
                }
×
375

376
                if !isDoubleQuote(l.r.nextChar) {
8✔
377
                        lval.err = fmt.Errorf("double quote expected")
1✔
378
                        return ERROR
1✔
379
                }
1✔
380

381
                l.r.ReadByte() // consume ending quote
6✔
382

6✔
383
                lval.id = strings.ToLower(tail)
6✔
384
                return IDENTIFIER
6✔
385
        }
386

387
        if isNumber(ch) {
34,052✔
388
                tail, err := l.readNumber()
1,070✔
389
                if err != nil {
1,070✔
390
                        lval.err = err
×
UNCOV
391
                        return ERROR
×
UNCOV
392
                }
×
393
                // looking for a float
394
                if isDot(l.r.nextChar) {
1,136✔
395
                        l.r.ReadByte() // consume dot
66✔
396

66✔
397
                        decimalPart, err := l.readNumber()
66✔
398
                        if err != nil {
66✔
399
                                lval.err = err
×
UNCOV
400
                                return ERROR
×
UNCOV
401
                        }
×
402

403
                        val, err := strconv.ParseFloat(fmt.Sprintf("%c%s.%s", ch, tail, decimalPart), 64)
66✔
404
                        if err != nil {
67✔
405
                                lval.err = err
1✔
406
                                return ERROR
1✔
407
                        }
1✔
408

409
                        lval.float = val
65✔
410
                        return FLOAT_LIT
65✔
411
                }
412

413
                val, err := strconv.ParseUint(fmt.Sprintf("%c%s", ch, tail), 10, 64)
1,004✔
414
                if err != nil {
1,004✔
415
                        lval.err = err
×
UNCOV
416
                        return ERROR
×
UNCOV
417
                }
×
418

419
                lval.integer = val
1,004✔
420
                return INTEGER_LIT
1,004✔
421
        }
422

423
        if isComparison(ch) {
32,385✔
424
                tail, err := l.readComparison()
473✔
425
                if err != nil {
473✔
426
                        lval.err = err
×
UNCOV
427
                        return ERROR
×
UNCOV
428
                }
×
429

430
                op := fmt.Sprintf("%c%s", ch, tail)
473✔
431
                if op == "!~" {
474✔
432
                        return NOT_MATCHES_OP
1✔
433
                }
1✔
434

435
                cmpOp, ok := cmpOps[op]
472✔
436
                if !ok {
472✔
437
                        lval.err = fmt.Errorf("invalid comparison operator %s", op)
×
UNCOV
438
                        return ERROR
×
UNCOV
439
                }
×
440

441
                lval.cmpOp = cmpOp
472✔
442
                return CMPOP
472✔
443
        }
444

445
        if isQuote(ch) {
32,334✔
446
                tail, err := l.readString()
895✔
447
                if err != nil {
895✔
448
                        lval.err = err
×
UNCOV
449
                        return ERROR
×
UNCOV
450
                }
×
451

452
                lval.str = tail
895✔
453
                return VARCHAR_LIT
895✔
454
        }
455

456
        if ch == ':' {
30,570✔
457
                ch, err := l.r.ReadByte()
26✔
458
                if err != nil {
26✔
459
                        lval.err = err
×
UNCOV
460
                        return ERROR
×
UNCOV
461
                }
×
462

463
                if ch != ':' {
26✔
464
                        lval.err = fmt.Errorf("colon expected")
×
UNCOV
465
                        return ERROR
×
UNCOV
466
                }
×
467

468
                return SCAST
26✔
469
        }
470

471
        if ch == '@' {
36,458✔
472
                if l.namedParamsType == UnnamedParamType {
5,941✔
473
                        lval.err = ErrEitherNamedOrUnnamedParams
1✔
474
                        return ERROR
1✔
475
                }
1✔
476

477
                if l.namedParamsType == NamedPositionalParamType {
5,940✔
478
                        lval.err = ErrEitherPosOrNonPosParams
1✔
479
                        return ERROR
1✔
480
                }
1✔
481

482
                l.namedParamsType = NamedNonPositionalParamType
5,938✔
483

5,938✔
484
                ch, err := l.r.NextByte()
5,938✔
485
                if err != nil {
5,938✔
486
                        lval.err = err
×
UNCOV
487
                        return ERROR
×
UNCOV
488
                }
×
489

490
                if !isLetter(ch) {
5,938✔
UNCOV
491
                        return ERROR
×
UNCOV
492
                }
×
493

494
                id, err := l.readWord()
5,938✔
495
                if err != nil {
5,938✔
496
                        lval.err = err
×
UNCOV
497
                        return ERROR
×
UNCOV
498
                }
×
499

500
                lval.id = strings.ToLower(id)
5,938✔
501

5,938✔
502
                return NPARAM
5,938✔
503
        }
504

505
        if ch == '$' {
24,620✔
506
                if l.namedParamsType == UnnamedParamType {
43✔
507
                        lval.err = ErrEitherNamedOrUnnamedParams
1✔
508
                        return ERROR
1✔
509
                }
1✔
510

511
                if l.namedParamsType == NamedNonPositionalParamType {
42✔
512
                        lval.err = ErrEitherPosOrNonPosParams
1✔
513
                        return ERROR
1✔
514
                }
1✔
515

516
                id, err := l.readNumber()
40✔
517
                if err != nil {
40✔
518
                        lval.err = err
×
UNCOV
519
                        return ERROR
×
UNCOV
520
                }
×
521

522
                pid, err := strconv.Atoi(id)
40✔
523
                if err != nil {
41✔
524
                        lval.err = err
1✔
525
                        return ERROR
1✔
526
                }
1✔
527

528
                if pid < 1 {
40✔
529
                        lval.err = ErrInvalidPositionalParameter
1✔
530
                        return ERROR
1✔
531
                }
1✔
532

533
                lval.pparam = pid
38✔
534

38✔
535
                l.namedParamsType = NamedPositionalParamType
38✔
536

38✔
537
                return PPARAM
38✔
538
        }
539

540
        if ch == '?' {
24,675✔
541
                if l.namedParamsType == NamedNonPositionalParamType || l.namedParamsType == NamedPositionalParamType {
141✔
542
                        lval.err = ErrEitherNamedOrUnnamedParams
2✔
543
                        return ERROR
2✔
544
                }
2✔
545

546
                l.paramsCount++
137✔
547
                lval.pparam = l.paramsCount
137✔
548

137✔
549
                l.namedParamsType = UnnamedParamType
137✔
550

137✔
551
                return PPARAM
137✔
552
        }
553

554
        if isDot(ch) {
24,625✔
555
                if isNumber(l.r.nextChar) { // looking for  a float
233✔
556
                        decimalPart, err := l.readNumber()
5✔
557
                        if err != nil {
5✔
558
                                lval.err = err
×
UNCOV
559
                                return ERROR
×
UNCOV
560
                        }
×
561
                        val, err := strconv.ParseFloat(fmt.Sprintf("%d.%s", 0, decimalPart), 64)
5✔
562
                        if err != nil {
5✔
563
                                lval.err = err
×
UNCOV
564
                                return ERROR
×
UNCOV
565
                        }
×
566
                        lval.float = val
5✔
567
                        return FLOAT_LIT
5✔
568
                }
569
                return DOT
223✔
570
        }
571

572
        return int(ch)
24,169✔
573
}
574

575
func (l *lexer) Error(err string) {
151✔
576
        l.err = fmt.Errorf("%s at position %d", err, l.r.ReadCount())
151✔
577
}
151✔
578

579
func (l *lexer) readWord() (string, error) {
37,401✔
580
        return l.readWhile(func(ch byte) bool {
239,617✔
581
                return isLetter(ch) || isNumber(ch)
202,216✔
582
        })
202,216✔
583
}
584

585
func (l *lexer) readNumber() (string, error) {
1,181✔
586
        return l.readWhile(isNumber)
1,181✔
587
}
1,181✔
588

589
func (l *lexer) readString() (string, error) {
989✔
590
        var b bytes.Buffer
989✔
591

989✔
592
        for {
26,468✔
593
                ch, err := l.r.ReadByte()
25,479✔
594
                if err != nil {
25,479✔
UNCOV
595
                        return "", err
×
UNCOV
596
                }
×
597

598
                nextCh, _ := l.r.NextByte()
25,479✔
599

25,479✔
600
                if isQuote(ch) {
26,470✔
601
                        if isQuote(nextCh) {
993✔
602
                                l.r.ReadByte() // consume escaped quote
2✔
603
                        } else {
991✔
604
                                break // string completely read
989✔
605
                        }
606
                }
607

608
                b.WriteByte(ch)
24,490✔
609
        }
610

611
        return b.String(), nil
989✔
612
}
613

614
func (l *lexer) readComparison() (string, error) {
473✔
615
        return l.readWhile(func(ch byte) bool {
1,086✔
616
                return isComparison(ch)
613✔
617
        })
613✔
618
}
619

620
func (l *lexer) readWhile(condFn func(b byte) bool) (string, error) {
39,055✔
621
        var b bytes.Buffer
39,055✔
622

39,055✔
623
        for {
254,549✔
624
                ch, err := l.r.NextByte()
215,494✔
625
                if err == io.EOF {
216,431✔
626
                        break
937✔
627
                }
628
                if err != nil {
214,557✔
UNCOV
629
                        return "", err
×
UNCOV
630
                }
×
631

632
                if !condFn(ch) {
252,675✔
633
                        break
38,118✔
634
                }
635

636
                ch, _ = l.r.ReadByte()
176,439✔
637
                b.WriteByte(ch)
176,439✔
638
        }
639

640
        return b.String(), nil
39,055✔
641
}
642

643
func isBLOBPrefix(ch byte) bool {
64,539✔
644
        return ch == 'x'
64,539✔
645
}
64,539✔
646

647
func isSeparator(ch byte) bool {
65,078✔
648
        return ch == ';'
65,078✔
649
}
65,078✔
650

651
func isLineBreak(ch byte) bool {
99,901✔
652
        return ch == '\r' || ch == '\n'
99,901✔
653
}
99,901✔
654

655
func isSpace(ch byte) bool {
98,565✔
656
        return ch == 32 || ch == 9 //SPACE or TAB
98,565✔
657
}
98,565✔
658

659
func isNumber(ch byte) bool {
84,452✔
660
        return '0' <= ch && ch <= '9'
84,452✔
661
}
84,452✔
662

663
func isLetter(ch byte) bool {
272,599✔
664
        return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_'
272,599✔
665
}
272,599✔
666

667
func isComparison(ch byte) bool {
32,525✔
668
        return ch == '!' || ch == '<' || ch == '=' || ch == '>' || ch == '~'
32,525✔
669
}
32,525✔
670

671
func isQuote(ch byte) bool {
58,006✔
672
        return ch == 0x27
58,006✔
673
}
58,006✔
674

675
func isDoubleQuote(ch byte) bool {
32,996✔
676
        return ch == 0x22
32,996✔
677
}
32,996✔
678

679
func isDot(ch byte) bool {
25,467✔
680
        return ch == '.'
25,467✔
681
}
25,467✔
682

683
func newCreateTableStmt(
684
        name string,
685
        elems []TableElem,
686
        ifNotExists bool,
687
) *CreateTableStmt {
294✔
688
        colsSpecs := make([]*ColSpec, 0, 5)
294✔
689
        var checks []CheckConstraint
294✔
690

294✔
691
        var pk PrimaryKeyConstraint
294✔
692
        for _, e := range elems {
1,188✔
693
                switch c := e.(type) {
894✔
694
                case *ColSpec:
670✔
695
                        colsSpecs = append(colsSpecs, c)
670✔
696
                case PrimaryKeyConstraint:
214✔
697
                        pk = c
214✔
698
                case CheckConstraint:
10✔
699
                        if checks == nil {
15✔
700
                                checks = make([]CheckConstraint, 0, 5)
5✔
701
                        }
5✔
702
                        checks = append(checks, c)
10✔
703
                }
704
        }
705

706
        return &CreateTableStmt{
294✔
707
                ifNotExists: ifNotExists,
294✔
708
                table:       name,
294✔
709
                colsSpec:    colsSpecs,
294✔
710
                pkColNames:  pk,
294✔
711
                checks:      checks,
294✔
712
        }
294✔
713
}
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