Skip to content

Commit 6e9a7dc

Browse files
authored
Merge pull request #23 from gilzoide/repl-sample
Add REPL sample
2 parents 9a6727f + 942fa21 commit 6e9a7dc

12 files changed

+1260
-1
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
*.o
22
*.o~
3+
Samples
4+
Samples.meta

Runtime/SQLiteExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,8 @@ public enum DeserializeFlags : uint
6565

6666
[DllImport(LibraryPath, EntryPoint = "sqlite3_free", CallingConvention = CallingConvention.Cdecl)]
6767
public static extern void Free(IntPtr ptr);
68+
69+
[DllImport(LibraryPath, EntryPoint = "sqlite3_column_bytes16", CallingConvention = CallingConvention.Cdecl)]
70+
public static extern int ColumnBytes16(IntPtr stmt, int index);
6871
}
6972
}

Runtime/SQLitePreparedStatement.cs

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
/*
2+
* Copyright (c) 2024 Gil Barbosa Reis
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
using System;
23+
using System.Collections.Generic;
24+
using System.Runtime.InteropServices;
25+
26+
namespace SQLite
27+
{
28+
/// <summary>
29+
/// Low level SQLite prepared statement object.
30+
/// </summary>
31+
/// <remarks>
32+
/// Using this is the same as using prepared statments in the SQLite C API.
33+
/// You need to bind all arguments to the statement, manually step for each row and until done, get values from the
34+
/// returned columns, manually reset for subsequent executions, then dispose when not needed anymore.
35+
/// </remarks>
36+
public class SQLitePreparedStatement : IDisposable
37+
{
38+
private static readonly IntPtr SQLITE_STATIC = IntPtr.Zero;
39+
40+
private SQLiteConnection _db;
41+
private IntPtr _preparedStatement;
42+
43+
public SQLitePreparedStatement(SQLiteConnection db, string statement)
44+
{
45+
if (db == null)
46+
{
47+
throw new ArgumentNullException(nameof(db));
48+
}
49+
50+
_db = db;
51+
_preparedStatement = SQLite3.Prepare2(db.Handle, statement);
52+
}
53+
54+
~SQLitePreparedStatement()
55+
{
56+
Dispose();
57+
}
58+
59+
public SQLite3.Result Reset()
60+
{
61+
ThrowIfDisposed();
62+
return SQLite3.Reset(_preparedStatement);
63+
}
64+
65+
public SQLite3.Result Bind(int index, bool value)
66+
{
67+
ThrowIfDisposed();
68+
return (SQLite3.Result) SQLite3.BindInt(_preparedStatement, index, value ? 1 : 0);
69+
}
70+
public SQLite3.Result Bind(string name, bool value)
71+
{
72+
ThrowIfDisposed();
73+
int index = SQLite3.BindParameterIndex(_preparedStatement, name);
74+
return Bind(index, value);
75+
}
76+
77+
public SQLite3.Result Bind(int index, int value)
78+
{
79+
ThrowIfDisposed();
80+
return (SQLite3.Result) SQLite3.BindInt(_preparedStatement, index, value);
81+
}
82+
public SQLite3.Result Bind(string name, int value)
83+
{
84+
ThrowIfDisposed();
85+
int index = SQLite3.BindParameterIndex(_preparedStatement, name);
86+
return Bind(index, value);
87+
}
88+
89+
public SQLite3.Result Bind(int index, long value)
90+
{
91+
ThrowIfDisposed();
92+
return (SQLite3.Result) SQLite3.BindInt64(_preparedStatement, index, value);
93+
}
94+
public SQLite3.Result Bind(string name, long value)
95+
{
96+
ThrowIfDisposed();
97+
int index = SQLite3.BindParameterIndex(_preparedStatement, name);
98+
return Bind(index, value);
99+
}
100+
101+
public SQLite3.Result Bind(int index, float value)
102+
{
103+
ThrowIfDisposed();
104+
return (SQLite3.Result) SQLite3.BindDouble(_preparedStatement, index, value);
105+
}
106+
public SQLite3.Result Bind(string name, float value)
107+
{
108+
ThrowIfDisposed();
109+
int index = SQLite3.BindParameterIndex(_preparedStatement, name);
110+
return Bind(index, value);
111+
}
112+
113+
public SQLite3.Result Bind(int index, double value)
114+
{
115+
ThrowIfDisposed();
116+
return (SQLite3.Result) SQLite3.BindDouble(_preparedStatement, index, value);
117+
}
118+
public SQLite3.Result Bind(string name, double value)
119+
{
120+
ThrowIfDisposed();
121+
int index = SQLite3.BindParameterIndex(_preparedStatement, name);
122+
return Bind(index, value);
123+
}
124+
125+
public SQLite3.Result Bind(int index, string value)
126+
{
127+
ThrowIfDisposed();
128+
return (SQLite3.Result) SQLite3.BindText(_preparedStatement, index, value, value.Length * sizeof(char), SQLITE_STATIC);
129+
}
130+
public SQLite3.Result Bind(string name, string value)
131+
{
132+
ThrowIfDisposed();
133+
int index = SQLite3.BindParameterIndex(_preparedStatement, name);
134+
return Bind(index, value);
135+
}
136+
137+
public SQLite3.Result Bind(int index, byte[] value)
138+
{
139+
ThrowIfDisposed();
140+
return (SQLite3.Result) SQLite3.BindBlob(_preparedStatement, index, value, value.Length, SQLITE_STATIC);
141+
}
142+
public SQLite3.Result Bind(string name, byte[] value)
143+
{
144+
ThrowIfDisposed();
145+
int index = SQLite3.BindParameterIndex(_preparedStatement, name);
146+
return Bind(index, value);
147+
}
148+
149+
public int BindParameterIndex(string name)
150+
{
151+
ThrowIfDisposed();
152+
return SQLite3.BindParameterIndex(_preparedStatement, name);
153+
}
154+
155+
public SQLite3.Result Step()
156+
{
157+
ThrowIfDisposed();
158+
var result = SQLite3.Step(_preparedStatement);
159+
if (result > SQLite3.Result.OK && result < SQLite3.Result.Row)
160+
{
161+
throw SQLiteException.New(result, SQLite3.GetErrmsg(_db.Handle));
162+
}
163+
return result;
164+
}
165+
166+
public int GetColumnCount()
167+
{
168+
ThrowIfDisposed();
169+
return SQLite3.ColumnCount(_preparedStatement);
170+
}
171+
172+
public string GetColumnName(int column)
173+
{
174+
ThrowIfDisposed();
175+
return SQLite3.ColumnName16(_preparedStatement, column);
176+
}
177+
178+
public IEnumerable<string> EnumerateColumnNames()
179+
{
180+
for (int i = 0, columnCount = GetColumnCount(); i < columnCount; i++)
181+
{
182+
yield return GetColumnName(i);
183+
}
184+
}
185+
186+
public IEnumerable<string> EnumerateColumnsAsText()
187+
{
188+
for (int i = 0, columnCount = GetColumnCount(); i < columnCount; i++)
189+
{
190+
yield return GetString(i);
191+
}
192+
}
193+
194+
public bool GetBool(int column)
195+
{
196+
ThrowIfDisposed();
197+
return SQLite3.ColumnInt(_preparedStatement, column) != 0;
198+
}
199+
200+
public int GetInt(int column)
201+
{
202+
ThrowIfDisposed();
203+
return SQLite3.ColumnInt(_preparedStatement, column);
204+
}
205+
206+
public long GetLong(int column)
207+
{
208+
ThrowIfDisposed();
209+
return SQLite3.ColumnInt64(_preparedStatement, column);
210+
}
211+
212+
public float GetFloat(int column)
213+
{
214+
ThrowIfDisposed();
215+
return (float) SQLite3.ColumnDouble(_preparedStatement, column);
216+
}
217+
218+
public double GetDouble(int column)
219+
{
220+
ThrowIfDisposed();
221+
return SQLite3.ColumnDouble(_preparedStatement, column);
222+
}
223+
224+
public string GetString(int column)
225+
{
226+
ThrowIfDisposed();
227+
IntPtr ptr = SQLite3.ColumnText16(_preparedStatement, column);
228+
int sizeInBytes = SQLite3.ColumnBytes16(_preparedStatement, column);
229+
return Marshal.PtrToStringUni(ptr, sizeInBytes / sizeof(char));
230+
}
231+
232+
public byte[] GetBytes(int column)
233+
{
234+
ThrowIfDisposed();
235+
IntPtr blob = SQLite3.ColumnBlob(_preparedStatement, column);
236+
int sizeInBytes = SQLite3.ColumnBytes(_preparedStatement, column);
237+
var value = new byte[sizeInBytes];
238+
Marshal.Copy(blob, value, 0, sizeInBytes);
239+
return value;
240+
}
241+
242+
public void Dispose()
243+
{
244+
SQLite3.Finalize(_preparedStatement);
245+
_preparedStatement = IntPtr.Zero;
246+
_db = null;
247+
}
248+
249+
private void ThrowIfDisposed()
250+
{
251+
if (_preparedStatement == IntPtr.Zero)
252+
{
253+
throw new ObjectDisposedException(nameof(_preparedStatement));
254+
}
255+
}
256+
}
257+
}

Runtime/SQLitePreparedStatement.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Samples~/REPL.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "Gilzoide.SqliteNet.Samples.REPL",
3+
"rootNamespace": "",
4+
"references": [
5+
"Gilzoide.SqliteNet"
6+
],
7+
"includePlatforms": [],
8+
"excludePlatforms": [],
9+
"allowUnsafeCode": false,
10+
"overrideReferences": false,
11+
"precompiledReferences": [],
12+
"autoReferenced": false,
13+
"defineConstraints": [],
14+
"versionDefines": [],
15+
"noEngineReferences": false
16+
}

Samples~/REPL/Gilzoide.SqliteNet.Samples.REPL.asmdef.meta

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)