Skip to content

Commit

Permalink
Refactor prepared statement into new class
Browse files Browse the repository at this point in the history
  • Loading branch information
tvandinther committed Feb 19, 2024
1 parent 15f9b6e commit 39aadf3
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 78 deletions.
87 changes: 9 additions & 78 deletions Libsql.Client/DatabaseWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,98 +137,29 @@ public async Task<IResultSet> Execute(string sql)
{
return await Task.Run(() =>
{
unsafe
{
var error = new Error();
int exitCode;
fixed (byte* sqlPtr = Encoding.UTF8.GetBytes(sql))
{
var statement = new libsql_stmt_t();
exitCode = Bindings.libsql_prepare(sqlPtr, &statement, &error.Ptr);
error.ThrowIfNonZero(exitCode, $"Failed to prepare statement for query: {sql}");
return ExecuteStatement(statement);
}
}
var statement = new Statement(sql);
return ExecuteStatement(statement);
});
}

public async Task<IResultSet> Execute(string sql, params object[] args)
{
return await Task.Run(() => {
unsafe {
var statement = new libsql_stmt_t();
var error = new Error();
int exitCode;
fixed (byte* sqlPtr = Encoding.UTF8.GetBytes(sql))
{
exitCode = Bindings.libsql_prepare(sqlPtr, &statement, &error.Ptr);
}
error.ThrowIfNonZero(exitCode, $"Failed to prepare statement for query: {sql}");
if (args is null)
{
exitCode = Bindings.libsql_bind_null(statement, 1, &error.Ptr);
error.ThrowIfNonZero(exitCode, "Failed to bind null parameter");
}
else {
for (var i = 0; i < args.Length; i++)
{
var arg = args[i];
if (arg is null)
{
exitCode = Bindings.libsql_bind_null(statement, i + 1, &error.Ptr);
error.ThrowIfNonZero(exitCode, "Failed to bind null parameter");
continue;
}
switch (arg)
{
case int val:
exitCode = Bindings.libsql_bind_int(statement, i + 1, val, &error.Ptr);
break;
case double d:
exitCode = Bindings.libsql_bind_float(statement, i + 1, d, &error.Ptr);
break;
case string s:
fixed (byte* sPtr = Encoding.UTF8.GetBytes(s))
{
exitCode = Bindings.libsql_bind_string(statement, i + 1, sPtr, &error.Ptr);
}
break;
case byte[] b:
fixed (byte* bPtr = b)
{
exitCode = Bindings.libsql_bind_blob(statement, i + 1, bPtr, b.Length, &error.Ptr);
}
break;
case null:
exitCode = Bindings.libsql_bind_null(statement, i + 1, &error.Ptr);
break;
default:
throw new ArgumentException($"Unsupported argument type: {arg.GetType()}");
}
error.ThrowIfNonZero(exitCode, $"Failed to bind parameter. Type: {arg.GetType()} Value: {arg}");
}
}
return ExecuteStatement(statement);
}
var statement = new Statement(sql);
statement.Bind(args);
return ExecuteStatement(statement);
});
}

private unsafe IResultSet ExecuteStatement(libsql_stmt_t statement)
private unsafe IResultSet ExecuteStatement(Statement statement)
{
var error = new Error();
var rows = new libsql_rows_t();
int exitCode;

exitCode = Bindings.libsql_execute_stmt(_connection, statement, &rows, &error.Ptr);
Bindings.libsql_free_stmt(statement);
exitCode = Bindings.libsql_execute_stmt(_connection, statement.Stmt, &rows, &error.Ptr);
statement.Dispose();

error.ThrowIfNonZero(exitCode, "Failed to execute statement");

Expand Down
92 changes: 92 additions & 0 deletions Libsql.Client/Statement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Text;

namespace Libsql.Client
{
internal class Statement
{
public libsql_stmt_t Stmt;

public unsafe Statement(string sql)
{
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(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();
}
}
}

0 comments on commit 39aadf3

Please sign in to comment.