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 };