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

codenotary / immudb / 12258730221

10 Dec 2024 02:47PM UTC coverage: 89.138% (-0.1%) from 89.266%
12258730221

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…

101 of 183 new or added lines in 13 files covered. (55.19%)

1 existing line in 1 file now uncovered.

37586 of 42166 relevant lines covered (89.14%)

150871.1 hits per line

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

75.32
/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
        PgTableIsVisible    string = "PG_TABLE_IS_VISIBLE"
46
        PgShobjDescription  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
        PgTableIsVisible:    &pgTableIsVisible{},
61
        PgShobjDescription:  &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

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

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

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

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

370
        // TODO: return creator of database if it has still
371
        // the ownership of the database, otherwise return sysadmin
372

NEW
373
        users, err := tx.ListUsers()
×
NEW
374
        if err != nil {
×
NEW
375
                return nil, err
×
NEW
376
        }
×
377

NEW
378
        idx := findAdmin(users)
×
NEW
379
        if idx < 0 {
×
NEW
380
                return nil, fmt.Errorf("admin not found")
×
NEW
381
        }
×
NEW
382
        return NewVarchar(users[idx].Username()), nil
×
383
}
384

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

394
type pgTableIsVisible struct{}
395

NEW
396
func (f *pgTableIsVisible) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
397
        if t != BooleanType {
×
NEW
398
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, BooleanType, t)
×
NEW
399
        }
×
NEW
400
        return nil
×
401
}
402

NEW
403
func (f *pgTableIsVisible) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
404
        return BooleanType, nil
×
NEW
405
}
×
406

NEW
407
func (f *pgTableIsVisible) Apply(tx *SQLTx, params []TypedValue) (TypedValue, error) {
×
NEW
408
        if len(params) != 1 {
×
NEW
409
                return nil, fmt.Errorf("%w: '%s' function expects %d arguments but %d were provided", ErrIllegalArguments, JSONTypeOfFnCall, 1, len(params))
×
NEW
410
        }
×
NEW
411
        return NewBool(true), nil
×
412
}
413

414
type pgShobjDescription struct{}
415

NEW
416
func (f *pgShobjDescription) RequiresType(t SQLValueType, cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) error {
×
NEW
417
        if t != VarcharType {
×
NEW
418
                return fmt.Errorf("%w: %v can not be interpreted as type %v", ErrInvalidTypes, VarcharType, t)
×
NEW
419
        }
×
NEW
420
        return nil
×
421
}
422

NEW
423
func (f *pgShobjDescription) InferType(cols map[string]ColDescriptor, params map[string]SQLValueType, implicitTable string) (SQLValueType, error) {
×
NEW
424
        return VarcharType, nil
×
NEW
425
}
×
426

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