diff options
| author | 2022-04-23 00:28:41 +0200 | |
|---|---|---|
| committer | 2022-04-23 15:05:54 +0200 | |
| commit | 889a52c021d566b3bc7f16a1808ebaf37bc8abdb (patch) | |
| tree | e85936ec2bbdd0f0505d791f3120a5bd499fd0c6 /sqlite.zig | |
| parent | readme: add note about complex allocations (diff) | |
| download | zig-sqlite-889a52c021d566b3bc7f16a1808ebaf37bc8abdb.tar.gz zig-sqlite-889a52c021d566b3bc7f16a1808ebaf37bc8abdb.tar.xz zig-sqlite-889a52c021d566b3bc7f16a1808ebaf37bc8abdb.zip | |
handle tagged union when binding parameters
Diffstat (limited to '')
| -rw-r--r-- | sqlite.zig | 87 |
1 files changed, 87 insertions, 0 deletions
| @@ -1675,6 +1675,24 @@ pub const DynamicStatement = struct { | |||
| 1675 | 1675 | ||
| 1676 | try self.bindField(FieldType.BaseType, options, field_name, i, field_value); | 1676 | try self.bindField(FieldType.BaseType, options, field_name, i, field_value); |
| 1677 | }, | 1677 | }, |
| 1678 | .Union => |info| { | ||
| 1679 | if (info.tag_type) |UnionTagType| { | ||
| 1680 | inline for (info.fields) |u_field| { | ||
| 1681 | // This wasn't entirely obvious when I saw code like this elsewhere, it works because of type coercion. | ||
| 1682 | // See https://ziglang.org/documentation/master/#Type-Coercion-unions-and-enums | ||
| 1683 | const field_tag: std.meta.Tag(FieldType) = field; | ||
| 1684 | const this_tag: std.meta.Tag(FieldType) = @field(UnionTagType, u_field.name); | ||
| 1685 | |||
| 1686 | if (field_tag == this_tag) { | ||
| 1687 | const field_value = @field(field, u_field.name); | ||
| 1688 | |||
| 1689 | try self.bindField(u_field.field_type, options, u_field.name, i, field_value); | ||
| 1690 | } | ||
| 1691 | } | ||
| 1692 | } else { | ||
| 1693 | @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)); | ||
| 1694 | } | ||
| 1695 | }, | ||
| 1678 | else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)), | 1696 | else => @compileError("cannot bind field " ++ field_name ++ " of type " ++ @typeName(FieldType)), |
| 1679 | }, | 1697 | }, |
| 1680 | } | 1698 | } |
| @@ -3782,3 +3800,72 @@ test "sqlite: fuzzer found crashes" { | |||
| 3782 | try testing.expectError(tc.exp_error, db.execDynamic(tc.input, .{}, .{})); | 3800 | try testing.expectError(tc.exp_error, db.execDynamic(tc.input, .{}, .{})); |
| 3783 | } | 3801 | } |
| 3784 | } | 3802 | } |
| 3803 | |||
| 3804 | test "tagged union" { | ||
| 3805 | var db = try getTestDb(); | ||
| 3806 | defer db.deinit(); | ||
| 3807 | try addTestData(&db); | ||
| 3808 | |||
| 3809 | const Foobar = union(enum) { | ||
| 3810 | name: []const u8, | ||
| 3811 | age: usize, | ||
| 3812 | }; | ||
| 3813 | |||
| 3814 | try db.exec("CREATE TABLE foobar(key TEXT, value ANY)", .{}, .{}); | ||
| 3815 | |||
| 3816 | var foobar = Foobar{ .name = "hello" }; | ||
| 3817 | |||
| 3818 | { | ||
| 3819 | try db.exec("INSERT INTO foobar(key, value) VALUES($key, $value)", .{}, .{ | ||
| 3820 | .key = std.meta.tagName(std.meta.activeTag(foobar)), | ||
| 3821 | .value = foobar, | ||
| 3822 | }); | ||
| 3823 | |||
| 3824 | var arena = heap.ArenaAllocator.init(testing.allocator); | ||
| 3825 | defer arena.deinit(); | ||
| 3826 | |||
| 3827 | const result = try db.oneAlloc( | ||
| 3828 | struct { | ||
| 3829 | key: []const u8, | ||
| 3830 | value: []const u8, | ||
| 3831 | }, | ||
| 3832 | arena.allocator(), | ||
| 3833 | "SELECT key, value FROM foobar WHERE key = $key", | ||
| 3834 | .{}, | ||
| 3835 | .{ | ||
| 3836 | std.meta.tagName(std.meta.activeTag(foobar)), | ||
| 3837 | }, | ||
| 3838 | ); | ||
| 3839 | try testing.expect(result != null); | ||
| 3840 | try testing.expectEqualStrings("name", result.?.key); | ||
| 3841 | try testing.expectEqualStrings(foobar.name, result.?.value); | ||
| 3842 | } | ||
| 3843 | |||
| 3844 | { | ||
| 3845 | foobar = Foobar{ .age = 204 }; | ||
| 3846 | |||
| 3847 | try db.exec("INSERT INTO foobar(key, value) VALUES($key, $value)", .{}, .{ | ||
| 3848 | .key = std.meta.tagName(std.meta.activeTag(foobar)), | ||
| 3849 | .value = foobar, | ||
| 3850 | }); | ||
| 3851 | |||
| 3852 | var arena = heap.ArenaAllocator.init(testing.allocator); | ||
| 3853 | defer arena.deinit(); | ||
| 3854 | |||
| 3855 | const result = try db.oneAlloc( | ||
| 3856 | struct { | ||
| 3857 | key: []const u8, | ||
| 3858 | value: usize, | ||
| 3859 | }, | ||
| 3860 | arena.allocator(), | ||
| 3861 | "SELECT key, value FROM foobar WHERE key = $key", | ||
| 3862 | .{}, | ||
| 3863 | .{ | ||
| 3864 | std.meta.tagName(std.meta.activeTag(foobar)), | ||
| 3865 | }, | ||
| 3866 | ); | ||
| 3867 | try testing.expect(result != null); | ||
| 3868 | try testing.expectEqualStrings("age", result.?.key); | ||
| 3869 | try testing.expectEqual(foobar.age, result.?.value); | ||
| 3870 | } | ||
| 3871 | } | ||