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

codenotary / immudb / 12273047947

11 Dec 2024 09:06AM UTC coverage: 89.286% (+0.02%) from 89.266%
12273047947

Pull #2036

gh-ci

ostafen
chore(embedded/sql): Add support for core pg_catalog tables (pg_class, pg_namespace, pg_roles)

Signed-off-by: Stefano Scafiti <stefano.scafiti96@gmail.com>
Pull Request #2036: chore(embedded/sql): Add support for core pg_catalog tables (pg_class…

160 of 184 new or added lines in 12 files covered. (86.96%)

1 existing line in 1 file now uncovered.

37641 of 42158 relevant lines covered (89.29%)

150814.99 hits per line

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

92.77
/embedded/sql/functions.go
1
/*
2
Copyright 2024 Codenotary Inc. All rights reserved.
3

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

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

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

17
package sql
18

19
import (
20
        "fmt"
21
        "strings"
22
        "time"
23

24
        "github.com/google/uuid"
25
)
26

27
const (
28
        LengthFnCall             string = "LENGTH"
29
        SubstringFnCall          string = "SUBSTRING"
30
        ConcatFnCall             string = "CONCAT"
31
        LowerFnCall              string = "LOWER"
32
        UpperFnCall              string = "UPPER"
33
        TrimFnCall               string = "TRIM"
34
        NowFnCall                string = "NOW"
35
        UUIDFnCall               string = "RANDOM_UUID"
36
        DatabasesFnCall          string = "DATABASES"
37
        TablesFnCall             string = "TABLES"
38
        TableFnCall              string = "TABLE"
39
        UsersFnCall              string = "USERS"
40
        ColumnsFnCall            string = "COLUMNS"
41
        IndexesFnCall            string = "INDEXES"
42
        GrantsFnCall             string = "GRANTS"
43
        JSONTypeOfFnCall         string = "JSON_TYPEOF"
44
        PGGetUserByIDFnCall      string = "PG_GET_USERBYID"
45
        PgTableIsVisibleFnCall   string = "PG_TABLE_IS_VISIBLE"
46
        PgShobjDescriptionFnCall string = "SHOBJ_DESCRIPTION"
47
)
48

49
var builtinFunctions = map[string]Function{
50
        LengthFnCall:             &LengthFn{},
51
        SubstringFnCall:          &SubstringFn{},
52
        ConcatFnCall:             &ConcatFn{},
53
        LowerFnCall:              &LowerUpperFnc{},
54
        UpperFnCall:              &LowerUpperFnc{isUpper: true},
55
        TrimFnCall:               &TrimFnc{},
56
        NowFnCall:                &NowFn{},
57
        UUIDFnCall:               &UUIDFn{},
58
        JSONTypeOfFnCall:         &JsonTypeOfFn{},
59
        PGGetUserByIDFnCall:      &pgGetUserByIDFunc{},
60
        PgTableIsVisibleFnCall:   &pgTableIsVisible{},
61
        PgShobjDescriptionFnCall: &pgShobjDescription{},
62
}
63

64
type Function interface {
65
        RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error
66
        InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error)
67
        Apply(tx *SQLTx, params []TypedValue) (TypedValue, error)
68
}
69

70
// -------------------------------------
71
// String Functions
72
// -------------------------------------
73

74
type LengthFn struct{}
75

76
func (f *LengthFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
77
        return IntegerType, nil
1✔
78
}
1✔
79

80
func (f *LengthFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
81
        if t != IntegerType {
3✔
82
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, IntegerType, t)
1✔
83
        }
1✔
84
        return nil
1✔
85
}
86

87
func (f *LengthFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
5✔
88
        if len(params) != 1 {
6✔
89
                return nil, fmt.Errorf("%w: '%s' function does expects one argument but %d were provided", ErrIllegalArguments, LengthFnCall, len(params))
1✔
90
        }
1✔
91

92
        v := params[0]
4✔
93
        if v.IsNull() {
5✔
94
                return &NullValue{t: IntegerType}, nil
1✔
95
        }
1✔
96

97
        if v.Type() != VarcharType {
4✔
98
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type %s", ErrIllegalArguments, LengthFnCall, VarcharType)
1✔
99
        }
1✔
100

101
        s, _ := v.RawValue().(string)
2✔
102
        return &Integer{val: int64(len(s))}, nil
2✔
103
}
104

105
type ConcatFn struct{}
106

107
func (f *ConcatFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
108
        return VarcharType, nil
1✔
109
}
1✔
110

111
func (f *ConcatFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
112
        if t != VarcharType {
3✔
113
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
114
        }
1✔
115
        return nil
1✔
116
}
117

118
func (f *ConcatFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
119
        if len(params) == 0 {
5✔
120
                return nil, fmt.Errorf("%w: '%s' function does expects at least one argument", ErrIllegalArguments, ConcatFnCall)
1✔
121
        }
1✔
122

123
        for _, v := range params {
14✔
124
                if v.Type() != AnyType && v.Type() != VarcharType {
12✔
125
                        return nil, fmt.Errorf("%w: '%s' function doesn't accept arguments of type %s", ErrIllegalArguments, ConcatFnCall, v.Type())
1✔
126
                }
1✔
127
        }
128

129
        var builder strings.Builder
2✔
130
        for _, v := range params {
10✔
131
                s, _ := v.RawValue().(string)
8✔
132
                builder.WriteString(s)
8✔
133
        }
8✔
134
        return &Varchar{val: builder.String()}, nil
2✔
135
}
136

137
type SubstringFn struct {
138
}
139

140
func (f *SubstringFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
141
        return VarcharType, nil
1✔
142
}
1✔
143

144
func (f *SubstringFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
145
        if t != VarcharType {
3✔
146
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
147
        }
1✔
148
        return nil
1✔
149
}
150

151
func (f *SubstringFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
7✔
152
        if len(params) != 3 {
8✔
153
                return nil, fmt.Errorf("%w: '%s' function does expects three argument but %d were provided", ErrIllegalArguments, SubstringFnCall, len(params))
1✔
154
        }
1✔
155

156
        v1, v2, v3 := params[0], params[1], params[2]
6✔
157

6✔
158
        if v1.IsNull() || v2.IsNull() || v3.IsNull() {
7✔
159
                return &NullValue{t: VarcharType}, nil
1✔
160
        }
1✔
161

162
        s, _ := v1.RawValue().(string)
5✔
163
        pos, _ := v2.RawValue().(int64)
5✔
164
        length, _ := v3.RawValue().(int64)
5✔
165

5✔
166
        if pos <= 0 {
6✔
167
                return nil, fmt.Errorf("%w: parameter 'position' must be greater than zero", ErrIllegalArguments)
1✔
168
        }
1✔
169

170
        if length < 0 {
5✔
171
                return nil, fmt.Errorf("%w: parameter 'length' cannot be negative", ErrIllegalArguments)
1✔
172
        }
1✔
173

174
        if pos-1 >= int64(len(s)) {
3✔
175
                return &Varchar{val: ""}, nil
×
176
        }
×
177

178
        end := pos - 1 + length
3✔
179
        if end > int64(len(s)) {
4✔
180
                end = int64(len(s))
1✔
181
        }
1✔
182
        return &Varchar{val: s[pos-1 : end]}, nil
3✔
183
}
184

185
type LowerUpperFnc struct {
186
        isUpper bool
187
}
188

189
func (f *LowerUpperFnc) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
2✔
190
        return VarcharType, nil
2✔
191
}
2✔
192

193
func (f *LowerUpperFnc) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
3✔
194
        if t != VarcharType {
4✔
195
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
196
        }
1✔
197
        return nil
2✔
198
}
199

200
func (f *LowerUpperFnc) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
6✔
201
        if len(params) != 1 {
7✔
202
                return nil, fmt.Errorf("%w: '%s' function does expects one argument but %d were provided", ErrIllegalArguments, f.name(), len(params))
1✔
203
        }
1✔
204

205
        v := params[0]
5✔
206
        if v.IsNull() {
7✔
207
                return &NullValue{t: VarcharType}, nil
2✔
208
        }
2✔
209

210
        if v.Type() != VarcharType {
4✔
211
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type %s", ErrIllegalArguments, f.name(), VarcharType)
1✔
212
        }
1✔
213

214
        s, _ := v.RawValue().(string)
2✔
215

2✔
216
        var res string
2✔
217
        if f.isUpper {
3✔
218
                res = strings.ToUpper(s)
1✔
219
        } else {
2✔
220
                res = strings.ToLower(s)
1✔
221
        }
1✔
222
        return &Varchar{val: res}, nil
2✔
223
}
224

225
func (f *LowerUpperFnc) name() string {
2✔
226
        if f.isUpper {
3✔
227
                return UpperFnCall
1✔
228
        }
1✔
229
        return LowerFnCall
1✔
230
}
231

232
type TrimFnc struct {
233
}
234

235
func (f *TrimFnc) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
236
        return VarcharType, nil
1✔
237
}
1✔
238

239
func (f *TrimFnc) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
240
        if t != VarcharType {
3✔
241
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
242
        }
1✔
243
        return nil
1✔
244
}
245

246
func (f *TrimFnc) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
4✔
247
        if len(params) != 1 {
5✔
248
                return nil, fmt.Errorf("%w: '%s' function does expects one argument but %d were provided", ErrIllegalArguments, TrimFnCall, len(params))
1✔
249
        }
1✔
250

251
        v := params[0]
3✔
252
        if v.IsNull() {
4✔
253
                return &NullValue{t: VarcharType}, nil
1✔
254
        }
1✔
255

256
        if v.Type() != VarcharType {
3✔
257
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type %s", ErrIllegalArguments, TrimFnCall, VarcharType)
1✔
258
        }
1✔
259

260
        s, _ := v.RawValue().(string)
1✔
261
        return &Varchar{val: strings.Trim(s, " \t\n\r\v\f")}, nil
1✔
262
}
263

264
// -------------------------------------
265
// Time Functions
266
// -------------------------------------
267

268
type NowFn struct{}
269

270
func (f *NowFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
14✔
271
        return TimestampType, nil
14✔
272
}
14✔
273

274
func (f *NowFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
275
        if t != TimestampType {
3✔
276
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, TimestampType, t)
1✔
277
        }
1✔
278
        return nil
1✔
279
}
280

281
func (f *NowFn) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
97✔
282
        if len(params) > 0 {
98✔
283
                return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, NowFnCall, len(params))
1✔
284
        }
1✔
285
        return &Timestamp{val: tx.Timestamp().Truncate(time.Microsecond).UTC()}, nil
96✔
286
}
287

288
// -------------------------------------
289
// JSON Functions
290
// -------------------------------------
291

292
type JsonTypeOfFn struct{}
293

294
func (f *JsonTypeOfFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
295
        return VarcharType, nil
1✔
296
}
1✔
297

298
func (f *JsonTypeOfFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
299
        if t != VarcharType {
3✔
300
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
301
        }
1✔
302
        return nil
1✔
303
}
304

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

310
        v := params[0]
303✔
311
        if v.IsNull() {
304✔
312
                return NewNull(AnyType), nil
1✔
313
        }
1✔
314

315
        jsonVal, ok := v.(*JSON)
302✔
316
        if !ok {
303✔
317
                return nil, fmt.Errorf("%w: '%s' function expects an argument of type JSON", ErrIllegalArguments, JSONTypeOfFnCall)
1✔
318
        }
1✔
319
        return NewVarchar(jsonVal.primitiveType()), nil
301✔
320
}
321

322
// -------------------------------------
323
// UUID Functions
324
// -------------------------------------
325

326
type UUIDFn struct{}
327

328
func (f *UUIDFn) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
329
        return UUIDType, nil
1✔
330
}
1✔
331

332
func (f *UUIDFn) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
333
        if t != UUIDType {
3✔
334
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, UUIDType, t)
1✔
335
        }
1✔
336
        return nil
1✔
337
}
338

339
func (f *UUIDFn) Apply(_ *SQLTx, params []TypedValue) (TypedValue, error) {
5✔
340
        if len(params) > 0 {
6✔
341
                return nil, fmt.Errorf("%w: '%s' function does not expect any argument but %d were provided", ErrIllegalArguments, UUIDFnCall, len(params))
1✔
342
        }
1✔
343
        return &UUID{val: uuid.New()}, nil
4✔
344
}
345

346
// pg functions
347

348
type pgGetUserByIDFunc struct{}
349

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

357
func (f *pgGetUserByIDFunc) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
358
        return VarcharType, nil
1✔
359
}
1✔
360

361
func (f *pgGetUserByIDFunc) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
362
        if len(params) != 1 {
3✔
363
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, PGGetUserByIDFnCall, 1, len(params))
1✔
364
        }
1✔
365

366
        if params[0].RawValue() != int64(0) {
2✔
367
                return nil, fmt.Errorf("user not found")
1✔
368
        }
1✔
369

NEW
370
        users, err := tx.ListUsers(tx.tx.Context())
×
NEW
371
        if err != nil {
×
NEW
372
                return nil, err
×
NEW
373
        }
×
374

NEW
375
        idx := findSysAdmin(users)
×
NEW
376
        if idx < 0 {
×
NEW
377
                return nil, fmt.Errorf("admin not found")
×
NEW
378
        }
×
NEW
379
        return NewVarchar(users[idx].Username()), nil
×
380
}
381

NEW
382
func findSysAdmin(users []User) int {
×
NEW
383
        for i, u := range users {
×
NEW
384
                if u.Permission() == PermissionSysAdmin {
×
NEW
385
                        return i
×
NEW
386
                }
×
387
        }
NEW
388
        return -1
×
389
}
390

391
type pgTableIsVisible struct{}
392

393
func (f *pgTableIsVisible) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
394
        if t != BooleanType {
3✔
395
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
1✔
396
        }
1✔
397
        return nil
1✔
398
}
399

400
func (f *pgTableIsVisible) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
401
        return BooleanType, nil
1✔
402
}
1✔
403

404
func (f *pgTableIsVisible) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
405
        if len(params) != 1 {
3✔
406
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, PgTableIsVisibleFnCall, 1, len(params))
1✔
407
        }
1✔
408
        return NewBool(true), nil
1✔
409
}
410

411
type pgShobjDescription struct{}
412

413
func (f *pgShobjDescription) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
2✔
414
        if t != VarcharType {
3✔
415
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
1✔
416
        }
1✔
417
        return nil
1✔
418
}
419

420
func (f *pgShobjDescription) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
1✔
421
        return VarcharType, nil
1✔
422
}
1✔
423

424
func (f *pgShobjDescription) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
2✔
425
        if len(params) != 2 {
3✔
426
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, PgShobjDescriptionFnCall, 2, len(params))
1✔
427
        }
1✔
428
        return NewVarchar(""), nil
1✔
429
}
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