@quereus/quereus 0.5.2 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/src/common/datatype.d.ts +4 -5
- package/dist/src/common/datatype.d.ts.map +1 -1
- package/dist/src/common/datatype.js.map +1 -1
- package/dist/src/common/type-inference.d.ts +3 -6
- package/dist/src/common/type-inference.d.ts.map +1 -1
- package/dist/src/common/type-inference.js +17 -22
- package/dist/src/common/type-inference.js.map +1 -1
- package/dist/src/core/param.d.ts.map +1 -1
- package/dist/src/core/param.js +3 -18
- package/dist/src/core/param.js.map +1 -1
- package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
- package/dist/src/func/builtins/aggregate.js +24 -2
- package/dist/src/func/builtins/aggregate.js.map +1 -1
- package/dist/src/func/builtins/builtin-window-functions.js +10 -10
- package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
- package/dist/src/func/builtins/conversion.d.ts +10 -0
- package/dist/src/func/builtins/conversion.d.ts.map +1 -1
- package/dist/src/func/builtins/conversion.js +20 -1
- package/dist/src/func/builtins/conversion.js.map +1 -1
- package/dist/src/func/builtins/datetime.js +9 -9
- package/dist/src/func/builtins/datetime.js.map +1 -1
- package/dist/src/func/builtins/explain.js +53 -53
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/func/builtins/generation.js +2 -2
- package/dist/src/func/builtins/generation.js.map +1 -1
- package/dist/src/func/builtins/index.d.ts.map +1 -1
- package/dist/src/func/builtins/index.js +16 -1
- package/dist/src/func/builtins/index.js.map +1 -1
- package/dist/src/func/builtins/json-tvf.js +17 -17
- package/dist/src/func/builtins/json-tvf.js.map +1 -1
- package/dist/src/func/builtins/json.js +11 -11
- package/dist/src/func/builtins/json.js.map +1 -1
- package/dist/src/func/builtins/scalar.d.ts.map +1 -1
- package/dist/src/func/builtins/scalar.js +202 -13
- package/dist/src/func/builtins/scalar.js.map +1 -1
- package/dist/src/func/builtins/schema.js +18 -18
- package/dist/src/func/builtins/schema.js.map +1 -1
- package/dist/src/func/builtins/string.d.ts.map +1 -1
- package/dist/src/func/builtins/string.js +59 -50
- package/dist/src/func/builtins/string.js.map +1 -1
- package/dist/src/func/builtins/timespan.d.ts +45 -0
- package/dist/src/func/builtins/timespan.d.ts.map +1 -0
- package/dist/src/func/builtins/timespan.js +147 -0
- package/dist/src/func/builtins/timespan.js.map +1 -0
- package/dist/src/func/registration.d.ts +26 -0
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +9 -5
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/parser.js +2 -2
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/building/constraint-builder.js +2 -2
- package/dist/src/planner/building/constraint-builder.js.map +1 -1
- package/dist/src/planner/building/delete.js +3 -3
- package/dist/src/planner/building/delete.js.map +1 -1
- package/dist/src/planner/building/function-call.d.ts.map +1 -1
- package/dist/src/planner/building/function-call.js +24 -4
- package/dist/src/planner/building/function-call.js.map +1 -1
- package/dist/src/planner/building/insert.js +3 -3
- package/dist/src/planner/building/insert.js.map +1 -1
- package/dist/src/planner/building/select.d.ts.map +1 -1
- package/dist/src/planner/building/select.js +3 -2
- package/dist/src/planner/building/select.js.map +1 -1
- package/dist/src/planner/building/update.js +7 -7
- package/dist/src/planner/building/update.js.map +1 -1
- package/dist/src/planner/nodes/aggregate-function.d.ts +2 -1
- package/dist/src/planner/nodes/aggregate-function.d.ts.map +1 -1
- package/dist/src/planner/nodes/aggregate-function.js +10 -3
- package/dist/src/planner/nodes/aggregate-function.js.map +1 -1
- package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/cte-node.js +2 -2
- package/dist/src/planner/nodes/cte-node.js.map +1 -1
- package/dist/src/planner/nodes/declarative-schema.js +3 -3
- package/dist/src/planner/nodes/declarative-schema.js.map +1 -1
- package/dist/src/planner/nodes/function.d.ts +2 -1
- package/dist/src/planner/nodes/function.d.ts.map +1 -1
- package/dist/src/planner/nodes/function.js +6 -3
- package/dist/src/planner/nodes/function.js.map +1 -1
- package/dist/src/planner/nodes/insert-node.js +1 -1
- package/dist/src/planner/nodes/insert-node.js.map +1 -1
- package/dist/src/planner/nodes/pragma.d.ts +1 -1
- package/dist/src/planner/nodes/pragma.d.ts.map +1 -1
- package/dist/src/planner/nodes/pragma.js +3 -3
- package/dist/src/planner/nodes/pragma.js.map +1 -1
- package/dist/src/planner/nodes/reference.js +1 -1
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
- package/dist/src/planner/nodes/scalar.js +55 -101
- package/dist/src/planner/nodes/scalar.js.map +1 -1
- package/dist/src/planner/nodes/sequencing-node.js +2 -2
- package/dist/src/planner/nodes/sequencing-node.js.map +1 -1
- package/dist/src/planner/nodes/sink-node.js +2 -2
- package/dist/src/planner/nodes/sink-node.js.map +1 -1
- package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
- package/dist/src/planner/nodes/subquery.js +4 -7
- package/dist/src/planner/nodes/subquery.js.map +1 -1
- package/dist/src/planner/nodes/view-reference-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/view-reference-node.js +2 -2
- package/dist/src/planner/nodes/view-reference-node.js.map +1 -1
- package/dist/src/planner/nodes/window-function.js +3 -3
- package/dist/src/planner/nodes/window-function.js.map +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js +1 -1
- package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +1 -1
- package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
- package/dist/src/planner/scopes/global.js +3 -3
- package/dist/src/planner/scopes/global.js.map +1 -1
- package/dist/src/planner/scopes/param.d.ts.map +1 -1
- package/dist/src/planner/scopes/param.js +2 -2
- package/dist/src/planner/scopes/param.js.map +1 -1
- package/dist/src/planner/type-utils.d.ts +2 -12
- package/dist/src/planner/type-utils.d.ts.map +1 -1
- package/dist/src/planner/type-utils.js +6 -21
- package/dist/src/planner/type-utils.js.map +1 -1
- package/dist/src/runtime/emit/between.js +2 -2
- package/dist/src/runtime/emit/between.js.map +1 -1
- package/dist/src/runtime/emit/binary.d.ts.map +1 -1
- package/dist/src/runtime/emit/binary.js +66 -30
- package/dist/src/runtime/emit/binary.js.map +1 -1
- package/dist/src/runtime/emit/subquery.js +8 -8
- package/dist/src/runtime/emit/subquery.js.map +1 -1
- package/dist/src/runtime/emit/temporal-arithmetic.d.ts +33 -0
- package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -0
- package/dist/src/runtime/emit/temporal-arithmetic.js +269 -0
- package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -0
- package/dist/src/runtime/emit/unary.d.ts.map +1 -1
- package/dist/src/runtime/emit/unary.js +16 -4
- package/dist/src/runtime/emit/unary.js.map +1 -1
- package/dist/src/schema/catalog.js +3 -3
- package/dist/src/schema/catalog.js.map +1 -1
- package/dist/src/schema/column.d.ts +0 -3
- package/dist/src/schema/column.d.ts.map +1 -1
- package/dist/src/schema/column.js +0 -2
- package/dist/src/schema/column.js.map +1 -1
- package/dist/src/schema/function.d.ts +29 -1
- package/dist/src/schema/function.d.ts.map +1 -1
- package/dist/src/schema/function.js.map +1 -1
- package/dist/src/schema/table.d.ts +3 -3
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +4 -6
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/registry.d.ts.map +1 -1
- package/dist/src/types/registry.js +5 -1
- package/dist/src/types/registry.js.map +1 -1
- package/dist/src/types/temporal-types.d.ts +5 -0
- package/dist/src/types/temporal-types.d.ts.map +1 -1
- package/dist/src/types/temporal-types.js +122 -0
- package/dist/src/types/temporal-types.js.map +1 -1
- package/dist/src/util/plan-formatter.d.ts.map +1 -1
- package/dist/src/util/plan-formatter.js +1 -5
- package/dist/src/util/plan-formatter.js.map +1 -1
- package/dist/src/util/row-descriptor.js +2 -2
- package/dist/src/util/row-descriptor.js.map +1 -1
- package/dist/src/vtab/best-access-plan.d.ts +4 -3
- package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
- package/dist/src/vtab/best-access-plan.js.map +1 -1
- package/dist/src/vtab/memory/module.js +1 -1
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/package.json +1 -1
- package/src/common/datatype.ts +4 -5
- package/src/common/type-inference.ts +13 -22
- package/src/core/param.ts +4 -11
- package/src/func/builtins/aggregate.ts +24 -2
- package/src/func/builtins/builtin-window-functions.ts +10 -10
- package/src/func/builtins/conversion.ts +26 -1
- package/src/func/builtins/datetime.ts +9 -9
- package/src/func/builtins/explain.ts +53 -53
- package/src/func/builtins/generation.ts +2 -2
- package/src/func/builtins/index.ts +20 -1
- package/src/func/builtins/json-tvf.ts +17 -17
- package/src/func/builtins/json.ts +11 -11
- package/src/func/builtins/scalar.ts +205 -14
- package/src/func/builtins/schema.ts +18 -18
- package/src/func/builtins/string.ts +93 -80
- package/src/func/builtins/timespan.ts +179 -0
- package/src/func/registration.ts +35 -5
- package/src/index.ts +2 -1
- package/src/parser/parser.ts +2 -2
- package/src/planner/building/constraint-builder.ts +2 -2
- package/src/planner/building/delete.ts +3 -3
- package/src/planner/building/function-call.ts +44 -3
- package/src/planner/building/insert.ts +3 -3
- package/src/planner/building/select.ts +3 -2
- package/src/planner/building/update.ts +7 -7
- package/src/planner/nodes/aggregate-function.ts +13 -3
- package/src/planner/nodes/cte-node.ts +2 -2
- package/src/planner/nodes/declarative-schema.ts +3 -3
- package/src/planner/nodes/function.ts +8 -3
- package/src/planner/nodes/insert-node.ts +1 -1
- package/src/planner/nodes/pragma.ts +4 -3
- package/src/planner/nodes/reference.ts +1 -1
- package/src/planner/nodes/scalar.ts +54 -102
- package/src/planner/nodes/sequencing-node.ts +2 -2
- package/src/planner/nodes/sink-node.ts +2 -2
- package/src/planner/nodes/subquery.ts +5 -7
- package/src/planner/nodes/view-reference-node.ts +2 -2
- package/src/planner/nodes/window-function.ts +3 -3
- package/src/planner/rules/access/rule-select-access-path.ts +1 -1
- package/src/planner/rules/retrieve/rule-grow-retrieve.ts +1 -1
- package/src/planner/scopes/global.ts +3 -3
- package/src/planner/scopes/param.ts +2 -2
- package/src/planner/type-utils.ts +6 -14
- package/src/runtime/emit/between.ts +2 -2
- package/src/runtime/emit/binary.ts +74 -30
- package/src/runtime/emit/subquery.ts +8 -8
- package/src/runtime/emit/temporal-arithmetic.ts +302 -0
- package/src/runtime/emit/unary.ts +17 -4
- package/src/schema/catalog.ts +3 -3
- package/src/schema/column.ts +0 -3
- package/src/schema/function.ts +29 -1
- package/src/schema/table.ts +5 -7
- package/src/types/index.ts +1 -1
- package/src/types/registry.ts +5 -1
- package/src/types/temporal-types.ts +123 -0
- package/src/util/plan-formatter.ts +1 -4
- package/src/util/row-descriptor.ts +2 -2
- package/src/vtab/best-access-plan.ts +4 -3
- package/src/vtab/memory/module.ts +1 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Temporal } from 'temporal-polyfill';
|
|
2
|
+
import { StatusCode, type SqlValue } from '../../common/types.js';
|
|
3
|
+
import { createScalarFunction } from '../registration.js';
|
|
4
|
+
import { QuereusError } from '../../common/errors.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Helper to parse a value as a Temporal.Duration
|
|
8
|
+
*/
|
|
9
|
+
function parseDuration(value: SqlValue): Temporal.Duration | null {
|
|
10
|
+
if (value === null) return null;
|
|
11
|
+
if (typeof value !== 'string') return null;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
return Temporal.Duration.from(value);
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// --- Extraction Functions ---
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* timespan_years() - Extract years component from timespan
|
|
24
|
+
*/
|
|
25
|
+
export const timespanYearsFunc = createScalarFunction(
|
|
26
|
+
{ name: 'timespan_years', numArgs: 1, deterministic: true },
|
|
27
|
+
(value: SqlValue): SqlValue => {
|
|
28
|
+
const duration = parseDuration(value);
|
|
29
|
+
if (!duration) return null;
|
|
30
|
+
return duration.years;
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* timespan_months() - Extract months component from timespan
|
|
36
|
+
*/
|
|
37
|
+
export const timespanMonthsFunc = createScalarFunction(
|
|
38
|
+
{ name: 'timespan_months', numArgs: 1, deterministic: true },
|
|
39
|
+
(value: SqlValue): SqlValue => {
|
|
40
|
+
const duration = parseDuration(value);
|
|
41
|
+
if (!duration) return null;
|
|
42
|
+
return duration.months;
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* timespan_weeks() - Extract weeks component from timespan
|
|
48
|
+
*/
|
|
49
|
+
export const timespanWeeksFunc = createScalarFunction(
|
|
50
|
+
{ name: 'timespan_weeks', numArgs: 1, deterministic: true },
|
|
51
|
+
(value: SqlValue): SqlValue => {
|
|
52
|
+
const duration = parseDuration(value);
|
|
53
|
+
if (!duration) return null;
|
|
54
|
+
return duration.weeks;
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* timespan_days() - Extract days component from timespan
|
|
60
|
+
*/
|
|
61
|
+
export const timespanDaysFunc = createScalarFunction(
|
|
62
|
+
{ name: 'timespan_days', numArgs: 1, deterministic: true },
|
|
63
|
+
(value: SqlValue): SqlValue => {
|
|
64
|
+
const duration = parseDuration(value);
|
|
65
|
+
if (!duration) return null;
|
|
66
|
+
return duration.days;
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* timespan_hours() - Extract hours component from timespan
|
|
72
|
+
*/
|
|
73
|
+
export const timespanHoursFunc = createScalarFunction(
|
|
74
|
+
{ name: 'timespan_hours', numArgs: 1, deterministic: true },
|
|
75
|
+
(value: SqlValue): SqlValue => {
|
|
76
|
+
const duration = parseDuration(value);
|
|
77
|
+
if (!duration) return null;
|
|
78
|
+
return duration.hours;
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* timespan_minutes() - Extract minutes component from timespan
|
|
84
|
+
*/
|
|
85
|
+
export const timespanMinutesFunc = createScalarFunction(
|
|
86
|
+
{ name: 'timespan_minutes', numArgs: 1, deterministic: true },
|
|
87
|
+
(value: SqlValue): SqlValue => {
|
|
88
|
+
const duration = parseDuration(value);
|
|
89
|
+
if (!duration) return null;
|
|
90
|
+
return duration.minutes;
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* timespan_seconds() - Extract seconds component from timespan
|
|
96
|
+
*/
|
|
97
|
+
export const timespanSecondsFunc = createScalarFunction(
|
|
98
|
+
{ name: 'timespan_seconds', numArgs: 1, deterministic: true },
|
|
99
|
+
(value: SqlValue): SqlValue => {
|
|
100
|
+
const duration = parseDuration(value);
|
|
101
|
+
if (!duration) return null;
|
|
102
|
+
return duration.seconds + duration.milliseconds / 1000 + duration.microseconds / 1000000 + duration.nanoseconds / 1000000000;
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// --- Total Functions ---
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* timespan_total_seconds() - Convert entire timespan to seconds
|
|
110
|
+
*/
|
|
111
|
+
export const timespanTotalSecondsFunc = createScalarFunction(
|
|
112
|
+
{ name: 'timespan_total_seconds', numArgs: 1, deterministic: true },
|
|
113
|
+
(value: SqlValue): SqlValue => {
|
|
114
|
+
const duration = parseDuration(value);
|
|
115
|
+
if (!duration) return null;
|
|
116
|
+
try {
|
|
117
|
+
// Use a reference date for calendar units (weeks, months, years)
|
|
118
|
+
const referenceDate = Temporal.PlainDate.from('2024-01-01');
|
|
119
|
+
return duration.total({ unit: 'seconds', relativeTo: referenceDate });
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* timespan_total_minutes() - Convert entire timespan to minutes
|
|
128
|
+
*/
|
|
129
|
+
export const timespanTotalMinutesFunc = createScalarFunction(
|
|
130
|
+
{ name: 'timespan_total_minutes', numArgs: 1, deterministic: true },
|
|
131
|
+
(value: SqlValue): SqlValue => {
|
|
132
|
+
const duration = parseDuration(value);
|
|
133
|
+
if (!duration) return null;
|
|
134
|
+
try {
|
|
135
|
+
// Use a reference date for calendar units (weeks, months, years)
|
|
136
|
+
const referenceDate = Temporal.PlainDate.from('2024-01-01');
|
|
137
|
+
return duration.total({ unit: 'minutes', relativeTo: referenceDate });
|
|
138
|
+
} catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* timespan_total_hours() - Convert entire timespan to hours
|
|
146
|
+
*/
|
|
147
|
+
export const timespanTotalHoursFunc = createScalarFunction(
|
|
148
|
+
{ name: 'timespan_total_hours', numArgs: 1, deterministic: true },
|
|
149
|
+
(value: SqlValue): SqlValue => {
|
|
150
|
+
const duration = parseDuration(value);
|
|
151
|
+
if (!duration) return null;
|
|
152
|
+
try {
|
|
153
|
+
// Use a reference date for calendar units (weeks, months, years)
|
|
154
|
+
const referenceDate = Temporal.PlainDate.from('2024-01-01');
|
|
155
|
+
return duration.total({ unit: 'hours', relativeTo: referenceDate });
|
|
156
|
+
} catch {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* timespan_total_days() - Convert entire timespan to days
|
|
164
|
+
*/
|
|
165
|
+
export const timespanTotalDaysFunc = createScalarFunction(
|
|
166
|
+
{ name: 'timespan_total_days', numArgs: 1, deterministic: true },
|
|
167
|
+
(value: SqlValue): SqlValue => {
|
|
168
|
+
const duration = parseDuration(value);
|
|
169
|
+
if (!duration) return null;
|
|
170
|
+
try {
|
|
171
|
+
// Use a reference date for calendar units (weeks, months, years)
|
|
172
|
+
const referenceDate = Temporal.PlainDate.from('2024-01-01');
|
|
173
|
+
return duration.total({ unit: 'days', relativeTo: referenceDate });
|
|
174
|
+
} catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
|
package/src/func/registration.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { AggregateFinalizer, AggregateReducer, IntegratedTableValuedFunc, ScalarFunc, TableValuedFunc, ScalarFunctionSchema,
|
|
2
2
|
TableValuedFunctionSchema, AggregateFunctionSchema } from '../schema/function.js';
|
|
3
3
|
import { FunctionFlags } from '../common/constants.js';
|
|
4
|
-
import { SqlDataType } from '../common/types.js';
|
|
5
4
|
import type { ScalarType, RelationType } from '../common/datatype.js';
|
|
5
|
+
import { REAL_TYPE } from '../types/builtin-types.js';
|
|
6
|
+
import type { LogicalType } from '../types/logical-type.js';
|
|
7
|
+
import type { DeepReadonly } from '../common/types.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Configuration options for scalar functions
|
|
@@ -18,6 +20,18 @@ interface ScalarFuncOptions {
|
|
|
18
20
|
deterministic?: boolean;
|
|
19
21
|
/** Return type information */
|
|
20
22
|
returnType?: ScalarType;
|
|
23
|
+
/**
|
|
24
|
+
* Optional type inference function for polymorphic functions.
|
|
25
|
+
* If provided, this function will be called at planning time to determine
|
|
26
|
+
* the return type based on the actual argument types.
|
|
27
|
+
*/
|
|
28
|
+
inferReturnType?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => ScalarType;
|
|
29
|
+
/**
|
|
30
|
+
* Optional argument type validation function.
|
|
31
|
+
* If provided, this function will be called at planning time to validate
|
|
32
|
+
* that the argument types are acceptable for this function.
|
|
33
|
+
*/
|
|
34
|
+
validateArgTypes?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => boolean;
|
|
21
35
|
}
|
|
22
36
|
|
|
23
37
|
/**
|
|
@@ -56,6 +70,18 @@ interface AggregateFuncOptions {
|
|
|
56
70
|
initialValue?: AggValue;
|
|
57
71
|
/** Return type information */
|
|
58
72
|
returnType?: ScalarType;
|
|
73
|
+
/**
|
|
74
|
+
* Optional type inference function for polymorphic aggregate functions.
|
|
75
|
+
* If provided, this function will be called at planning time to determine
|
|
76
|
+
* the return type based on the actual argument types.
|
|
77
|
+
*/
|
|
78
|
+
inferReturnType?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => ScalarType;
|
|
79
|
+
/**
|
|
80
|
+
* Optional argument type validation function.
|
|
81
|
+
* If provided, this function will be called at planning time to validate
|
|
82
|
+
* that the argument types are acceptable for this function.
|
|
83
|
+
*/
|
|
84
|
+
validateArgTypes?: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => boolean;
|
|
59
85
|
}
|
|
60
86
|
|
|
61
87
|
/**
|
|
@@ -69,7 +95,7 @@ interface AggregateFuncOptions {
|
|
|
69
95
|
export function createScalarFunction(options: ScalarFuncOptions, jsFunc: ScalarFunc): ScalarFunctionSchema {
|
|
70
96
|
const returnType: ScalarType = options.returnType ?? {
|
|
71
97
|
typeClass: 'scalar',
|
|
72
|
-
|
|
98
|
+
logicalType: REAL_TYPE,
|
|
73
99
|
nullable: true,
|
|
74
100
|
isReadOnly: true
|
|
75
101
|
};
|
|
@@ -79,7 +105,9 @@ export function createScalarFunction(options: ScalarFuncOptions, jsFunc: ScalarF
|
|
|
79
105
|
numArgs: options.numArgs,
|
|
80
106
|
flags: options.flags ?? (FunctionFlags.UTF8 | (options.deterministic !== false ? FunctionFlags.DETERMINISTIC : 0)),
|
|
81
107
|
returnType,
|
|
82
|
-
implementation: jsFunc
|
|
108
|
+
implementation: jsFunc,
|
|
109
|
+
inferReturnType: options.inferReturnType,
|
|
110
|
+
validateArgTypes: options.validateArgTypes
|
|
83
111
|
};
|
|
84
112
|
}
|
|
85
113
|
|
|
@@ -154,7 +182,7 @@ export function createAggregateFunction(
|
|
|
154
182
|
): AggregateFunctionSchema {
|
|
155
183
|
const returnType: ScalarType = options.returnType ?? {
|
|
156
184
|
typeClass: 'scalar',
|
|
157
|
-
|
|
185
|
+
logicalType: REAL_TYPE,
|
|
158
186
|
nullable: true,
|
|
159
187
|
isReadOnly: true
|
|
160
188
|
};
|
|
@@ -166,6 +194,8 @@ export function createAggregateFunction(
|
|
|
166
194
|
returnType,
|
|
167
195
|
stepFunction: stepFunc,
|
|
168
196
|
finalizeFunction: finalizeFunc,
|
|
169
|
-
initialValue: options.initialValue
|
|
197
|
+
initialValue: options.initialValue,
|
|
198
|
+
inferReturnType: options.inferReturnType,
|
|
199
|
+
validateArgTypes: options.validateArgTypes
|
|
170
200
|
};
|
|
171
201
|
}
|
package/src/index.ts
CHANGED
package/src/parser/parser.ts
CHANGED
|
@@ -1512,8 +1512,8 @@ export class Parser {
|
|
|
1512
1512
|
}
|
|
1513
1513
|
|
|
1514
1514
|
// Function call (with optional window function support)
|
|
1515
|
-
if (this.checkIdentifierLike(['key', 'action', 'set', 'default', 'check', 'unique', 'references', 'on', 'cascade', 'restrict', 'like']) && this.checkNext(1, TokenType.LPAREN)) {
|
|
1516
|
-
const name = this.consumeIdentifier(['key', 'action', 'set', 'default', 'check', 'unique', 'references', 'on', 'cascade', 'restrict', 'like'], "Expected function name.");
|
|
1515
|
+
if (this.checkIdentifierLike(['key', 'action', 'set', 'default', 'check', 'unique', 'references', 'on', 'cascade', 'restrict', 'like', 'replace']) && this.checkNext(1, TokenType.LPAREN)) {
|
|
1516
|
+
const name = this.consumeIdentifier(['key', 'action', 'set', 'default', 'check', 'unique', 'references', 'on', 'cascade', 'restrict', 'like', 'replace'], "Expected function name.");
|
|
1517
1517
|
|
|
1518
1518
|
this.consume(TokenType.LPAREN, "Expected '(' after function name.");
|
|
1519
1519
|
|
|
@@ -83,7 +83,7 @@ export function buildConstraintChecks(
|
|
|
83
83
|
if (newAttrId !== undefined) {
|
|
84
84
|
const newColumnType = {
|
|
85
85
|
typeClass: 'scalar' as const,
|
|
86
|
-
|
|
86
|
+
logicalType: tableColumn.logicalType,
|
|
87
87
|
nullable: !tableColumn.notNull,
|
|
88
88
|
isReadOnly: false
|
|
89
89
|
};
|
|
@@ -104,7 +104,7 @@ export function buildConstraintChecks(
|
|
|
104
104
|
if (oldAttrId !== undefined) {
|
|
105
105
|
const oldColumnType = {
|
|
106
106
|
typeClass: 'scalar' as const,
|
|
107
|
-
|
|
107
|
+
logicalType: tableColumn.logicalType,
|
|
108
108
|
nullable: true, // OLD values can be NULL (especially for INSERT)
|
|
109
109
|
isReadOnly: false
|
|
110
110
|
};
|
|
@@ -36,7 +36,7 @@ export function buildDeleteStmt(
|
|
|
36
36
|
name: contextVar.name,
|
|
37
37
|
type: {
|
|
38
38
|
typeClass: 'scalar' as const,
|
|
39
|
-
|
|
39
|
+
logicalType: contextVar.logicalType,
|
|
40
40
|
nullable: !contextVar.notNull,
|
|
41
41
|
isReadOnly: true
|
|
42
42
|
},
|
|
@@ -77,7 +77,7 @@ export function buildDeleteStmt(
|
|
|
77
77
|
name: col.name,
|
|
78
78
|
type: {
|
|
79
79
|
typeClass: 'scalar' as const,
|
|
80
|
-
|
|
80
|
+
logicalType: col.logicalType,
|
|
81
81
|
nullable: !col.notNull,
|
|
82
82
|
isReadOnly: false
|
|
83
83
|
},
|
|
@@ -89,7 +89,7 @@ export function buildDeleteStmt(
|
|
|
89
89
|
name: col.name,
|
|
90
90
|
type: {
|
|
91
91
|
typeClass: 'scalar' as const,
|
|
92
|
-
|
|
92
|
+
logicalType: col.logicalType,
|
|
93
93
|
nullable: true, // NEW values are always NULL for DELETE
|
|
94
94
|
isReadOnly: false
|
|
95
95
|
},
|
|
@@ -5,11 +5,12 @@ import { QuereusError } from "../../common/errors.js";
|
|
|
5
5
|
import { StatusCode } from "../../common/types.js";
|
|
6
6
|
import * as AST from "../../parser/ast.js";
|
|
7
7
|
import { ScalarPlanNode } from "../nodes/plan-node.js";
|
|
8
|
-
import { isAggregateFunctionSchema } from '../../schema/function.js';
|
|
8
|
+
import { isAggregateFunctionSchema, isScalarFunctionSchema } from '../../schema/function.js';
|
|
9
9
|
import { buildExpression } from "./expression.js";
|
|
10
10
|
import { ScalarFunctionCallNode } from "../nodes/function.js";
|
|
11
11
|
import { resolveFunctionSchema } from "./schema-resolution.js";
|
|
12
12
|
import { CapabilityDetectors } from '../framework/characteristics.js';
|
|
13
|
+
import type { ScalarType } from "../../common/datatype.js";
|
|
13
14
|
|
|
14
15
|
export function buildFunctionCall(ctx: PlanningContext, expr: AST.FunctionExpr, allowAggregates: boolean): ScalarPlanNode {
|
|
15
16
|
// In HAVING context, check if this function matches an existing aggregate
|
|
@@ -70,6 +71,25 @@ export function buildFunctionCall(ctx: PlanningContext, expr: AST.FunctionExpr,
|
|
|
70
71
|
// Build arguments for aggregate function
|
|
71
72
|
const args = expr.args.map(arg => buildExpression(ctx, arg, false)); // Aggregates can't contain other aggregates
|
|
72
73
|
|
|
74
|
+
// Perform type inference if available
|
|
75
|
+
let inferredType: ScalarType | undefined;
|
|
76
|
+
if (functionSchema.inferReturnType) {
|
|
77
|
+
const argTypes = args.map(arg => arg.getType().logicalType);
|
|
78
|
+
|
|
79
|
+
// Validate argument types if validator is provided
|
|
80
|
+
if (functionSchema.validateArgTypes && !functionSchema.validateArgTypes(argTypes)) {
|
|
81
|
+
throw new QuereusError(
|
|
82
|
+
`Invalid argument types for aggregate function ${expr.name}`,
|
|
83
|
+
StatusCode.MISMATCH,
|
|
84
|
+
undefined,
|
|
85
|
+
expr.loc?.start.line,
|
|
86
|
+
expr.loc?.start.column
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
inferredType = functionSchema.inferReturnType(argTypes);
|
|
91
|
+
}
|
|
92
|
+
|
|
73
93
|
return new AggregateFunctionCallNode(
|
|
74
94
|
ctx.scope,
|
|
75
95
|
expr,
|
|
@@ -78,11 +98,32 @@ export function buildFunctionCall(ctx: PlanningContext, expr: AST.FunctionExpr,
|
|
|
78
98
|
args,
|
|
79
99
|
expr.distinct ?? false, // Use the distinct field from the AST
|
|
80
100
|
undefined, // orderBy - TODO: parse from expr
|
|
81
|
-
undefined // filter - TODO: parse from expr
|
|
101
|
+
undefined, // filter - TODO: parse from expr
|
|
102
|
+
inferredType
|
|
82
103
|
);
|
|
83
104
|
} else {
|
|
84
105
|
// Regular scalar function
|
|
85
106
|
const args = expr.args.map(arg => buildExpression(ctx, arg, allowAggregates));
|
|
86
|
-
|
|
107
|
+
|
|
108
|
+
// Perform type inference if available
|
|
109
|
+
let inferredType: ScalarType | undefined;
|
|
110
|
+
if (isScalarFunctionSchema(functionSchema) && functionSchema.inferReturnType) {
|
|
111
|
+
const argTypes = args.map(arg => arg.getType().logicalType);
|
|
112
|
+
|
|
113
|
+
// Validate argument types if validator is provided
|
|
114
|
+
if (functionSchema.validateArgTypes && !functionSchema.validateArgTypes(argTypes)) {
|
|
115
|
+
throw new QuereusError(
|
|
116
|
+
`Invalid argument types for function ${expr.name}`,
|
|
117
|
+
StatusCode.MISMATCH,
|
|
118
|
+
undefined,
|
|
119
|
+
expr.loc?.start.line,
|
|
120
|
+
expr.loc?.start.column
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
inferredType = functionSchema.inferReturnType(argTypes);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return new ScalarFunctionCallNode(ctx.scope, expr, functionSchema, args, inferredType);
|
|
87
128
|
}
|
|
88
129
|
}
|
|
@@ -197,7 +197,7 @@ export function buildInsertStmt(
|
|
|
197
197
|
name: contextVar.name,
|
|
198
198
|
type: {
|
|
199
199
|
typeClass: 'scalar' as const,
|
|
200
|
-
|
|
200
|
+
logicalType: contextVar.logicalType,
|
|
201
201
|
nullable: !contextVar.notNull,
|
|
202
202
|
isReadOnly: true
|
|
203
203
|
},
|
|
@@ -287,7 +287,7 @@ export function buildInsertStmt(
|
|
|
287
287
|
name: col.name,
|
|
288
288
|
type: {
|
|
289
289
|
typeClass: 'scalar' as const,
|
|
290
|
-
|
|
290
|
+
logicalType: col.logicalType,
|
|
291
291
|
nullable: true, // OLD values are always NULL for INSERT
|
|
292
292
|
isReadOnly: false
|
|
293
293
|
},
|
|
@@ -299,7 +299,7 @@ export function buildInsertStmt(
|
|
|
299
299
|
name: col.name,
|
|
300
300
|
type: {
|
|
301
301
|
typeClass: 'scalar' as const,
|
|
302
|
-
|
|
302
|
+
logicalType: col.logicalType,
|
|
303
303
|
nullable: !col.notNull,
|
|
304
304
|
isReadOnly: false
|
|
305
305
|
},
|
|
@@ -18,6 +18,7 @@ import { InternalRecursiveCTERefNode as _InternalRecursiveCTERefNode } from '../
|
|
|
18
18
|
import type { CTEScopeNode, CTEPlanNode } from '../nodes/cte-node.js';
|
|
19
19
|
import { JoinNode } from '../nodes/join-node.js';
|
|
20
20
|
import { ColumnReferenceNode } from '../nodes/reference.js';
|
|
21
|
+
import { TEXT_TYPE } from '../../types/builtin-types.js';
|
|
21
22
|
import { ValuesNode } from '../nodes/values-node.js';
|
|
22
23
|
import { createLogger } from '../../common/logger.js';
|
|
23
24
|
|
|
@@ -440,7 +441,7 @@ export function buildFrom(fromClause: AST.FromClause, parentContext: PlanningCon
|
|
|
440
441
|
columnNames.forEach((colName, i) => {
|
|
441
442
|
if (i < subqueryAttributes.length) {
|
|
442
443
|
const attr = subqueryAttributes[i];
|
|
443
|
-
const columnType = fromTable.getType().columns[i]?.type || { typeClass: 'scalar',
|
|
444
|
+
const columnType = fromTable.getType().columns[i]?.type || { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true };
|
|
444
445
|
subqueryScope.registerSymbol(colName.toLowerCase(), (exp, s) =>
|
|
445
446
|
new ColumnReferenceNode(s, exp as AST.ColumnExpr, columnType, attr.id, i));
|
|
446
447
|
}
|
|
@@ -479,7 +480,7 @@ export function buildFrom(fromClause: AST.FromClause, parentContext: PlanningCon
|
|
|
479
480
|
columnNames.forEach((colName, i) => {
|
|
480
481
|
if (i < mutatingAttributes.length) {
|
|
481
482
|
const attr = mutatingAttributes[i];
|
|
482
|
-
const columnType = fromTable.getType().columns[i]?.type || { typeClass: 'scalar',
|
|
483
|
+
const columnType = fromTable.getType().columns[i]?.type || { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: false };
|
|
483
484
|
mutatingScope.registerSymbol(colName.toLowerCase(), (exp, s) =>
|
|
484
485
|
new ColumnReferenceNode(s, exp as AST.ColumnExpr, columnType, attr.id, i));
|
|
485
486
|
}
|
|
@@ -36,7 +36,7 @@ export function buildUpdateStmt(
|
|
|
36
36
|
name: contextVar.name,
|
|
37
37
|
type: {
|
|
38
38
|
typeClass: 'scalar' as const,
|
|
39
|
-
|
|
39
|
+
logicalType: contextVar.logicalType,
|
|
40
40
|
nullable: !contextVar.notNull,
|
|
41
41
|
isReadOnly: true
|
|
42
42
|
},
|
|
@@ -86,7 +86,7 @@ export function buildUpdateStmt(
|
|
|
86
86
|
name: col.name,
|
|
87
87
|
type: {
|
|
88
88
|
typeClass: 'scalar' as const,
|
|
89
|
-
|
|
89
|
+
logicalType: col.logicalType,
|
|
90
90
|
nullable: !col.notNull,
|
|
91
91
|
isReadOnly: false
|
|
92
92
|
},
|
|
@@ -98,7 +98,7 @@ export function buildUpdateStmt(
|
|
|
98
98
|
name: col.name,
|
|
99
99
|
type: {
|
|
100
100
|
typeClass: 'scalar' as const,
|
|
101
|
-
|
|
101
|
+
logicalType: col.logicalType,
|
|
102
102
|
nullable: !col.notNull,
|
|
103
103
|
isReadOnly: false
|
|
104
104
|
},
|
|
@@ -151,7 +151,7 @@ export function buildUpdateStmt(
|
|
|
151
151
|
exp as AST.ColumnExpr,
|
|
152
152
|
{
|
|
153
153
|
typeClass: 'scalar',
|
|
154
|
-
|
|
154
|
+
logicalType: tableColumn.logicalType,
|
|
155
155
|
nullable: !tableColumn.notNull,
|
|
156
156
|
isReadOnly: false
|
|
157
157
|
},
|
|
@@ -168,7 +168,7 @@ export function buildUpdateStmt(
|
|
|
168
168
|
exp as AST.ColumnExpr,
|
|
169
169
|
{
|
|
170
170
|
typeClass: 'scalar',
|
|
171
|
-
|
|
171
|
+
logicalType: tableColumn.logicalType,
|
|
172
172
|
nullable: !tableColumn.notNull,
|
|
173
173
|
isReadOnly: false
|
|
174
174
|
},
|
|
@@ -184,7 +184,7 @@ export function buildUpdateStmt(
|
|
|
184
184
|
exp as AST.ColumnExpr,
|
|
185
185
|
{
|
|
186
186
|
typeClass: 'scalar',
|
|
187
|
-
|
|
187
|
+
logicalType: tableColumn.logicalType,
|
|
188
188
|
nullable: !tableColumn.notNull,
|
|
189
189
|
isReadOnly: false
|
|
190
190
|
},
|
|
@@ -200,7 +200,7 @@ export function buildUpdateStmt(
|
|
|
200
200
|
exp as AST.ColumnExpr,
|
|
201
201
|
{
|
|
202
202
|
typeClass: 'scalar',
|
|
203
|
-
|
|
203
|
+
logicalType: tableColumn.logicalType,
|
|
204
204
|
nullable: !tableColumn.notNull,
|
|
205
205
|
isReadOnly: false
|
|
206
206
|
},
|
|
@@ -6,6 +6,7 @@ import type { FunctionSchema } from '../../schema/function.js';
|
|
|
6
6
|
import { isAggregateFunctionSchema } from '../../schema/function.js';
|
|
7
7
|
import type * as AST from '../../parser/ast.js';
|
|
8
8
|
import { formatExpressionList, formatScalarType } from '../../util/plan-formatter.js';
|
|
9
|
+
import { NULL_TYPE } from '../../types/builtin-types.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Represents an aggregate function call within a SQL query.
|
|
@@ -13,6 +14,7 @@ import { formatExpressionList, formatScalarType } from '../../util/plan-formatte
|
|
|
13
14
|
*/
|
|
14
15
|
export class AggregateFunctionCallNode extends PlanNode implements ScalarPlanNode {
|
|
15
16
|
readonly nodeType = PlanNodeType.ScalarFunctionCall; // Using same type as scalar functions
|
|
17
|
+
private readonly _inferredType?: ScalarType;
|
|
16
18
|
|
|
17
19
|
constructor(
|
|
18
20
|
scope: Scope,
|
|
@@ -22,12 +24,19 @@ export class AggregateFunctionCallNode extends PlanNode implements ScalarPlanNod
|
|
|
22
24
|
public readonly args: ReadonlyArray<ScalarPlanNode>,
|
|
23
25
|
public readonly isDistinct: boolean = false,
|
|
24
26
|
public readonly orderBy?: ReadonlyArray<{ expression: ScalarPlanNode; direction: 'asc' | 'desc' }>,
|
|
25
|
-
public readonly filter?: ScalarPlanNode
|
|
27
|
+
public readonly filter?: ScalarPlanNode,
|
|
28
|
+
inferredType?: ScalarType
|
|
26
29
|
) {
|
|
27
30
|
super(scope);
|
|
31
|
+
this._inferredType = inferredType;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
getType(): ScalarType {
|
|
35
|
+
// Use inferred type if available
|
|
36
|
+
if (this._inferredType) {
|
|
37
|
+
return this._inferredType;
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
// Get the return type from the function schema
|
|
32
41
|
if (isAggregateFunctionSchema(this.functionSchema)) {
|
|
33
42
|
return this.functionSchema.returnType;
|
|
@@ -36,7 +45,7 @@ export class AggregateFunctionCallNode extends PlanNode implements ScalarPlanNod
|
|
|
36
45
|
// Fallback for non-aggregate functions (shouldn't happen)
|
|
37
46
|
return {
|
|
38
47
|
typeClass: 'scalar',
|
|
39
|
-
|
|
48
|
+
logicalType: NULL_TYPE,
|
|
40
49
|
nullable: true, // Aggregates can return NULL
|
|
41
50
|
isReadOnly: true
|
|
42
51
|
};
|
|
@@ -109,7 +118,8 @@ export class AggregateFunctionCallNode extends PlanNode implements ScalarPlanNod
|
|
|
109
118
|
newArgs,
|
|
110
119
|
this.isDistinct,
|
|
111
120
|
newOrderBy,
|
|
112
|
-
newFilter
|
|
121
|
+
newFilter,
|
|
122
|
+
this._inferredType
|
|
113
123
|
);
|
|
114
124
|
}
|
|
115
125
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { PlanNode, type UnaryRelationalNode, type RelationalPlanNode, type Attribute, type TableDescriptor, isRelationalNode } from './plan-node.js';
|
|
2
2
|
import type { RelationType, ScalarType } from '../../common/datatype.js';
|
|
3
|
-
import { SqlDataType } from '../../common/types.js';
|
|
4
3
|
import { PlanNodeType } from './plan-node-type.js';
|
|
5
4
|
import type { Scope } from '../scopes/scope.js';
|
|
6
5
|
import { Cached } from '../../util/cached.js';
|
|
7
6
|
import type { CTECapable } from '../framework/characteristics.js';
|
|
7
|
+
import { TEXT_TYPE } from '../../types/builtin-types.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Narrow contract that any node must satisfy to be placed in the CTE lookup map
|
|
@@ -74,7 +74,7 @@ export class CTENode extends PlanNode implements CTEPlanNode, CTEScopeNode, CTEC
|
|
|
74
74
|
}
|
|
75
75
|
// Fallback: generic TEXT scalar if nothing else is available (should not normally happen)
|
|
76
76
|
if (!resolvedType) {
|
|
77
|
-
resolvedType = { typeClass: 'scalar',
|
|
77
|
+
resolvedType = { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: false } satisfies ScalarType;
|
|
78
78
|
}
|
|
79
79
|
return {
|
|
80
80
|
id: srcAttr?.id ?? PlanNode.nextAttrId(),
|
|
@@ -3,7 +3,7 @@ import { PlanNodeType } from './plan-node-type.js';
|
|
|
3
3
|
import type { Scope } from '../scopes/scope.js';
|
|
4
4
|
import type * as AST from '../../parser/ast.js';
|
|
5
5
|
import { RelationType, type VoidType } from '../../common/datatype.js';
|
|
6
|
-
import {
|
|
6
|
+
import { TEXT_TYPE } from '../../types/builtin-types.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* DECLARE SCHEMA statement plan node
|
|
@@ -66,7 +66,7 @@ export class DiffSchemaNode extends PlanNode implements RelationalPlanNode {
|
|
|
66
66
|
name: 'ddl',
|
|
67
67
|
type: {
|
|
68
68
|
typeClass: 'scalar',
|
|
69
|
-
|
|
69
|
+
logicalType: TEXT_TYPE,
|
|
70
70
|
nullable: false,
|
|
71
71
|
isReadOnly: true,
|
|
72
72
|
},
|
|
@@ -172,7 +172,7 @@ export class ExplainSchemaNode extends PlanNode implements RelationalPlanNode {
|
|
|
172
172
|
name: 'info',
|
|
173
173
|
type: {
|
|
174
174
|
typeClass: 'scalar',
|
|
175
|
-
|
|
175
|
+
logicalType: TEXT_TYPE,
|
|
176
176
|
nullable: false,
|
|
177
177
|
isReadOnly: true,
|
|
178
178
|
},
|
|
@@ -9,18 +9,22 @@ import { FunctionFlags } from '../../common/constants.js';
|
|
|
9
9
|
|
|
10
10
|
export class ScalarFunctionCallNode extends PlanNode implements NaryScalarNode {
|
|
11
11
|
override readonly nodeType = PlanNodeType.ScalarFunctionCall;
|
|
12
|
+
private readonly _inferredType?: ScalarType;
|
|
12
13
|
|
|
13
14
|
constructor(
|
|
14
15
|
scope: Scope,
|
|
15
16
|
public readonly expression: AST.FunctionExpr,
|
|
16
17
|
public readonly functionSchema: FunctionSchema,
|
|
17
|
-
public readonly operands: ScalarPlanNode[]
|
|
18
|
+
public readonly operands: ScalarPlanNode[],
|
|
19
|
+
inferredType?: ScalarType
|
|
18
20
|
) {
|
|
19
21
|
super(scope);
|
|
22
|
+
this._inferredType = inferredType;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
getType(): ScalarType {
|
|
23
|
-
|
|
26
|
+
// Use inferred type if available, otherwise use schema's return type
|
|
27
|
+
return this._inferredType ?? (this.functionSchema.returnType as ScalarType);
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
getChildren(): readonly ScalarPlanNode[] {
|
|
@@ -54,7 +58,8 @@ export class ScalarFunctionCallNode extends PlanNode implements NaryScalarNode {
|
|
|
54
58
|
this.scope,
|
|
55
59
|
this.expression,
|
|
56
60
|
this.functionSchema,
|
|
57
|
-
newChildren as ScalarPlanNode[]
|
|
61
|
+
newChildren as ScalarPlanNode[],
|
|
62
|
+
this._inferredType
|
|
58
63
|
);
|
|
59
64
|
}
|
|
60
65
|
|
|
@@ -50,7 +50,7 @@ export class InsertNode extends PlanNode implements RelationalPlanNode {
|
|
|
50
50
|
name: col.name,
|
|
51
51
|
type: {
|
|
52
52
|
typeClass: 'scalar',
|
|
53
|
-
|
|
53
|
+
logicalType: col.logicalType,
|
|
54
54
|
nullable: isOld ? true : !col.notNull, // OLD values can be null, NEW follows column constraints
|
|
55
55
|
isReadOnly: false
|
|
56
56
|
},
|