From e964c6eb2b95f692875ae344374bc99c99013120 Mon Sep 17 00:00:00 2001 From: IamSanjid Date: Wed, 23 Oct 2024 02:50:55 +0600 Subject: Reuse field for binding --- query.zig | 17 +++++++++++------ sqlite.zig | 48 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/query.zig b/query.zig index e12ba6d..31245f7 100644 --- a/query.zig +++ b/query.zig @@ -125,11 +125,11 @@ pub fn ParsedQuery(comptime tmp_query: []const u8) type { if (!isNamedIdentifierChar(c)) { // This marks the end of the named bind marker. state = .start; - const name = buf[hold_pos .. pos - 1]; + const name = buf[hold_pos - 1 .. pos]; // TODO(vincent): name retains a pointer to a comptime var, FIX ! if (bindMarkerForName(tmp_bind_markers[0..nb_tmp_bind_markers], name) == null) { const new_buf = buf; - tmp_bind_markers[nb_tmp_bind_markers].name = new_buf[hold_pos .. pos - 1]; + tmp_bind_markers[nb_tmp_bind_markers].name = new_buf[hold_pos - 1 .. pos]; nb_tmp_bind_markers += 1; } } @@ -175,6 +175,8 @@ pub fn ParsedQuery(comptime tmp_query: []const u8) type { nb_tmp_bind_markers += 1; }, .bind_marker_identifier => { + const new_buf = buf; + tmp_bind_markers[nb_tmp_bind_markers].name = @as([]const u8, new_buf[hold_pos - 1 .. pos]); nb_tmp_bind_markers += 1; }, .start => {}, @@ -339,15 +341,15 @@ test "parsed query: bind markers identifier" { }, .{ .query = "foobar ?123", - .expected_marker = .{}, + .expected_marker = .{ .typed = null, .name = "123" }, }, .{ .query = "foobar :hola", - .expected_marker = .{}, + .expected_marker = .{ .typed = null, .name = "hola" }, }, .{ .query = "foobar @foo", - .expected_marker = .{}, + .expected_marker = .{ .typed = null, .name = "foo" }, }, }; @@ -357,7 +359,10 @@ test "parsed query: bind markers identifier" { try testing.expectEqual(@as(usize, 1), parsed_query.bind_markers.len); const bind_marker = parsed_query.bind_markers[0]; - try testing.expectEqual(tc.expected_marker, bind_marker); + if (bind_marker.name) |name| { + try testing.expectEqualStrings(tc.expected_marker.name.?, name); + } + try testing.expectEqual(tc.expected_marker.typed, bind_marker.typed); } } diff --git a/sqlite.zig b/sqlite.zig index 4d7457b..62950c8 100644 --- a/sqlite.zig +++ b/sqlite.zig @@ -2069,11 +2069,26 @@ pub fn Statement(comptime opts: StatementOptions, comptime query: anytype) type const StructTypeInfo = @typeInfo(StructType).@"struct"; - if (comptime query.bind_markers.len != StructTypeInfo.fields.len) { - @compileError(std.fmt.comptimePrint("expected {d} bind parameters but got {d}", .{ - query.bind_markers.len, - StructTypeInfo.fields.len, - })); + comptime marker_len_check: { + if (query.bind_markers.len != StructTypeInfo.fields.len) { + if (query.bind_markers.len > StructTypeInfo.fields.len) { + var found_markers = 0; + for (query.bind_markers) |bind_marker| { + if (bind_marker.name) |name| { + if (@hasField(StructType, name)) { + found_markers += 1; + } + } + } + if (found_markers == query.bind_markers.len) { + break :marker_len_check; + } + } + @compileError(std.fmt.comptimePrint("expected {d} bind parameters but got {d}", .{ + query.bind_markers.len, + StructTypeInfo.fields.len, + })); + } } inline for (StructTypeInfo.fields, 0..) |struct_field, _i| { @@ -4021,3 +4036,26 @@ test "tagged union" { try testing.expectEqual(foobar.age, result.?.value); } } + +test "reuse same field twice in query string" { + var db = try getTestDb(); + defer db.deinit(); + try addTestData(&db); + + const update_name = "NewUpdatedName"; + + const update_name_query = "UPDATE user SET id = $id, name = $name WHERE id = $id"; + try db.exec(update_name_query, .{}, .{ .id = 20, .name = update_name }); + + const fetch_name_query = "SELECT name FROM user WHERE id = $id"; + const name = try db.oneAlloc( + []const u8, + testing.allocator, + fetch_name_query, + .{}, + .{ .id = 20 }, + ); + try testing.expect(name != null); + defer testing.allocator.free(name.?); + try testing.expectEqualStrings(name.?, update_name); +} -- cgit v1.2.3