-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for prepared statements with positional arguments (#22)
* Add positional argument tests * Implement passing implementation of positional arguments for #15 * Change order of methods * Refactor prepared statement into new class * WIP * remove prints * add items to gitignore * Add null check to row column type population If there are no returned rows, we can not parse it to find the column types. This check fixes a bug where the process would crash if there were no rows as it was using a null pointer to ask for column types. * make os for build runners consistent with test runners * Add documentation for positional arguments
- Loading branch information
1 parent
203f127
commit 04cd738
Showing
11 changed files
with
255 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
bin/ | ||
obj/ | ||
.idea/ | ||
.mono/ | ||
*.DotSettings.user | ||
|
||
# Rust files | ||
target/ | ||
bindings/ | ||
Cargo.lock | ||
Cargo.lock | ||
|
||
*.db-shm | ||
*.db-wal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
namespace Libsql.Client.Tests; | ||
|
||
public class PositionalArgumentTests | ||
{ | ||
private readonly IDatabaseClient _db = DatabaseClient.Create().Result; | ||
|
||
[Fact] | ||
public async Task SingleParameter() | ||
{ | ||
var rs = await _db.Execute("SELECT ?", 1); | ||
var row = rs.Rows.First(); | ||
var value = row.First(); | ||
var integer = Assert.IsType<Integer>(value); | ||
|
||
Assert.Equal(1, integer.Value); | ||
} | ||
|
||
[Fact] | ||
public async Task MultipleParameters() | ||
{ | ||
var rs = await _db.Execute("SELECT ?, ?, ?", 1.0, "2", 3); | ||
var row = rs.Rows.First(); | ||
var integer = Assert.IsType<Integer>(row.Skip(2).First()); | ||
|
||
Assert.Equal(3, integer.Value); | ||
} | ||
|
||
[Fact] | ||
public async Task BindIntParameter() | ||
{ | ||
var rs = await _db.Execute("SELECT ?", 1); | ||
var row = rs.Rows.First(); | ||
var value = row.First(); | ||
var integer = Assert.IsType<Integer>(value); | ||
|
||
Assert.Equal(1, integer.Value); | ||
} | ||
|
||
[Fact] | ||
public async Task BindRealParameter() | ||
{ | ||
var rs = await _db.Execute("SELECT ?", 1.0); | ||
var row = rs.Rows.First(); | ||
var value = row.First(); | ||
var real = Assert.IsType<Real>(value); | ||
|
||
Assert.Equal(1.0, real.Value); | ||
} | ||
|
||
[Fact] | ||
public async Task BindStringParameter() | ||
{ | ||
var rs = await _db.Execute("SELECT ?", "hello"); | ||
var row = rs.Rows.First(); | ||
var value = row.First(); | ||
var text = Assert.IsType<Text>(value); | ||
|
||
Assert.Equal("hello", text.Value); | ||
} | ||
|
||
[Fact] | ||
public async Task BindSingleNullParameter() | ||
{ | ||
var rs = await _db.Execute("SELECT ?", null); | ||
var row = rs.Rows.First(); | ||
var value = row.First(); | ||
Assert.IsType<Null>(value); | ||
} | ||
|
||
[Fact] | ||
public async Task BindMultipleParametersWithANull() | ||
{ | ||
var rs = await _db.Execute("SELECT ?, ?, ?", 1, null, 3); | ||
var row = rs.Rows.First(); | ||
var value = row.Skip(1).First(); | ||
Assert.IsType<Null>(value); | ||
} | ||
|
||
[Fact] | ||
public async Task BindBlobParameter() | ||
{ | ||
var rs = await _db.Execute("SELECT ?", new byte[] { 1, 2, 3 }); | ||
var row = rs.Rows.First(); | ||
var value = row.First(); | ||
var blob = Assert.IsType<Blob>(value); | ||
|
||
Assert.Equal(new byte[] { 1, 2, 3 }, blob.Value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
using System; | ||
using System.Text; | ||
|
||
namespace Libsql.Client | ||
{ | ||
internal class Statement | ||
{ | ||
public libsql_stmt_t Stmt; | ||
private libsql_connection_t _connection; | ||
|
||
public unsafe Statement(libsql_connection_t connection, string sql) | ||
{ | ||
_connection = connection; | ||
Stmt = new libsql_stmt_t(); | ||
var error = new Error(); | ||
int exitCode; | ||
|
||
fixed (byte* sqlPtr = Encoding.UTF8.GetBytes(sql)) | ||
{ | ||
fixed (libsql_stmt_t* statementPtr = &Stmt) | ||
{ | ||
exitCode = Bindings.libsql_prepare(_connection, sqlPtr, statementPtr, &error.Ptr); | ||
} | ||
} | ||
|
||
error.ThrowIfNonZero(exitCode, $"Failed to prepare statement for: {sql}"); | ||
} | ||
|
||
public unsafe void Bind(object[] values) | ||
{ | ||
var error = new Error(); | ||
int exitCode; | ||
|
||
if (values is null) | ||
{ | ||
exitCode = Bindings.libsql_bind_null(Stmt, 1, &error.Ptr); | ||
error.ThrowIfNonZero(exitCode, "Failed to bind null parameter"); | ||
} | ||
else | ||
{ | ||
for (var i = 0; i < values.Length; i++) | ||
{ | ||
var arg = values[i]; | ||
|
||
|
||
if (arg is int val) { | ||
exitCode = Bindings.libsql_bind_int(Stmt, i + 1, val, &error.Ptr); | ||
} | ||
else if (arg is double d) { | ||
exitCode = Bindings.libsql_bind_float(Stmt, i + 1, d, &error.Ptr); | ||
} | ||
else if (arg is string s) { | ||
fixed (byte* sPtr = Encoding.UTF8.GetBytes(s)) | ||
{ | ||
exitCode = Bindings.libsql_bind_string(Stmt, i + 1, sPtr, &error.Ptr); | ||
} | ||
} | ||
else if (arg is byte[] b) { | ||
fixed (byte* bPtr = b) | ||
{ | ||
exitCode = Bindings.libsql_bind_blob(Stmt, i + 1, bPtr, b.Length, &error.Ptr); | ||
} | ||
} | ||
else if (arg is null) | ||
{ | ||
exitCode = Bindings.libsql_bind_null(Stmt, i + 1, &error.Ptr); | ||
} | ||
else | ||
{ | ||
throw new ArgumentException($"Unsupported argument type: {arg.GetType()}"); | ||
} | ||
|
||
error.ThrowIfNonZero(exitCode, $"Failed to bind parameter. Type: {(arg is null ? "null" : arg.GetType().ToString())} Value: {arg}"); | ||
} | ||
} | ||
} | ||
|
||
private void ReleaseUnmanagedResources() | ||
{ | ||
Bindings.libsql_free_stmt(Stmt); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
ReleaseUnmanagedResources(); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
~Statement() | ||
{ | ||
ReleaseUnmanagedResources(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.