Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added parameter escaping and support for il2cpp #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ If this folder does not exist create it in the root folder of your Unity project
void ExecuteNonQuery(string query) //for SQL query like UPDATE, DELETE....
Dictionary ExecuteQuery(string query) //for SQL query like SELECT ....

###parameter escaping:
Just pass a List<> as the second parameter of this methods and include them in your query, with "?" or "@param" as in regular SQLite.

##for Android compatibility:
</br>
Expand All @@ -46,11 +48,12 @@ follow this simple steps and you can get full compatibility with android.
* BLOB support by Jonathan Derrough @ http://jderrough.blogspot.com/
* modify by Santiago Bustamante @ [email protected]
* Android compatibility by Thomas Olsen @ [email protected]
* Parameter escaping and iOS 64 bit compatibility by Scalia @ http://scalia.es

<br/>

####feedback?

* twitter: [@busta117](http://www.twitter.com/busta117)
* mail: <[email protected]>
* <http://www.santiagobustamante.info>
* <http://www.santiagobustamante.info>
199 changes: 131 additions & 68 deletions SqliteDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/*
Expand All @@ -12,12 +13,12 @@
* Android compatibility by Thomas Olsen @ [email protected]
*
* */

public class SqliteException : Exception
{
public SqliteException (string message) : base(message)
{
}
}

Expand All @@ -32,58 +33,76 @@ public class SqliteDatabase
const int SQLITE_TEXT = 3;
const int SQLITE_BLOB = 4;
const int SQLITE_NULL = 5;

[DllImport("sqlite3", EntryPoint = "sqlite3_open")]

const int SQLITE_STATIC = 0;
const int SQLITE_TRANSIENT = -1;

[DllImport("__Internal", EntryPoint = "sqlite3_open")]
private static extern int sqlite3_open (string filename, out IntPtr db);
[DllImport("sqlite3", EntryPoint = "sqlite3_close")]
[DllImport("__Internal", EntryPoint = "sqlite3_close")]
private static extern int sqlite3_close (IntPtr db);
[DllImport("sqlite3", EntryPoint = "sqlite3_prepare_v2")]
[DllImport("__Internal", EntryPoint = "sqlite3_prepare_v2")]
private static extern int sqlite3_prepare_v2 (IntPtr db, string zSql, int nByte, out IntPtr ppStmpt, IntPtr pzTail);
[DllImport("sqlite3", EntryPoint = "sqlite3_step")]
[DllImport("__Internal", EntryPoint = "sqlite3_step")]
private static extern int sqlite3_step (IntPtr stmHandle);
[DllImport("sqlite3", EntryPoint = "sqlite3_finalize")]
[DllImport("__Internal", EntryPoint = "sqlite3_finalize")]
private static extern int sqlite3_finalize (IntPtr stmHandle);
[DllImport("sqlite3", EntryPoint = "sqlite3_errmsg")]
[DllImport("__Internal", EntryPoint = "sqlite3_errmsg")]
private static extern IntPtr sqlite3_errmsg (IntPtr db);
[DllImport("sqlite3", EntryPoint = "sqlite3_column_count")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_count")]
private static extern int sqlite3_column_count (IntPtr stmHandle);
[DllImport("sqlite3", EntryPoint = "sqlite3_column_name")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_name")]
private static extern IntPtr sqlite3_column_name (IntPtr stmHandle, int iCol);
[DllImport("sqlite3", EntryPoint = "sqlite3_column_type")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_type")]
private static extern int sqlite3_column_type (IntPtr stmHandle, int iCol);
[DllImport("sqlite3", EntryPoint = "sqlite3_column_int")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_int")]
private static extern int sqlite3_column_int (IntPtr stmHandle, int iCol);
[DllImport("sqlite3", EntryPoint = "sqlite3_column_text")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_text")]
private static extern IntPtr sqlite3_column_text (IntPtr stmHandle, int iCol);
[DllImport("sqlite3", EntryPoint = "sqlite3_column_double")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_double")]
private static extern double sqlite3_column_double (IntPtr stmHandle, int iCol);
[DllImport("sqlite3", EntryPoint = "sqlite3_column_blob")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_blob")]
private static extern IntPtr sqlite3_column_blob (IntPtr stmHandle, int iCol);

[DllImport("sqlite3", EntryPoint = "sqlite3_column_bytes")]
[DllImport("__Internal", EntryPoint = "sqlite3_column_bytes")]
private static extern int sqlite3_column_bytes (IntPtr stmHandle, int iCol);

[DllImport("__Internal", EntryPoint = "sqlite3_bind_text")]
private static extern int sqlite3_bind_text(IntPtr stmHandle, int iCol, string value, int nByte, int mode);

[DllImport("__Internal", EntryPoint = "sqlite3_bind_int")]
private static extern int sqlite3_bind_int(IntPtr stmHandle, int iCol, int value);

[DllImport("__Internal", EntryPoint = "sqlite3_bind_int64")]
private static extern int sqlite3_bind_int64(IntPtr stmHandle, int iCol, long value);

[DllImport("__Internal", EntryPoint = "sqlite3_bind_double")]
private static extern int sqlite3_bind_double(IntPtr stmHandle, int iCol, double value);

[DllImport("__Internal", EntryPoint = "sqlite3_bind_null")]
private static extern int sqlite3_bind_null(IntPtr stmHandle, int iCol);

private IntPtr _connection;

private bool IsConnectionOpen { get; set; }

private string pathDB;


#region Public Methods
#region Public Methods
/// <summary>
/// Initializes a new instance of the <see cref="SqliteDatabase"/> class.
/// </summary>
Expand Down Expand Up @@ -115,13 +134,13 @@ public SqliteDatabase (string dbName)

} else {
// Mac, Windows, Iphone
//validate the existens of the DB in the original folder (folder "streamingAssets")
if (System.IO.File.Exists (sourcePath)) {

//copy file - alle systems except Android
System.IO.File.Copy (sourcePath, pathDB, true);

} else {
CanExQuery = false;
Debug.Log ("ERROR: the file DB named " + dbName + " doesn't exist in the StreamingAssets Folder, please copy it there.");
Expand All @@ -142,50 +161,57 @@ private void Open (string path)
if (IsConnectionOpen) {
throw new SqliteException ("There is already an open connection");
}
if (sqlite3_open (path, out _connection) != SQLITE_OK) {
throw new SqliteException ("Could not open database file: " + path);
}
IsConnectionOpen = true;
}
private void Close ()
{
if (IsConnectionOpen) {
sqlite3_close (_connection);
}
IsConnectionOpen = false;
}
/// <summary>
/// Executes a Update, Delete, etc query.
/// </summary>
/// <param name='query'>
/// Query.
/// </param>
/// <param name='parameters'>
/// Parameters.
/// </param>
/// <exception cref='SqliteException'>
/// Is thrown when the sqlite exception.
/// </exception>
public void ExecuteNonQuery (string query)
public void ExecuteNonQuery (string query, List<object> parameters = null)
{
if (!CanExQuery) {
Debug.Log ("ERROR: Can't execute the query, verify DB origin file");
return;
}

this.Open ();
if (!IsConnectionOpen) {
throw new SqliteException ("SQLite database is not open.");
}

IntPtr stmHandle = Prepare (query);


if (null != parameters) {
BindParameters(stmHandle, parameters);
}

if (sqlite3_step (stmHandle) != SQLITE_DONE) {
throw new SqliteException ("Could not execute SQL statement.");
}
Finalize (stmHandle);
this.Close ();
}
Expand All @@ -199,10 +225,13 @@ public void ExecuteNonQuery (string query)
/// <param name='query'>
/// Query.
/// </param>
/// <param name='parameters'>
/// Parameters.
/// </param>
/// <exception cref='SqliteException'>
/// Is thrown when the sqlite exception.
/// </exception>
public DataTable ExecuteQuery (string query)
public DataTable ExecuteQuery (string query, List<object> parameters = null)
{
if (!CanExQuery) {
Debug.Log ("ERROR: Can't execute the query, verify DB origin file");
Expand All @@ -213,17 +242,20 @@ public DataTable ExecuteQuery (string query)
if (!IsConnectionOpen) {
throw new SqliteException ("SQLite database is not open.");
}
IntPtr stmHandle = Prepare (query);


if (null != parameters) {
BindParameters(stmHandle, parameters);
}

int columnCount = sqlite3_column_count (stmHandle);
var dataTable = new DataTable ();
for (int i = 0; i < columnCount; i++) {
string columnName = Marshal.PtrToStringAnsi (sqlite3_column_name (stmHandle, i));
dataTable.Columns.Add (columnName);
}


//populate datatable
while (sqlite3_step(stmHandle) == SQLITE_ROW) {
Expand All @@ -233,16 +265,16 @@ public DataTable ExecuteQuery (string query)
case SQLITE_INTEGER:
row [i] = sqlite3_column_int (stmHandle, i);
break;
case SQLITE_TEXT:
IntPtr text = sqlite3_column_text (stmHandle, i);
row [i] = Marshal.PtrToStringAnsi (text);
break;

case SQLITE_FLOAT:
row [i] = sqlite3_column_double (stmHandle, i);
break;
case SQLITE_BLOB:
IntPtr blob = sqlite3_column_blob (stmHandle, i);
int size = sqlite3_column_bytes (stmHandle, i);
Expand All @@ -256,48 +288,79 @@ public DataTable ExecuteQuery (string query)
break;
}
}
dataTable.AddRow (row);
}
Finalize (stmHandle);
this.Close ();
return dataTable;
}
public void ExecuteScript (string script)
{
string[] statements = script.Split (';');
foreach (string statement in statements) {
if (!string.IsNullOrEmpty (statement.Trim ())) {
ExecuteNonQuery (statement);
}
}
}
#endregion
#region Private Methods
#endregion
#region Private Methods
private IntPtr Prepare (string query)
{
IntPtr stmHandle;
if (sqlite3_prepare_v2 (_connection, query, query.Length, out stmHandle, IntPtr.Zero) != SQLITE_OK) {
IntPtr errorMsg = sqlite3_errmsg (_connection);
throw new SqliteException (Marshal.PtrToStringAnsi (errorMsg));
}
return stmHandle;
}


private void BindParameters(IntPtr stmHandle, List<object> parameters)
{
for(int i=0; i<parameters.Count; i++) {
object obj = parameters[i];
if (null == obj) {
if (sqlite3_bind_null(stmHandle, i+1) != SQLITE_OK) {
throw new SqliteException ("Error binding null parameter " + i);
}
} else if (obj is string) {
string s = (string) obj;
if (sqlite3_bind_text(stmHandle, i+1, s, s.Length, SQLITE_TRANSIENT) != SQLITE_OK) {
throw new SqliteException ("Error binding string parameter " + i);
}
} else if (obj is long) {
if (sqlite3_bind_int64(stmHandle, i+1, (long) obj) != SQLITE_OK) {
throw new SqliteException ("Error binding long parameter " + i);
}
} else if (obj is int) {
if (sqlite3_bind_int(stmHandle, i+1, (int) obj) != SQLITE_OK) {
throw new SqliteException ("Error binding int parameter " + i);
}
} else if (obj is double) {
if (sqlite3_bind_double(stmHandle, i+1, (double) obj) != SQLITE_OK) {
throw new SqliteException ("Error binding double parameter " + i);
}
} else {
throw new SqliteException ("Unsupported parameter " + i);
}
}
}

private void Finalize (IntPtr stmHandle)
{
if (sqlite3_finalize (stmHandle) != SQLITE_OK) {
throw new SqliteException ("Could not finalize SQL statement.");
}
}
#endregion
#endregion
}