@quereus/quereus 0.5.1 → 0.6.0

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.
Files changed (221) hide show
  1. package/README.md +5 -1
  2. package/dist/src/common/datatype.d.ts +4 -5
  3. package/dist/src/common/datatype.d.ts.map +1 -1
  4. package/dist/src/common/datatype.js.map +1 -1
  5. package/dist/src/common/type-inference.d.ts +3 -6
  6. package/dist/src/common/type-inference.d.ts.map +1 -1
  7. package/dist/src/common/type-inference.js +17 -22
  8. package/dist/src/common/type-inference.js.map +1 -1
  9. package/dist/src/core/param.d.ts.map +1 -1
  10. package/dist/src/core/param.js +3 -18
  11. package/dist/src/core/param.js.map +1 -1
  12. package/dist/src/func/builtins/aggregate.d.ts.map +1 -1
  13. package/dist/src/func/builtins/aggregate.js +24 -2
  14. package/dist/src/func/builtins/aggregate.js.map +1 -1
  15. package/dist/src/func/builtins/builtin-window-functions.js +10 -10
  16. package/dist/src/func/builtins/builtin-window-functions.js.map +1 -1
  17. package/dist/src/func/builtins/conversion.d.ts +10 -0
  18. package/dist/src/func/builtins/conversion.d.ts.map +1 -1
  19. package/dist/src/func/builtins/conversion.js +20 -1
  20. package/dist/src/func/builtins/conversion.js.map +1 -1
  21. package/dist/src/func/builtins/explain.js +53 -53
  22. package/dist/src/func/builtins/explain.js.map +1 -1
  23. package/dist/src/func/builtins/generation.js +2 -2
  24. package/dist/src/func/builtins/generation.js.map +1 -1
  25. package/dist/src/func/builtins/index.d.ts.map +1 -1
  26. package/dist/src/func/builtins/index.js +16 -1
  27. package/dist/src/func/builtins/index.js.map +1 -1
  28. package/dist/src/func/builtins/json-tvf.js +17 -17
  29. package/dist/src/func/builtins/json-tvf.js.map +1 -1
  30. package/dist/src/func/builtins/scalar.d.ts.map +1 -1
  31. package/dist/src/func/builtins/scalar.js +202 -13
  32. package/dist/src/func/builtins/scalar.js.map +1 -1
  33. package/dist/src/func/builtins/schema.js +18 -18
  34. package/dist/src/func/builtins/schema.js.map +1 -1
  35. package/dist/src/func/builtins/string.d.ts.map +1 -1
  36. package/dist/src/func/builtins/string.js +56 -47
  37. package/dist/src/func/builtins/string.js.map +1 -1
  38. package/dist/src/func/builtins/timespan.d.ts +45 -0
  39. package/dist/src/func/builtins/timespan.d.ts.map +1 -0
  40. package/dist/src/func/builtins/timespan.js +147 -0
  41. package/dist/src/func/builtins/timespan.js.map +1 -0
  42. package/dist/src/func/registration.d.ts +26 -0
  43. package/dist/src/func/registration.d.ts.map +1 -1
  44. package/dist/src/func/registration.js +9 -5
  45. package/dist/src/func/registration.js.map +1 -1
  46. package/dist/src/index.d.ts +1 -1
  47. package/dist/src/index.d.ts.map +1 -1
  48. package/dist/src/index.js +1 -1
  49. package/dist/src/index.js.map +1 -1
  50. package/dist/src/parser/parser.js +2 -2
  51. package/dist/src/parser/parser.js.map +1 -1
  52. package/dist/src/planner/building/constraint-builder.js +2 -2
  53. package/dist/src/planner/building/constraint-builder.js.map +1 -1
  54. package/dist/src/planner/building/delete.js +3 -3
  55. package/dist/src/planner/building/delete.js.map +1 -1
  56. package/dist/src/planner/building/function-call.d.ts.map +1 -1
  57. package/dist/src/planner/building/function-call.js +24 -4
  58. package/dist/src/planner/building/function-call.js.map +1 -1
  59. package/dist/src/planner/building/insert.js +3 -3
  60. package/dist/src/planner/building/insert.js.map +1 -1
  61. package/dist/src/planner/building/select.d.ts.map +1 -1
  62. package/dist/src/planner/building/select.js +3 -2
  63. package/dist/src/planner/building/select.js.map +1 -1
  64. package/dist/src/planner/building/update.js +7 -7
  65. package/dist/src/planner/building/update.js.map +1 -1
  66. package/dist/src/planner/nodes/aggregate-function.d.ts +2 -1
  67. package/dist/src/planner/nodes/aggregate-function.d.ts.map +1 -1
  68. package/dist/src/planner/nodes/aggregate-function.js +10 -3
  69. package/dist/src/planner/nodes/aggregate-function.js.map +1 -1
  70. package/dist/src/planner/nodes/cte-node.d.ts.map +1 -1
  71. package/dist/src/planner/nodes/cte-node.js +2 -2
  72. package/dist/src/planner/nodes/cte-node.js.map +1 -1
  73. package/dist/src/planner/nodes/declarative-schema.js +3 -3
  74. package/dist/src/planner/nodes/declarative-schema.js.map +1 -1
  75. package/dist/src/planner/nodes/function.d.ts +2 -1
  76. package/dist/src/planner/nodes/function.d.ts.map +1 -1
  77. package/dist/src/planner/nodes/function.js +6 -3
  78. package/dist/src/planner/nodes/function.js.map +1 -1
  79. package/dist/src/planner/nodes/insert-node.js +1 -1
  80. package/dist/src/planner/nodes/insert-node.js.map +1 -1
  81. package/dist/src/planner/nodes/pragma.d.ts +1 -1
  82. package/dist/src/planner/nodes/pragma.d.ts.map +1 -1
  83. package/dist/src/planner/nodes/pragma.js +3 -3
  84. package/dist/src/planner/nodes/pragma.js.map +1 -1
  85. package/dist/src/planner/nodes/reference.js +1 -1
  86. package/dist/src/planner/nodes/reference.js.map +1 -1
  87. package/dist/src/planner/nodes/scalar.d.ts.map +1 -1
  88. package/dist/src/planner/nodes/scalar.js +55 -101
  89. package/dist/src/planner/nodes/scalar.js.map +1 -1
  90. package/dist/src/planner/nodes/sequencing-node.js +2 -2
  91. package/dist/src/planner/nodes/sequencing-node.js.map +1 -1
  92. package/dist/src/planner/nodes/sink-node.js +2 -2
  93. package/dist/src/planner/nodes/sink-node.js.map +1 -1
  94. package/dist/src/planner/nodes/subquery.d.ts.map +1 -1
  95. package/dist/src/planner/nodes/subquery.js +4 -7
  96. package/dist/src/planner/nodes/subquery.js.map +1 -1
  97. package/dist/src/planner/nodes/view-reference-node.d.ts.map +1 -1
  98. package/dist/src/planner/nodes/view-reference-node.js +2 -2
  99. package/dist/src/planner/nodes/view-reference-node.js.map +1 -1
  100. package/dist/src/planner/nodes/window-function.js +3 -3
  101. package/dist/src/planner/nodes/window-function.js.map +1 -1
  102. package/dist/src/planner/rules/access/rule-select-access-path.js +1 -1
  103. package/dist/src/planner/rules/access/rule-select-access-path.js.map +1 -1
  104. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js +1 -1
  105. package/dist/src/planner/rules/retrieve/rule-grow-retrieve.js.map +1 -1
  106. package/dist/src/planner/scopes/global.js +3 -3
  107. package/dist/src/planner/scopes/global.js.map +1 -1
  108. package/dist/src/planner/scopes/param.d.ts.map +1 -1
  109. package/dist/src/planner/scopes/param.js +2 -2
  110. package/dist/src/planner/scopes/param.js.map +1 -1
  111. package/dist/src/planner/type-utils.d.ts +2 -12
  112. package/dist/src/planner/type-utils.d.ts.map +1 -1
  113. package/dist/src/planner/type-utils.js +6 -21
  114. package/dist/src/planner/type-utils.js.map +1 -1
  115. package/dist/src/runtime/emit/binary.d.ts.map +1 -1
  116. package/dist/src/runtime/emit/binary.js +40 -2
  117. package/dist/src/runtime/emit/binary.js.map +1 -1
  118. package/dist/src/runtime/emit/set-operation.d.ts.map +1 -1
  119. package/dist/src/runtime/emit/set-operation.js +33 -22
  120. package/dist/src/runtime/emit/set-operation.js.map +1 -1
  121. package/dist/src/runtime/emit/temporal-arithmetic.d.ts +33 -0
  122. package/dist/src/runtime/emit/temporal-arithmetic.d.ts.map +1 -0
  123. package/dist/src/runtime/emit/temporal-arithmetic.js +269 -0
  124. package/dist/src/runtime/emit/temporal-arithmetic.js.map +1 -0
  125. package/dist/src/runtime/emit/unary.d.ts.map +1 -1
  126. package/dist/src/runtime/emit/unary.js +12 -0
  127. package/dist/src/runtime/emit/unary.js.map +1 -1
  128. package/dist/src/schema/catalog.js +3 -3
  129. package/dist/src/schema/catalog.js.map +1 -1
  130. package/dist/src/schema/column.d.ts +0 -3
  131. package/dist/src/schema/column.d.ts.map +1 -1
  132. package/dist/src/schema/column.js +0 -2
  133. package/dist/src/schema/column.js.map +1 -1
  134. package/dist/src/schema/function.d.ts +29 -1
  135. package/dist/src/schema/function.d.ts.map +1 -1
  136. package/dist/src/schema/function.js.map +1 -1
  137. package/dist/src/schema/table.d.ts +3 -3
  138. package/dist/src/schema/table.d.ts.map +1 -1
  139. package/dist/src/schema/table.js +4 -6
  140. package/dist/src/schema/table.js.map +1 -1
  141. package/dist/src/types/index.d.ts +1 -1
  142. package/dist/src/types/index.d.ts.map +1 -1
  143. package/dist/src/types/index.js +1 -1
  144. package/dist/src/types/index.js.map +1 -1
  145. package/dist/src/types/registry.d.ts.map +1 -1
  146. package/dist/src/types/registry.js +5 -1
  147. package/dist/src/types/registry.js.map +1 -1
  148. package/dist/src/types/temporal-types.d.ts +5 -0
  149. package/dist/src/types/temporal-types.d.ts.map +1 -1
  150. package/dist/src/types/temporal-types.js +122 -0
  151. package/dist/src/types/temporal-types.js.map +1 -1
  152. package/dist/src/util/ast-stringify.js +1 -1
  153. package/dist/src/util/ast-stringify.js.map +1 -1
  154. package/dist/src/util/plan-formatter.d.ts.map +1 -1
  155. package/dist/src/util/plan-formatter.js +1 -5
  156. package/dist/src/util/plan-formatter.js.map +1 -1
  157. package/dist/src/util/row-descriptor.js +2 -2
  158. package/dist/src/util/row-descriptor.js.map +1 -1
  159. package/dist/src/vtab/best-access-plan.d.ts +4 -3
  160. package/dist/src/vtab/best-access-plan.d.ts.map +1 -1
  161. package/dist/src/vtab/best-access-plan.js.map +1 -1
  162. package/dist/src/vtab/memory/module.js +1 -1
  163. package/dist/src/vtab/memory/module.js.map +1 -1
  164. package/package.json +1 -1
  165. package/src/common/datatype.ts +4 -5
  166. package/src/common/type-inference.ts +13 -22
  167. package/src/core/param.ts +4 -11
  168. package/src/func/builtins/aggregate.ts +24 -2
  169. package/src/func/builtins/builtin-window-functions.ts +10 -10
  170. package/src/func/builtins/conversion.ts +26 -1
  171. package/src/func/builtins/explain.ts +53 -53
  172. package/src/func/builtins/generation.ts +2 -2
  173. package/src/func/builtins/index.ts +20 -1
  174. package/src/func/builtins/json-tvf.ts +17 -17
  175. package/src/func/builtins/scalar.ts +205 -14
  176. package/src/func/builtins/schema.ts +18 -18
  177. package/src/func/builtins/string.ts +91 -78
  178. package/src/func/builtins/timespan.ts +179 -0
  179. package/src/func/registration.ts +35 -5
  180. package/src/index.ts +2 -1
  181. package/src/parser/parser.ts +2 -2
  182. package/src/planner/building/constraint-builder.ts +2 -2
  183. package/src/planner/building/delete.ts +3 -3
  184. package/src/planner/building/function-call.ts +44 -3
  185. package/src/planner/building/insert.ts +3 -3
  186. package/src/planner/building/select.ts +3 -2
  187. package/src/planner/building/update.ts +7 -7
  188. package/src/planner/nodes/aggregate-function.ts +13 -3
  189. package/src/planner/nodes/cte-node.ts +2 -2
  190. package/src/planner/nodes/declarative-schema.ts +3 -3
  191. package/src/planner/nodes/function.ts +8 -3
  192. package/src/planner/nodes/insert-node.ts +1 -1
  193. package/src/planner/nodes/pragma.ts +4 -3
  194. package/src/planner/nodes/reference.ts +1 -1
  195. package/src/planner/nodes/scalar.ts +54 -102
  196. package/src/planner/nodes/sequencing-node.ts +2 -2
  197. package/src/planner/nodes/sink-node.ts +2 -2
  198. package/src/planner/nodes/subquery.ts +5 -7
  199. package/src/planner/nodes/view-reference-node.ts +2 -2
  200. package/src/planner/nodes/window-function.ts +3 -3
  201. package/src/planner/rules/access/rule-select-access-path.ts +1 -1
  202. package/src/planner/rules/retrieve/rule-grow-retrieve.ts +1 -1
  203. package/src/planner/scopes/global.ts +3 -3
  204. package/src/planner/scopes/param.ts +2 -2
  205. package/src/planner/type-utils.ts +6 -14
  206. package/src/runtime/emit/binary.ts +48 -2
  207. package/src/runtime/emit/set-operation.ts +52 -22
  208. package/src/runtime/emit/temporal-arithmetic.ts +302 -0
  209. package/src/runtime/emit/unary.ts +13 -0
  210. package/src/schema/catalog.ts +3 -3
  211. package/src/schema/column.ts +0 -3
  212. package/src/schema/function.ts +29 -1
  213. package/src/schema/table.ts +5 -7
  214. package/src/types/index.ts +1 -1
  215. package/src/types/registry.ts +5 -1
  216. package/src/types/temporal-types.ts +123 -0
  217. package/src/util/ast-stringify.ts +1 -1
  218. package/src/util/plan-formatter.ts +1 -4
  219. package/src/util/row-descriptor.ts +2 -2
  220. package/src/vtab/best-access-plan.ts +4 -3
  221. package/src/vtab/memory/module.ts +1 -1
@@ -1,10 +1,10 @@
1
1
  import type { Row, SqlValue, JSONValue } from "../../common/types.js";
2
- import { SqlDataType } from "../../common/types.js";
3
2
  import { createTableValuedFunction } from "../registration.js";
4
3
  import { QuereusError } from "../../common/errors.js";
5
4
  import { StatusCode } from "../../common/types.js";
6
5
  import { safeJsonParse, evaluateJsonPathBasic, getJsonType } from "./json-helpers.js";
7
6
  import { jsonStringify } from "../../util/serialization.js";
7
+ import { INTEGER_TYPE, TEXT_TYPE } from "../../types/builtin-types.js";
8
8
 
9
9
  // JSON Each table-valued function
10
10
  export const jsonEachFunc = createTableValuedFunction(
@@ -17,14 +17,14 @@ export const jsonEachFunc = createTableValuedFunction(
17
17
  isReadOnly: true,
18
18
  isSet: false,
19
19
  columns: [
20
- { name: 'key', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true },
21
- { name: 'value', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true },
22
- { name: 'type', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
23
- { name: 'atom', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true },
24
- { name: 'id', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true },
25
- { name: 'parent', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: true, isReadOnly: true }, generated: true },
26
- { name: 'fullkey', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
27
- { name: 'path', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true }
20
+ { name: 'key', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true },
21
+ { name: 'value', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true },
22
+ { name: 'type', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
23
+ { name: 'atom', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true },
24
+ { name: 'id', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true },
25
+ { name: 'parent', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: true, isReadOnly: true }, generated: true },
26
+ { name: 'fullkey', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
27
+ { name: 'path', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true }
28
28
  ],
29
29
  keys: [],
30
30
  rowConstraints: []
@@ -119,14 +119,14 @@ export const jsonTreeFunc = createTableValuedFunction(
119
119
  isReadOnly: true,
120
120
  isSet: false,
121
121
  columns: [
122
- { name: 'key', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true },
123
- { name: 'value', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true },
124
- { name: 'type', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
125
- { name: 'atom', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true },
126
- { name: 'id', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true },
127
- { name: 'parent', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: true, isReadOnly: true }, generated: true },
128
- { name: 'fullkey', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
129
- { name: 'path', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true }
122
+ { name: 'key', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true },
123
+ { name: 'value', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true },
124
+ { name: 'type', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
125
+ { name: 'atom', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true },
126
+ { name: 'id', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true },
127
+ { name: 'parent', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: true, isReadOnly: true }, generated: true },
128
+ { name: 'fullkey', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
129
+ { name: 'path', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true }
130
130
  ],
131
131
  keys: [],
132
132
  rowConstraints: []
@@ -1,10 +1,64 @@
1
- import type { SqlValue } from '../../common/types.js';
1
+ import type { SqlValue, DeepReadonly } from '../../common/types.js';
2
2
  import { createScalarFunction } from '../registration.js';
3
3
  import { compareSqlValues, getSqlDataTypeName } from '../../util/comparison.js';
4
+ import type { LogicalType } from '../../types/logical-type.js';
5
+ import { ANY_TYPE, INTEGER_TYPE, REAL_TYPE } from '../../types/builtin-types.js';
6
+
7
+ /**
8
+ * Find the common type among multiple logical types.
9
+ * This implements type promotion rules for polymorphic functions.
10
+ *
11
+ * Rules:
12
+ * 1. If all types are the same, return that type
13
+ * 2. If mixing INTEGER and REAL, return REAL (numeric promotion)
14
+ * 3. Otherwise, return the first type (conservative approach)
15
+ *
16
+ * @param types Array of logical types to find common type for
17
+ * @returns The common logical type
18
+ */
19
+ function findCommonType(types: ReadonlyArray<DeepReadonly<LogicalType>>): DeepReadonly<LogicalType> {
20
+ if (types.length === 0) return ANY_TYPE;
21
+ if (types.length === 1) return types[0];
22
+
23
+ // Check if all types are the same
24
+ const firstType = types[0];
25
+ const allSame = types.every(t => t.name === firstType.name);
26
+ if (allSame) return firstType;
27
+
28
+ // Check for numeric type promotion (INTEGER + REAL -> REAL)
29
+ const allNumeric = types.every(t => t.isNumeric === true);
30
+ if (allNumeric) {
31
+ // If any type is REAL, return REAL
32
+ const hasReal = types.some(t => t.name === 'REAL');
33
+ if (hasReal) return REAL_TYPE;
34
+ // All INTEGER
35
+ return INTEGER_TYPE;
36
+ }
37
+
38
+ // For non-numeric types, return the first type (conservative)
39
+ // In a more sophisticated implementation, we could:
40
+ // - Find a common supertype
41
+ // - Return ANY_TYPE if types are incompatible
42
+ // - Throw an error for incompatible types
43
+ return firstType;
44
+ }
4
45
 
5
46
  // --- abs(X) ---
6
47
  export const absFunc = createScalarFunction(
7
- { name: 'abs', numArgs: 1, deterministic: true },
48
+ {
49
+ name: 'abs',
50
+ numArgs: 1,
51
+ deterministic: true,
52
+ // Type inference: return the same type as the input for numeric types
53
+ inferReturnType: (argTypes) => ({
54
+ typeClass: 'scalar',
55
+ logicalType: argTypes[0],
56
+ nullable: false,
57
+ isReadOnly: true
58
+ }),
59
+ // Validate that the argument is numeric
60
+ validateArgTypes: (argTypes) => argTypes[0].isNumeric === true
61
+ },
8
62
  (arg: SqlValue): SqlValue => {
9
63
  if (arg === null) return null;
10
64
  if (typeof arg === 'bigint') return arg < 0n ? -arg : arg;
@@ -16,7 +70,19 @@ export const absFunc = createScalarFunction(
16
70
 
17
71
  // --- round(X, Y?) ---
18
72
  export const roundFunc = createScalarFunction(
19
- { name: 'round', numArgs: -1, deterministic: true },
73
+ {
74
+ name: 'round',
75
+ numArgs: -1,
76
+ deterministic: true,
77
+ // Type inference: return the same type as the input for numeric types
78
+ inferReturnType: (argTypes) => ({
79
+ typeClass: 'scalar',
80
+ logicalType: argTypes[0],
81
+ nullable: false,
82
+ isReadOnly: true
83
+ }),
84
+ validateArgTypes: (argTypes) => argTypes[0].isNumeric === true
85
+ },
20
86
  (numVal: SqlValue, placesVal?: SqlValue): SqlValue => {
21
87
  if (numVal === null) return null;
22
88
  const x = Number(numVal);
@@ -40,7 +106,18 @@ export const roundFunc = createScalarFunction(
40
106
 
41
107
  // --- coalesce(...) ---
42
108
  export const coalesceFunc = createScalarFunction(
43
- { name: 'coalesce', numArgs: -1, deterministic: true },
109
+ {
110
+ name: 'coalesce',
111
+ numArgs: -1,
112
+ deterministic: true,
113
+ // Type inference: find the common type among all arguments
114
+ inferReturnType: (argTypes) => ({
115
+ typeClass: 'scalar',
116
+ logicalType: findCommonType(argTypes),
117
+ nullable: true, // coalesce can return null if all args are null
118
+ isReadOnly: true
119
+ })
120
+ },
44
121
  (...args: SqlValue[]): SqlValue => {
45
122
  for (const arg of args) {
46
123
  if (arg !== null) {
@@ -53,7 +130,18 @@ export const coalesceFunc = createScalarFunction(
53
130
 
54
131
  // --- nullif(X, Y) ---
55
132
  export const nullifFunc = createScalarFunction(
56
- { name: 'nullif', numArgs: 2, deterministic: true },
133
+ {
134
+ name: 'nullif',
135
+ numArgs: 2,
136
+ deterministic: true,
137
+ // Type inference: return the type of the first argument (nullable)
138
+ inferReturnType: (argTypes) => ({
139
+ typeClass: 'scalar',
140
+ logicalType: argTypes[0],
141
+ nullable: true, // nullif can always return null
142
+ isReadOnly: true
143
+ })
144
+ },
57
145
  (argX: SqlValue, argY: SqlValue): SqlValue => {
58
146
  const comparison = compareSqlValues(argX, argY);
59
147
  return comparison === 0 ? null : argX;
@@ -96,7 +184,18 @@ export const randomblobFunc = createScalarFunction(
96
184
 
97
185
  // --- iif(X, Y, Z) ---
98
186
  export const iifFunc = createScalarFunction(
99
- { name: 'iif', numArgs: 3, deterministic: true },
187
+ {
188
+ name: 'iif',
189
+ numArgs: 3,
190
+ deterministic: true,
191
+ // Type inference: find the common type between the true and false values
192
+ inferReturnType: (argTypes) => ({
193
+ typeClass: 'scalar',
194
+ logicalType: findCommonType([argTypes[1], argTypes[2]]), // Common type of Y and Z
195
+ nullable: true, // Could return either Y or Z, so nullable if either is
196
+ isReadOnly: true
197
+ })
198
+ },
100
199
  (condition: SqlValue, trueVal: SqlValue, falseVal: SqlValue): SqlValue => {
101
200
  let isTrue: boolean;
102
201
  if (condition === null) {
@@ -118,7 +217,19 @@ export const iifFunc = createScalarFunction(
118
217
 
119
218
  // --- sqrt(X) ---
120
219
  export const sqrtFunc = createScalarFunction(
121
- { name: 'sqrt', numArgs: 1, deterministic: true },
220
+ {
221
+ name: 'sqrt',
222
+ numArgs: 1,
223
+ deterministic: true,
224
+ // Type inference: sqrt always returns REAL (even for INTEGER input)
225
+ inferReturnType: (argTypes) => ({
226
+ typeClass: 'scalar',
227
+ logicalType: argTypes[0].name === 'INTEGER' ? argTypes[0] : argTypes[0], // Keep input type
228
+ nullable: false,
229
+ isReadOnly: true
230
+ }),
231
+ validateArgTypes: (argTypes) => argTypes[0].isNumeric === true
232
+ },
122
233
  (arg: SqlValue): SqlValue => {
123
234
  if (arg === null) return null;
124
235
  const num = Number(arg);
@@ -149,7 +260,19 @@ export const powerFunc = createScalarFunction(
149
260
 
150
261
  // --- floor(X) ---
151
262
  export const floorFunc = createScalarFunction(
152
- { name: 'floor', numArgs: 1, deterministic: true },
263
+ {
264
+ name: 'floor',
265
+ numArgs: 1,
266
+ deterministic: true,
267
+ // Type inference: preserve input type
268
+ inferReturnType: (argTypes) => ({
269
+ typeClass: 'scalar',
270
+ logicalType: argTypes[0],
271
+ nullable: false,
272
+ isReadOnly: true
273
+ }),
274
+ validateArgTypes: (argTypes) => argTypes[0].isNumeric === true
275
+ },
153
276
  (arg: SqlValue): SqlValue => {
154
277
  if (arg === null) return null;
155
278
  const num = Number(arg);
@@ -167,19 +290,41 @@ const ceil = (arg: SqlValue): SqlValue => {
167
290
  return Math.ceil(num);
168
291
  };
169
292
 
293
+ const ceilTypeInference = {
294
+ inferReturnType: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => ({
295
+ typeClass: 'scalar' as const,
296
+ logicalType: argTypes[0],
297
+ nullable: false,
298
+ isReadOnly: true
299
+ }),
300
+ validateArgTypes: (argTypes: ReadonlyArray<DeepReadonly<LogicalType>>) => argTypes[0].isNumeric === true
301
+ };
302
+
170
303
  export const ceilFunc = createScalarFunction(
171
- { name: 'ceil', numArgs: 1, deterministic: true },
304
+ { name: 'ceil', numArgs: 1, deterministic: true, ...ceilTypeInference },
172
305
  ceil
173
306
  );
174
307
 
175
308
  export const ceilingFunc = createScalarFunction(
176
- { name: 'ceiling', numArgs: 1, deterministic: true },
309
+ { name: 'ceiling', numArgs: 1, deterministic: true, ...ceilTypeInference },
177
310
  ceil
178
311
  );
179
312
 
180
313
  // Math clamp function
181
314
  export const clampFunc = createScalarFunction(
182
- { name: 'clamp', numArgs: 3, deterministic: true },
315
+ {
316
+ name: 'clamp',
317
+ numArgs: 3,
318
+ deterministic: true,
319
+ // Type inference: return the type of the first argument (value)
320
+ inferReturnType: (argTypes) => ({
321
+ typeClass: 'scalar',
322
+ logicalType: argTypes[0],
323
+ nullable: true,
324
+ isReadOnly: true
325
+ }),
326
+ validateArgTypes: (argTypes) => argTypes[0].isNumeric === true && argTypes[1].isNumeric === true && argTypes[2].isNumeric === true
327
+ },
183
328
  (value: SqlValue, min: SqlValue, max: SqlValue): SqlValue => {
184
329
  const v = Number(value);
185
330
  const minVal = Number(min);
@@ -192,7 +337,18 @@ export const clampFunc = createScalarFunction(
192
337
 
193
338
  // Greatest-of function
194
339
  export const greatestFunc = createScalarFunction(
195
- { name: 'greatest', numArgs: -1, deterministic: true },
340
+ {
341
+ name: 'greatest',
342
+ numArgs: -1,
343
+ deterministic: true,
344
+ // Type inference: find the common type among all arguments
345
+ inferReturnType: (argTypes) => ({
346
+ typeClass: 'scalar',
347
+ logicalType: findCommonType(argTypes),
348
+ nullable: true,
349
+ isReadOnly: true
350
+ })
351
+ },
196
352
  (...args: SqlValue[]): SqlValue => {
197
353
  if (args.length === 0) return null;
198
354
  return args.reduce((max, current) => {
@@ -206,7 +362,18 @@ export const greatestFunc = createScalarFunction(
206
362
 
207
363
  // Least-of function
208
364
  export const leastFunc = createScalarFunction(
209
- { name: 'least', numArgs: -1, deterministic: true },
365
+ {
366
+ name: 'least',
367
+ numArgs: -1,
368
+ deterministic: true,
369
+ // Type inference: find the common type among all arguments
370
+ inferReturnType: (argTypes) => ({
371
+ typeClass: 'scalar',
372
+ logicalType: findCommonType(argTypes),
373
+ nullable: true,
374
+ isReadOnly: true
375
+ })
376
+ },
210
377
  (...args: SqlValue[]): SqlValue => {
211
378
  if (args.length === 0) return null;
212
379
  return args.reduce((min, current) => {
@@ -220,7 +387,31 @@ export const leastFunc = createScalarFunction(
220
387
 
221
388
  // Choose function
222
389
  export const chooseFunc = createScalarFunction(
223
- { name: 'choose', numArgs: -1, deterministic: true },
390
+ {
391
+ name: 'choose',
392
+ numArgs: -1,
393
+ deterministic: true,
394
+ // Type inference: find the common type among all value arguments (skip index at position 0)
395
+ inferReturnType: (argTypes) => {
396
+ if (argTypes.length < 2) {
397
+ // Need at least index and one value
398
+ return {
399
+ typeClass: 'scalar',
400
+ logicalType: argTypes[0] || ANY_TYPE,
401
+ nullable: true,
402
+ isReadOnly: true
403
+ };
404
+ }
405
+ // Find common type among all value arguments (skip the index at position 0)
406
+ const valueTypes = argTypes.slice(1);
407
+ return {
408
+ typeClass: 'scalar',
409
+ logicalType: findCommonType(valueTypes),
410
+ nullable: true,
411
+ isReadOnly: true
412
+ };
413
+ }
414
+ },
224
415
  (...args: SqlValue[]): SqlValue => {
225
416
  if (args.length === 0) return null;
226
417
  const index = Number(args[0]);
@@ -1,6 +1,5 @@
1
1
  import type { Row } from "../../common/types.js";
2
2
  import type { SqlValue } from "../../common/types.js";
3
- import { SqlDataType } from "../../common/types.js";
4
3
  import { createIntegratedTableValuedFunction } from "../registration.js";
5
4
  import { QuereusError } from "../../common/errors.js";
6
5
  import { StatusCode } from "../../common/types.js";
@@ -8,6 +7,7 @@ import type { Database } from "../../core/database.js";
8
7
  import type { FunctionSchema } from "../../schema/function.js";
9
8
  import { isScalarFunctionSchema, isTableValuedFunctionSchema, isAggregateFunctionSchema, isWindowFunctionSchema } from "../../schema/function.js";
10
9
  import { Schema } from "../../schema/schema.js";
10
+ import { INTEGER_TYPE, TEXT_TYPE } from "../../types/builtin-types.js";
11
11
  import { ColumnSchema } from "../../schema/column.js";
12
12
 
13
13
  /**
@@ -31,10 +31,10 @@ export const schemaFunc = createIntegratedTableValuedFunction(
31
31
  isReadOnly: true,
32
32
  isSet: false,
33
33
  columns: [
34
- { name: 'type', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
35
- { name: 'name', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
36
- { name: 'tbl_name', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
37
- { name: 'sql', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true }
34
+ { name: 'type', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
35
+ { name: 'name', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
36
+ { name: 'tbl_name', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
37
+ { name: 'sql', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true }
38
38
  ],
39
39
  keys: [],
40
40
  rowConstraints: []
@@ -100,12 +100,12 @@ export const tableInfoFunc = createIntegratedTableValuedFunction(
100
100
  isReadOnly: true,
101
101
  isSet: false,
102
102
  columns: [
103
- { name: 'cid', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true },
104
- { name: 'name', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
105
- { name: 'type', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
106
- { name: 'notnull', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true },
107
- { name: 'dflt_value', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: true, isReadOnly: true }, generated: true },
108
- { name: 'pk', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true }
103
+ { name: 'cid', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true },
104
+ { name: 'name', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
105
+ { name: 'type', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
106
+ { name: 'notnull', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true },
107
+ { name: 'dflt_value', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: true, isReadOnly: true }, generated: true },
108
+ { name: 'pk', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true }
109
109
  ],
110
110
  keys: [],
111
111
  rowConstraints: []
@@ -129,7 +129,7 @@ export const tableInfoFunc = createIntegratedTableValuedFunction(
129
129
  yield [
130
130
  i, // cid
131
131
  column.name, // name
132
- column.affinity || SqlDataType.TEXT, // type
132
+ column.logicalType.name, // type
133
133
  column.notNull ? 1 : 0, // notnull
134
134
  column.defaultValue?.toString() || null, // dflt_value
135
135
  isPrimaryKey ? 1 : 0 // pk
@@ -154,12 +154,12 @@ export const functionInfoFunc = createIntegratedTableValuedFunction(
154
154
  isReadOnly: true,
155
155
  isSet: false,
156
156
  columns: [
157
- { name: 'name', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
158
- { name: 'num_args', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true },
159
- { name: 'type', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true },
160
- { name: 'deterministic', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true },
161
- { name: 'flags', type: { typeClass: 'scalar', affinity: SqlDataType.INTEGER, nullable: false, isReadOnly: true }, generated: true },
162
- { name: 'signature', type: { typeClass: 'scalar', affinity: SqlDataType.TEXT, nullable: false, isReadOnly: true }, generated: true }
157
+ { name: 'name', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
158
+ { name: 'num_args', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true },
159
+ { name: 'type', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true },
160
+ { name: 'deterministic', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true },
161
+ { name: 'flags', type: { typeClass: 'scalar', logicalType: INTEGER_TYPE, nullable: false, isReadOnly: true }, generated: true },
162
+ { name: 'signature', type: { typeClass: 'scalar', logicalType: TEXT_TYPE, nullable: false, isReadOnly: true }, generated: true }
163
163
  ],
164
164
  keys: [],
165
165
  rowConstraints: []