lib/sql/src/statement/ast.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const sql = @import("../root.zig");
3 const plan = sql.plan;
4 const catalog_mod = sql.catalog;
5 const row = sql.row;
6 const session_mod = sql.session;
7 const version = sql.version;
8
9 const Allocator = std.mem.Allocator;
10
11 const StatementError = error{
12 CapacityOverflow,
13 ColumnCountMismatch,
14 ColumnNotFound,
15 DuplicateColumn,
16 EmptyStatement,
17 ExpectedColumn,
18 ExpectedIdentifier,
19 ExpectedInteger,
20 ExpectedKeyword,
21 ExpectedProjection,
22 ExpectedRowId,
23 ExpectedString,
24 ExpectedToken,
25 ExpectedValue,
26 InvalidInteger,
27 InvalidLimit,
28 InvalidParameter,
29 ParameterIndexConflict,
30 ParameterIndexOutOfBounds,
31 ParameterNotFound,
32 RowIdAssignment,
33 TableNotFound,
34 TooManyParameters,
35 TrailingInput,
36 UnsupportedStatement,
37 WriteSessionRequired,
38 };
39
40 pub const Error =
41 plan.Error ||
42 session_mod.DatabaseError ||
43 std.mem.Allocator.Error ||
44 StatementError;
45
46 pub const max_parameters: usize = 1024;
47
48 pub const Parameter = struct {
49 name: ?[]const u8 = null,
50 };
51
52 pub const Expression = union(enum) {
53 literal: row.Value,
54 parameter: usize,
55 };
56
57 pub const Insert = struct {
58 table: []const u8,
59 columns: ?[][]const u8 = null,
60 values: []Expression,
61 };
62
63 pub const Projection = union(enum) {
64 all,
65 columns: [][]const u8,
66 };
67
68 pub const PredicateColumn = union(enum) {
69 rowid,
70 field: []const u8,
71 };
72
73 pub const PredicateOperator = enum {
74 eq,
75 lt,
76 lte,
77 gt,
78 gte,
79 };
80
81 pub const Predicate = struct {
82 column: PredicateColumn,
83 operator: PredicateOperator,
84 value: Expression,
85 };
86
87 pub const OrderKey = struct {
88 column: PredicateColumn,
89 descending: bool = false,
90 };
91
92 pub const Select = struct {
93 table: []const u8,
94 projection: Projection,
95 predicates: []Predicate = &.{},
96 order: []OrderKey = &.{},
97 limit: ?Expression = null,
98 offset: ?Expression = null,
99 };
100
101 pub const Assignment = struct {
102 column: []const u8,
103 value: Expression,
104 };
105
106 pub const Update = struct {
107 table: []const u8,
108 assignments: []Assignment,
109 predicates: []Predicate,
110 };
111
112 pub const Delete = struct {
113 table: []const u8,
114 predicates: []Predicate,
115 };
116
117 pub const CreateTable = struct {
118 table: []const u8,
119 columns: []catalog_mod.ColumnDefinition,
120 indexes: []catalog_mod.IndexDefinition,
121
122 pub fn relationDefinition(self: CreateTable) catalog_mod.RelationDefinition {
123 return .{
124 .name = self.table,
125 .columns = self.columns,
126 .indexes = self.indexes,
127 };
128 }
129 };
130
131 pub const CreateIndex = struct {
132 name: []const u8,
133 table: []const u8,
134 columns: [][]const u8,
135 };
136
137 pub const Analyze = struct {
138 table: []const u8,
139 };
140
141 pub const DropTable = struct {
142 table: []const u8,
143 };
144
145 pub const Statement = union(enum) {
146 insert: Insert,
147 select: Select,
148 update: Update,
149 delete: Delete,
150 create_table: CreateTable,
151 create_index: CreateIndex,
152 drop_table: DropTable,
153 analyze: Analyze,
154
155 pub fn deinit(self: *Statement, allocator: Allocator) void {
156 switch (self.*) {
157 .insert => |insert| {
158 if (insert.columns) |columns| allocator.free(columns);
159 allocator.free(insert.values);
160 },
161 .select => |select| {
162 switch (select.projection) {
163 .all => {},
164 .columns => |columns| allocator.free(columns),
165 }
166 allocator.free(select.predicates);
167 allocator.free(select.order);
168 },
169 .update => |update| {
170 allocator.free(update.assignments);
171 allocator.free(update.predicates);
172 },
173 .delete => |delete| allocator.free(delete.predicates),
174 .create_table => |create_table| {
175 for (create_table.indexes) |index| allocator.free(@constCast(index.fields));
176 allocator.free(create_table.indexes);
177 allocator.free(create_table.columns);
178 },
179 .create_index => |create_index| allocator.free(create_index.columns),
180 .drop_table => {},
181 .analyze => {},
182 }
183 self.* = undefined;
184 }
185
186 pub fn tableName(self: Statement) []const u8 {
187 return switch (self) {
188 .insert => |insert| insert.table,
189 .select => |select| select.table,
190 .update => |update| update.table,
191 .delete => |delete| delete.table,
192 .create_table => |create_table| create_table.table,
193 .create_index => |create_index| create_index.table,
194 .drop_table => |drop_table| drop_table.table,
195 .analyze => |analyze| analyze.table,
196 };
197 }
198 };
199
200 pub const Parsed = struct {
201 statement: Statement,
202 parameters: []Parameter,
203
204 pub fn deinit(self: *Parsed, allocator: Allocator) void {
205 allocator.free(self.parameters);
206 self.statement.deinit(allocator);
207 self.* = undefined;
208 }
209 };
210
211 pub fn parameterShape(parameters: []const Parameter) version.Hash {
212 var builder = ParameterShape.init("sql.parameters");
213 builder.writeU64(parameters.len);
214 for (parameters) |parameter| {
215 if (parameter.name) |name| {
216 builder.writeU8(1);
217 builder.bytes(name);
218 } else {
219 builder.writeU8(0);
220 }
221 }
222 return builder.finish();
223 }
224
225 pub const ParameterShape = struct {
226 hasher: std.crypto.hash.sha2.Sha256,
227
228 pub fn init(tag: []const u8) ParameterShape {
229 var builder = ParameterShape{ .hasher = std.crypto.hash.sha2.Sha256.init(.{}) };
230 builder.bytes(tag);
231 return builder;
232 }
233
234 pub fn finish(self: *ParameterShape) version.Hash {
235 var digest: version.Hash = undefined;
236 self.hasher.final(&digest);
237 return digest;
238 }
239
240 pub fn bytes(self: *ParameterShape, value: []const u8) void {
241 self.writeU64(value.len);
242 self.hasher.update(value);
243 }
244
245 pub fn writeU8(self: *ParameterShape, value: u8) void {
246 self.hasher.update(&.{value});
247 }
248
249 pub fn writeU64(self: *ParameterShape, value: anytype) void {
250 var encoded: [8]u8 = undefined;
251 std.mem.writeInt(u64, encoded[0..], @intCast(value), .big);
252 self.hasher.update(&encoded);
253 }
254 };