mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-21 03:03:46 -04:00
Move SQLite backend to new interfaces
This commit is contained in:
parent
81b1617ba1
commit
bad7d3443e
@ -35,16 +35,8 @@ namespace MCGalaxy.SQL
|
||||
public override bool MultipleSchema { get { return false; } }
|
||||
public override string EngineName { get { return "SQLite"; } }
|
||||
|
||||
internal override IDbConnection CreateConnection() {
|
||||
public override ISqlConnection CreateConnection() {
|
||||
return new MCGSQLiteConnection();
|
||||
}
|
||||
|
||||
internal override IDbCommand CreateCommand(string sql, IDbConnection conn) {
|
||||
return new SQLiteCommand(sql, (SQLiteConnection)conn);
|
||||
}
|
||||
|
||||
internal override IDbDataParameter CreateParameter() {
|
||||
return new SQLiteParameter();
|
||||
}
|
||||
|
||||
|
||||
@ -67,7 +59,7 @@ namespace MCGalaxy.SQL
|
||||
|
||||
public override void CreateDatabase() { }
|
||||
|
||||
public override string RawGetDateTime(IDataRecord record, int col) {
|
||||
public override string RawGetDateTime(ISqlRecord record, int col) {
|
||||
return record.GetString(col); // reader.GetDateTime is extremely slow so avoid it
|
||||
}
|
||||
|
||||
@ -146,7 +138,8 @@ namespace MCGalaxy.SQL
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MCGSQLiteConnection : SQLiteConnection {
|
||||
sealed class MCGSQLiteConnection : SQLiteConnection
|
||||
{
|
||||
protected override bool ConnectionPooling { get { return Server.Config.DatabasePooling; } }
|
||||
protected override string DBPath { get { return "MCGalaxy.db"; } }
|
||||
}
|
||||
|
@ -5,9 +5,7 @@
|
||||
* Released to the public domain, use at your own risk!
|
||||
********************************************************/
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
@ -15,10 +13,20 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using SQLiteErrorCode = System.Int32;
|
||||
|
||||
namespace MCGalaxy.SQL {
|
||||
namespace MCGalaxy.SQL
|
||||
{
|
||||
enum SqlType
|
||||
{
|
||||
Single, Double, Decimal,
|
||||
SByte, Int16, Int32, Int64,
|
||||
Byte, UInt16, UInt32, UInt64,
|
||||
Boolean, DateTime,
|
||||
Binary, String, Object,
|
||||
}
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
internal static class Interop {
|
||||
static class Interop
|
||||
{
|
||||
const string lib = "sqlite3";
|
||||
|
||||
[DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
|
||||
@ -100,28 +108,21 @@ namespace MCGalaxy.SQL {
|
||||
internal static extern IntPtr sqlite3_errstr(SQLiteErrorCode rc); /* 3.7.15+ */
|
||||
}
|
||||
|
||||
public abstract class SQLiteConnection : IDbConnection {
|
||||
ConnectionState state = ConnectionState.Closed;
|
||||
public abstract class SQLiteConnection : ISqlConnection
|
||||
{
|
||||
internal int _transactionLevel;
|
||||
IntPtr handle;
|
||||
public IntPtr handle;
|
||||
|
||||
protected abstract bool ConnectionPooling { get; }
|
||||
protected abstract string DBPath { get; }
|
||||
|
||||
public IDbTransaction BeginTransaction(IsolationLevel isolationLevel) {
|
||||
public override ISqlTransaction BeginTransaction() {
|
||||
return new SQLiteTransaction(this);
|
||||
}
|
||||
|
||||
public IDbTransaction BeginTransaction() {
|
||||
return new SQLiteTransaction(this);
|
||||
}
|
||||
public override void ChangeDatabase(string databaseName) { }
|
||||
|
||||
public void ChangeDatabase(string databaseName) { }
|
||||
public int ConnectionTimeout { get { return SQLiteConvert.Timeout; } }
|
||||
public string ConnectionString { get { return ""; } set { } }
|
||||
|
||||
public IDbCommand CreateCommand() { return new SQLiteCommand(this); }
|
||||
public string Database { get { return "main"; } }
|
||||
public override ISqlCommand CreateCommand(string sql) { return new SQLiteCommand(sql, this); }
|
||||
|
||||
public long LastInsertRowId {
|
||||
get {
|
||||
@ -143,8 +144,6 @@ namespace MCGalaxy.SQL {
|
||||
return Interop.sqlite3_get_autocommit(handle) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectionState State { get { return state; } }
|
||||
|
||||
public SQLiteErrorCode ResultCode() {
|
||||
if (handle == IntPtr.Zero) throw new InvalidOperationException("Database connection closed");
|
||||
@ -182,9 +181,8 @@ namespace MCGalaxy.SQL {
|
||||
}
|
||||
}
|
||||
|
||||
public void Open() {
|
||||
if (state != ConnectionState.Closed) throw new InvalidOperationException();
|
||||
Close();
|
||||
public override void Open() {
|
||||
if (handle != IntPtr.Zero) throw new InvalidOperationException();
|
||||
|
||||
try {
|
||||
if (ConnectionPooling) handle = RemoveFromPool();
|
||||
@ -200,7 +198,6 @@ namespace MCGalaxy.SQL {
|
||||
}
|
||||
|
||||
SetTimeout(0);
|
||||
state = ConnectionState.Open;
|
||||
} catch (SQLiteException) {
|
||||
Close();
|
||||
throw;
|
||||
@ -216,10 +213,8 @@ namespace MCGalaxy.SQL {
|
||||
internal static void Check(SQLiteConnection connection) {
|
||||
if (connection == null)
|
||||
throw new ArgumentNullException("connection");
|
||||
if (connection.state != ConnectionState.Open)
|
||||
throw new InvalidOperationException("The connection is not open.");
|
||||
if (connection.handle == IntPtr.Zero)
|
||||
throw new InvalidOperationException("The connection handle is invalid.");
|
||||
throw new InvalidOperationException("The connection is not open.");
|
||||
}
|
||||
|
||||
internal bool Reset(bool canThrow) {
|
||||
@ -242,8 +237,8 @@ namespace MCGalaxy.SQL {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose() { Close(false); }
|
||||
public void Close() { Close(true); }
|
||||
public override void Dispose() { Close(false); }
|
||||
public override void Close() { Close(true); }
|
||||
|
||||
void Close(bool canThrow) {
|
||||
if (handle == IntPtr.Zero) return;
|
||||
@ -289,16 +284,17 @@ namespace MCGalaxy.SQL {
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SQLiteCommand : IDbCommand {
|
||||
string strCmdText, strRemaining;
|
||||
SQLiteConnection conn;
|
||||
SQLiteParameterCollection parameters = new SQLiteParameterCollection();
|
||||
public sealed class SQLiteCommand : ISqlCommand
|
||||
{
|
||||
string sqlCmd;
|
||||
internal SQLiteConnection conn;
|
||||
SQLiteStatement stmt;
|
||||
List<string> param_names = new List<string>();
|
||||
List<object> param_values = new List<object>();
|
||||
|
||||
public SQLiteCommand(SQLiteConnection connection) : this(null, connection) { }
|
||||
public SQLiteCommand(string commandText, SQLiteConnection connection) {
|
||||
if (commandText != null) CommandText = commandText;
|
||||
if (connection != null) Connection = connection;
|
||||
public SQLiteCommand(string sql, SQLiteConnection connection) {
|
||||
sqlCmd = sql;
|
||||
conn = connection;
|
||||
}
|
||||
|
||||
void DisposeStatement() {
|
||||
@ -306,78 +302,61 @@ namespace MCGalaxy.SQL {
|
||||
stmt = null;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
public override void Dispose() {
|
||||
conn = null;
|
||||
parameters.Clear();
|
||||
strCmdText = null;
|
||||
strRemaining = null;
|
||||
param_names.Clear();
|
||||
param_values.Clear();
|
||||
sqlCmd = null;
|
||||
DisposeStatement();
|
||||
}
|
||||
|
||||
internal SQLiteStatement NextStatement() {
|
||||
if (stmt != null) DisposeStatement();
|
||||
if (String.IsNullOrEmpty(strRemaining)) return null;
|
||||
if (String.IsNullOrEmpty(sqlCmd)) return null;
|
||||
|
||||
try {
|
||||
stmt = conn.Prepare(strRemaining, ref strRemaining);
|
||||
stmt = conn.Prepare(sqlCmd, ref sqlCmd);
|
||||
} catch (Exception) {
|
||||
DisposeStatement();
|
||||
// Cannot continue on, so set the remaining text to null.
|
||||
strRemaining = null;
|
||||
sqlCmd = null;
|
||||
throw;
|
||||
}
|
||||
|
||||
if (stmt != null) stmt.BindAll(parameters);
|
||||
if (stmt != null) stmt.BindAll(param_names, param_values);
|
||||
return stmt;
|
||||
}
|
||||
|
||||
public override void Prepare() { }
|
||||
|
||||
public void Cancel() { }
|
||||
public string CommandText {
|
||||
get { return strCmdText; }
|
||||
set { strCmdText = value; strRemaining = value; }
|
||||
}
|
||||
|
||||
public int CommandTimeout {
|
||||
get { return SQLiteConvert.Timeout; } set { }
|
||||
public override void ClearParameters() {
|
||||
param_names.Clear();
|
||||
param_values.Clear();
|
||||
}
|
||||
|
||||
public IDbConnection Connection {
|
||||
get { return conn; } set { conn = (SQLiteConnection)value; }
|
||||
public override void AddParameter(string name, object value) {
|
||||
param_names.Add(name);
|
||||
param_values.Add(value);
|
||||
}
|
||||
|
||||
public CommandType CommandType { get { return CommandType.Text; } set { } }
|
||||
public IDbDataParameter CreateParameter() { return new SQLiteParameter(); }
|
||||
public IDataParameterCollection Parameters { get { return parameters; } }
|
||||
public IDbTransaction Transaction { get { return null; } set { } }
|
||||
|
||||
public IDataReader ExecuteReader(CommandBehavior behavior) {
|
||||
public override ISqlReader ExecuteReader() {
|
||||
SQLiteConnection.Check(conn);
|
||||
return new SQLiteDataReader(this);
|
||||
}
|
||||
public IDataReader ExecuteReader() { return ExecuteReader(0); }
|
||||
|
||||
public int ExecuteNonQuery() {
|
||||
using (IDataReader reader = ExecuteReader()) {
|
||||
while (reader.NextResult()) { }
|
||||
return reader.RecordsAffected;
|
||||
SQLiteDataReader reader = new SQLiteDataReader(this);
|
||||
reader.NextResult();
|
||||
return reader;
|
||||
}
|
||||
|
||||
public override int ExecuteNonQuery() {
|
||||
using (ISqlReader reader = ExecuteReader()) {
|
||||
while (reader.Read()) { }
|
||||
return reader.RowsAffected;
|
||||
}
|
||||
}
|
||||
|
||||
public object ExecuteScalar() {
|
||||
using (IDataReader reader = ExecuteReader()) {
|
||||
if (reader.Read()) return reader[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Prepare() { }
|
||||
|
||||
public UpdateRowSource UpdatedRowSource {
|
||||
get { return UpdateRowSource.None; } set { }
|
||||
}
|
||||
}
|
||||
|
||||
static class SQLiteConvert {
|
||||
static class SQLiteConvert
|
||||
{
|
||||
static string[] _datetimeFormats = new string[] {
|
||||
"yyyy-MM-dd HH:mm:ss.FFFFFFFK", /* NOTE: UTC default (0). */
|
||||
"yyyy-MM-dd HH:mm:ssK",
|
||||
@ -450,80 +429,65 @@ namespace MCGalaxy.SQL {
|
||||
typeof(object), // Null (5)
|
||||
};
|
||||
|
||||
internal static DbType TypeToDbType(Type typ) {
|
||||
internal static SqlType TypeToDbType(Type typ) {
|
||||
TypeCode tc = Type.GetTypeCode(typ);
|
||||
if (tc == TypeCode.Object) {
|
||||
if (typ == typeof(byte[])) return DbType.Binary;
|
||||
return DbType.String;
|
||||
if (typ == typeof(byte[])) return SqlType.Binary;
|
||||
return SqlType.String;
|
||||
}
|
||||
return type_to_dbtype[(int)tc];
|
||||
}
|
||||
|
||||
static DbType[] type_to_dbtype = {
|
||||
DbType.Object, // Empty (0)
|
||||
DbType.Binary, // Object (1)
|
||||
DbType.Object, // DBNull (2)
|
||||
DbType.Boolean, // Boolean (3)
|
||||
DbType.SByte, // Char (4)
|
||||
DbType.SByte, // SByte (5)
|
||||
DbType.Byte, // Byte (6)
|
||||
DbType.Int16, // Int16 (7)
|
||||
DbType.UInt16, // UInt16 (8)
|
||||
DbType.Int32, // Int32 (9)
|
||||
DbType.UInt32, // UInt32 (10)
|
||||
DbType.Int64, // Int64 (11)
|
||||
DbType.UInt64, // UInt64 (12)
|
||||
DbType.Single, // Single (13)
|
||||
DbType.Double, // Double (14)
|
||||
DbType.Decimal, // Decimal (15)
|
||||
DbType.DateTime, // DateTime (16)
|
||||
DbType.Object, // ?? (17)
|
||||
DbType.String // String (18)
|
||||
static SqlType[] type_to_dbtype = {
|
||||
SqlType.Object, // Empty (0)
|
||||
SqlType.Binary, // Object (1)
|
||||
SqlType.Object, // DBNull (2)
|
||||
SqlType.Boolean, // Boolean (3)
|
||||
SqlType.SByte, // Char (4)
|
||||
SqlType.SByte, // SByte (5)
|
||||
SqlType.Byte, // Byte (6)
|
||||
SqlType.Int16, // Int16 (7)
|
||||
SqlType.UInt16, // UInt16 (8)
|
||||
SqlType.Int32, // Int32 (9)
|
||||
SqlType.UInt32, // UInt32 (10)
|
||||
SqlType.Int64, // Int64 (11)
|
||||
SqlType.UInt64, // UInt64 (12)
|
||||
SqlType.Single, // Single (13)
|
||||
SqlType.Double, // Double (14)
|
||||
SqlType.Decimal, // Decimal (15)
|
||||
SqlType.DateTime, // DateTime (16)
|
||||
SqlType.Object, // ?? (17)
|
||||
SqlType.String // String (18)
|
||||
};
|
||||
|
||||
internal static Type[] dbtype_to_type = {
|
||||
typeof(string), // AnsiString (0)
|
||||
typeof(byte[]), // Binary (1)
|
||||
typeof(byte), // Byte (2)
|
||||
typeof(bool), // Boolean (3)
|
||||
typeof(decimal), // Currency (4)
|
||||
typeof(DateTime), // Date (5)
|
||||
typeof(DateTime), // DateTime (6)
|
||||
typeof(decimal), // Decimal (7)
|
||||
typeof(double), // Double (8)
|
||||
typeof(Guid), // Guid (9)
|
||||
typeof(Int16), // Int16 (10)
|
||||
typeof(Int32), // Int32 (11)
|
||||
typeof(Int64), // Int64 (12)
|
||||
typeof(object), // Object (13)
|
||||
typeof(sbyte), // SByte (14)
|
||||
typeof(float), // Single (15)
|
||||
typeof(string), // String (16)
|
||||
typeof(DateTime), // Time (17)
|
||||
typeof(UInt16), // UInt16 (18)
|
||||
typeof(UInt32), // UInt32 (19)
|
||||
typeof(UInt64), // UInt64 (20)
|
||||
internal static Type[] sqltype_to_type = {
|
||||
typeof(float), typeof(double), typeof(decimal),
|
||||
typeof(sbyte), typeof(Int16), typeof(Int32), typeof(Int64),
|
||||
typeof(byte), typeof(UInt16), typeof(UInt32), typeof(UInt64),
|
||||
typeof(bool), typeof(DateTime),
|
||||
typeof(byte[]), typeof(string), typeof(object)
|
||||
};
|
||||
|
||||
static bool TryParseDbType(string typeName, out DbType type) {
|
||||
static bool TryParseDbType(string typeName, out SqlType type) {
|
||||
string[] names = all_names;
|
||||
for (int i = 0; i < names.Length; i++) {
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (!typeName.Equals(names[i], StringComparison.OrdinalIgnoreCase)) continue;
|
||||
type = all_types[i]; return true;
|
||||
}
|
||||
type = 0; return false;
|
||||
}
|
||||
|
||||
internal static DbType TypeNameToDbType(string typeName) {
|
||||
if (typeName == null) return DbType.Object;
|
||||
internal static SqlType TypeNameToDbType(string typeName) {
|
||||
if (typeName == null) return SqlType.Object;
|
||||
|
||||
DbType value;
|
||||
SqlType value;
|
||||
if (TryParseDbType(typeName, out value)) return value;
|
||||
|
||||
int i = typeName.IndexOf('(');
|
||||
if (i > 0 && TryParseDbType(typeName.Substring(0, i).TrimEnd(), out value)) return value;
|
||||
|
||||
return DbType.Object;
|
||||
return SqlType.Object;
|
||||
}
|
||||
|
||||
static string[] all_names = new string[] {
|
||||
@ -541,23 +505,24 @@ namespace MCGalaxy.SQL {
|
||||
"VARCHAR",
|
||||
};
|
||||
|
||||
static DbType[] all_types = new DbType[] {
|
||||
DbType.Int64, DbType.UInt64, DbType.Binary, DbType.Binary,
|
||||
DbType.Boolean, DbType.Boolean, DbType.String, DbType.DateTime,
|
||||
DbType.DateTime, DbType.Double, DbType.Double, DbType.Int64,
|
||||
DbType.Int32, DbType.SByte, DbType.Int16, DbType.Int32,
|
||||
DbType.Int64, DbType.Int64, DbType.SByte, DbType.Int16,
|
||||
DbType.Int32, DbType.Int64, DbType.Int64, DbType.Int32,
|
||||
DbType.Double, DbType.Single, DbType.Int16, DbType.UInt16,
|
||||
DbType.String, DbType.String, DbType.DateTime, DbType.Byte,
|
||||
DbType.SByte, DbType.UInt32, DbType.Byte, DbType.UInt16,
|
||||
DbType.UInt32, DbType.UInt64, DbType.UInt64, DbType.UInt64,
|
||||
DbType.Byte, DbType.UInt16, DbType.UInt32, DbType.UInt64,
|
||||
DbType.String,
|
||||
static SqlType[] all_types = new SqlType[] {
|
||||
SqlType.Int64, SqlType.UInt64, SqlType.Binary, SqlType.Binary,
|
||||
SqlType.Boolean, SqlType.Boolean, SqlType.String, SqlType.DateTime,
|
||||
SqlType.DateTime, SqlType.Double, SqlType.Double, SqlType.Int64,
|
||||
SqlType.Int32, SqlType.SByte, SqlType.Int16, SqlType.Int32,
|
||||
SqlType.Int64, SqlType.Int64, SqlType.SByte, SqlType.Int16,
|
||||
SqlType.Int32, SqlType.Int64, SqlType.Int64, SqlType.Int32,
|
||||
SqlType.Double, SqlType.Single, SqlType.Int16, SqlType.UInt16,
|
||||
SqlType.String, SqlType.String, SqlType.DateTime, SqlType.Byte,
|
||||
SqlType.SByte, SqlType.UInt32, SqlType.Byte, SqlType.UInt16,
|
||||
SqlType.UInt32, SqlType.UInt64, SqlType.UInt64, SqlType.UInt64,
|
||||
SqlType.Byte, SqlType.UInt16, SqlType.UInt32, SqlType.UInt64,
|
||||
SqlType.String,
|
||||
};
|
||||
}
|
||||
|
||||
enum TypeAffinity {
|
||||
enum TypeAffinity
|
||||
{
|
||||
Uninitialized = 0,
|
||||
Int64 = 1,
|
||||
Double = 2,
|
||||
@ -567,12 +532,14 @@ namespace MCGalaxy.SQL {
|
||||
DateTime = 10,
|
||||
}
|
||||
|
||||
struct SQLiteType {
|
||||
public DbType Type;
|
||||
struct SQLiteType
|
||||
{
|
||||
public SqlType Type;
|
||||
public TypeAffinity Affinity;
|
||||
}
|
||||
|
||||
public sealed class SQLiteDataReader : IDataReader {
|
||||
public sealed class SQLiteDataReader : ISqlReader
|
||||
{
|
||||
SQLiteCommand _command;
|
||||
SQLiteStatement stmt;
|
||||
int readState, rowsAffected, columns;
|
||||
@ -584,8 +551,8 @@ namespace MCGalaxy.SQL {
|
||||
NextResult();
|
||||
}
|
||||
|
||||
public void Dispose() { Close(); }
|
||||
public void Close() {
|
||||
public override void Dispose() { Close(); }
|
||||
public override void Close() {
|
||||
_command = null;
|
||||
stmt = null;
|
||||
fieldNames = null;
|
||||
@ -595,81 +562,62 @@ namespace MCGalaxy.SQL {
|
||||
void CheckClosed() {
|
||||
if (_command == null)
|
||||
throw new InvalidOperationException("DataReader has been closed");
|
||||
if (_command.Connection.State != ConnectionState.Open)
|
||||
throw new InvalidOperationException("Connection was closed, statement was terminated");
|
||||
|
||||
SQLiteConnection.Check(_command.conn);
|
||||
}
|
||||
|
||||
public int Depth { get { return 0; } }
|
||||
public int FieldCount { get { return columns; } }
|
||||
public override int FieldCount { get { return columns; } }
|
||||
|
||||
void VerifyForGet() {
|
||||
CheckClosed();
|
||||
if (readState != 0) throw new InvalidOperationException("No current row");
|
||||
}
|
||||
|
||||
public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public IDataReader GetData(int i) { throw new NotSupportedException(); }
|
||||
public decimal GetDecimal(int i) { throw new NotSupportedException(); }
|
||||
public Guid GetGuid(int i) { throw new NotSupportedException(); }
|
||||
public DataTable GetSchemaTable() { throw new NotSupportedException(); }
|
||||
|
||||
public bool GetBoolean(int i) { return GetInt32(i) != 0; }
|
||||
public byte GetByte(int i) { return (byte)GetInt32(i); }
|
||||
public char GetChar(int i) { return (char)GetInt32(i); }
|
||||
public override bool GetBoolean(int i) { return GetInt32(i) != 0; }
|
||||
|
||||
public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) {
|
||||
public override byte[] GetBytes(int i) {
|
||||
if (CheckAffinity(i) == TypeAffinity.Blob)
|
||||
return stmt.GetBytes(i, (int)fieldOffset, buffer, bufferoffset, length);
|
||||
return stmt.GetBytes(i);
|
||||
throw new InvalidCastException();
|
||||
}
|
||||
|
||||
public string GetDataTypeName(int i) {
|
||||
VerifyForGet();
|
||||
return stmt.ColumnType(i);
|
||||
}
|
||||
|
||||
public DateTime GetDateTime(int i) {
|
||||
public override DateTime GetDateTime(int i) {
|
||||
TypeAffinity aff = CheckAffinity(i);
|
||||
if (aff == TypeAffinity.Int64 || aff == TypeAffinity.Double || aff == TypeAffinity.Text)
|
||||
return stmt.GetDateTime(i);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public double GetDouble(int i) {
|
||||
public override double GetDouble(int i) {
|
||||
TypeAffinity aff = CheckAffinity(i);
|
||||
if (aff == TypeAffinity.Int64 || aff == TypeAffinity.Double)
|
||||
return stmt.GetDouble(i);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Type GetFieldType(int i) {
|
||||
public override Type GetFieldType(int i) {
|
||||
SQLiteType t = GetSQLiteType(i);
|
||||
if (t.Type == DbType.Object)
|
||||
if (t.Type == SqlType.Object)
|
||||
return SQLiteConvert.affinity_to_type[(int)t.Affinity];
|
||||
else
|
||||
return SQLiteConvert.dbtype_to_type[(int)t.Type];
|
||||
return SQLiteConvert.sqltype_to_type[(int)t.Type];
|
||||
}
|
||||
|
||||
public float GetFloat(int i) { return (float)GetDouble(i); }
|
||||
public short GetInt16(int i) { return (short)GetInt32(i); }
|
||||
public string GetName(int i) { return stmt.ColumnName(i); }
|
||||
public override string GetName(int i) { return stmt.ColumnName(i); }
|
||||
|
||||
public int GetInt32(int i) {
|
||||
public override int GetInt32(int i) {
|
||||
if (CheckAffinity(i) == TypeAffinity.Int64)
|
||||
return stmt.GetInt32(i);
|
||||
throw new InvalidCastException();
|
||||
}
|
||||
|
||||
public long GetInt64(int i) {
|
||||
public override long GetInt64(int i) {
|
||||
if (CheckAffinity(i) == TypeAffinity.Int64)
|
||||
return stmt.GetInt64(i);
|
||||
throw new InvalidCastException();
|
||||
}
|
||||
|
||||
public int GetOrdinal(string name) {
|
||||
public override int GetOrdinal(string name) {
|
||||
VerifyForGet();
|
||||
if (fieldNames == null) fieldNames = new string[columns];
|
||||
|
||||
@ -684,23 +632,15 @@ namespace MCGalaxy.SQL {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public string GetString(int i) { return stmt.GetText(i); }
|
||||
public override string GetString(int i) { return stmt.GetText(i); }
|
||||
|
||||
public object GetValue(int i) {
|
||||
public override object GetValue(int i) {
|
||||
VerifyForGet();
|
||||
SQLiteType t = GetSQLiteType(i);
|
||||
return stmt.GetValue(i, t);
|
||||
}
|
||||
|
||||
public int GetValues(object[] values) {
|
||||
int count = Math.Min(columns, values.Length);
|
||||
for (int i = 0; i < count; i++) { values[i] = GetValue(i); }
|
||||
return count;
|
||||
}
|
||||
|
||||
public bool IsClosed { get { return _command == null; } }
|
||||
|
||||
public bool IsDBNull(int i) {
|
||||
public override bool IsDBNull(int i) {
|
||||
VerifyForGet();
|
||||
return stmt.ColumnAffinity(i) == TypeAffinity.Null;
|
||||
}
|
||||
@ -753,7 +693,7 @@ namespace MCGalaxy.SQL {
|
||||
return typ;
|
||||
}
|
||||
|
||||
public bool Read() {
|
||||
public override bool Read() {
|
||||
CheckClosed();
|
||||
|
||||
// First Row was already read at NextResult() level, so don't step again here
|
||||
@ -766,12 +706,11 @@ namespace MCGalaxy.SQL {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int RecordsAffected { get { return rowsAffected; } }
|
||||
public object this[string name] { get { return GetValue(GetOrdinal(name)); } }
|
||||
public object this[int i] { get { return GetValue(i); } }
|
||||
public override int RowsAffected { get { return rowsAffected; } }
|
||||
}
|
||||
|
||||
sealed class SQLiteException : ExternalException {
|
||||
sealed class SQLiteException : ExternalException
|
||||
{
|
||||
SQLiteErrorCode _code;
|
||||
|
||||
public SQLiteException(SQLiteErrorCode code, string message)
|
||||
@ -833,7 +772,8 @@ namespace MCGalaxy.SQL {
|
||||
}
|
||||
}
|
||||
|
||||
static class SQLiteErrorCodes {
|
||||
static class SQLiteErrorCodes
|
||||
{
|
||||
public const int Unknown = -1;
|
||||
public const int Ok = 0;
|
||||
public const int Error = 1;
|
||||
@ -843,79 +783,8 @@ namespace MCGalaxy.SQL {
|
||||
public const int Done = 101;
|
||||
}
|
||||
|
||||
public sealed class SQLiteParameter : IDbDataParameter {
|
||||
int type = -1;
|
||||
object value;
|
||||
string name;
|
||||
|
||||
public DbType DbType {
|
||||
get {
|
||||
if (type == -1) {
|
||||
if (value != null && value != DBNull.Value) {
|
||||
return SQLiteConvert.TypeToDbType(value.GetType());
|
||||
}
|
||||
return DbType.String; // Unassigned default value is String
|
||||
}
|
||||
return (DbType)type;
|
||||
}
|
||||
set { type = (int)value; }
|
||||
}
|
||||
|
||||
public string ParameterName { get { return name; } set { name = value; } }
|
||||
|
||||
public object Value {
|
||||
get { return value; }
|
||||
set {
|
||||
this.value = value;
|
||||
// If the DbType has never been assigned, try to glean one from the value's datatype
|
||||
if (type == -1 && value != null && value != DBNull.Value)
|
||||
type = (int)SQLiteConvert.TypeToDbType(value.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNullable { get { return true; } set { } }
|
||||
public string SourceColumn { get { return ""; } set { } }
|
||||
public ParameterDirection Direction { get { return 0; } set { } }
|
||||
public DataRowVersion SourceVersion { get { return 0; } set { } }
|
||||
|
||||
public byte Precision { get { return 0; } set { } }
|
||||
public byte Scale { get { return 0; } set { } }
|
||||
public int Size { get { return 0; } set { } }
|
||||
}
|
||||
|
||||
public sealed class SQLiteParameterCollection : IDataParameterCollection {
|
||||
internal List<SQLiteParameter> list = new List<SQLiteParameter>();
|
||||
public bool IsSynchronized { get { return false; } }
|
||||
public bool IsFixedSize { get { return false; } }
|
||||
public bool IsReadOnly { get { return false; } }
|
||||
public object SyncRoot { get { return null; } }
|
||||
public IEnumerator GetEnumerator() { return null; }
|
||||
|
||||
public int Add(object value) {
|
||||
list.Add((SQLiteParameter)value);
|
||||
return list.Count - 1;
|
||||
}
|
||||
|
||||
public void Clear() { list.Clear(); }
|
||||
public int Count { get { return list.Count; } }
|
||||
|
||||
public bool Contains(string name) { return false; }
|
||||
public bool Contains(object value) { return false; }
|
||||
public void CopyTo(Array array, int index) { }
|
||||
|
||||
public object this[string name] { get {return null; } set { } }
|
||||
public object this[int index] { get {return null; } set { } }
|
||||
|
||||
public int IndexOf(string name) { return -1; }
|
||||
public int IndexOf(object value) { return -1; }
|
||||
public void Insert(int index, object value) { }
|
||||
|
||||
public void Remove(object value) { }
|
||||
public void RemoveAt(string name) { }
|
||||
public void RemoveAt(int index) { }
|
||||
}
|
||||
|
||||
sealed class SQLiteStatement : IDisposable {
|
||||
sealed class SQLiteStatement : IDisposable
|
||||
{
|
||||
IntPtr handle;
|
||||
internal SQLiteConnection conn;
|
||||
string[] paramNames;
|
||||
@ -980,14 +849,15 @@ namespace MCGalaxy.SQL {
|
||||
return SQLiteConvert.FromUTF8(p, -1);
|
||||
}
|
||||
|
||||
internal void BindAll(SQLiteParameterCollection args) {
|
||||
if (paramNames == null || args.list.Count == 0) return;
|
||||
internal void BindAll(List<string> names, List<object> values) {
|
||||
if (paramNames == null || names.Count == 0) return;
|
||||
|
||||
foreach (SQLiteParameter arg in args.list) {
|
||||
int i = FindParameter(arg.ParameterName);
|
||||
for (int idx = 0; idx < names.Count; idx++)
|
||||
{
|
||||
int i = FindParameter(names[idx]);
|
||||
if (i == -1) continue;
|
||||
|
||||
SQLiteErrorCode n = BindParameter(i + 1, arg);
|
||||
SQLiteErrorCode n = BindParameter(i + 1, values[idx]);
|
||||
if (n != SQLiteErrorCodes.Ok) throw new SQLiteException(n, conn.GetLastError());
|
||||
}
|
||||
}
|
||||
@ -1000,48 +870,38 @@ namespace MCGalaxy.SQL {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SQLiteErrorCode BindParameter(int i, SQLiteParameter param) {
|
||||
object obj = param.Value;
|
||||
DbType type = param.DbType;
|
||||
if (obj != null && type == DbType.Object)
|
||||
type = SQLiteConvert.TypeToDbType(obj.GetType());
|
||||
|
||||
SQLiteErrorCode BindParameter(int i, object obj) {
|
||||
if (obj == null || obj == DBNull.Value) {
|
||||
return Interop.sqlite3_bind_null(handle, i);
|
||||
}
|
||||
|
||||
SqlType type = SQLiteConvert.TypeToDbType(obj.GetType());
|
||||
switch (type) {
|
||||
case DbType.DateTime:
|
||||
//
|
||||
// NOTE: The old method (commented below) does not honor the selected date format
|
||||
// for the connection.
|
||||
// _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, cultureInfo));
|
||||
return Bind_DateTime(i, (obj is string) ?
|
||||
SQLiteConvert.ToDateTime((string)obj) :
|
||||
Convert.ToDateTime(obj, CultureInfo.InvariantCulture));
|
||||
case DbType.Boolean:
|
||||
case SqlType.DateTime:
|
||||
return Bind_DateTime(i, Convert.ToDateTime(obj, CultureInfo.InvariantCulture));
|
||||
case SqlType.Boolean:
|
||||
return Bind_Int32(i, Convert.ToBoolean(obj) ? 1 : 0);
|
||||
case DbType.SByte:
|
||||
case SqlType.SByte:
|
||||
return Bind_Int32(i, Convert.ToSByte(obj));
|
||||
case DbType.Int16:
|
||||
case SqlType.Int16:
|
||||
return Bind_Int32(i, Convert.ToInt16(obj));
|
||||
case DbType.Int32:
|
||||
case SqlType.Int32:
|
||||
return Bind_Int32(i, Convert.ToInt32(obj));
|
||||
case DbType.Int64:
|
||||
case SqlType.Int64:
|
||||
return Bind_Int64(i, Convert.ToInt64(obj));
|
||||
case DbType.Byte:
|
||||
case SqlType.Byte:
|
||||
return Bind_Int32(i, Convert.ToByte(obj));
|
||||
case DbType.UInt16:
|
||||
case SqlType.UInt16:
|
||||
return Bind_Int32(i, Convert.ToUInt16(obj));
|
||||
case DbType.UInt32:
|
||||
case SqlType.UInt32:
|
||||
return Bind_Int32(i, (int)Convert.ToUInt32(obj));
|
||||
case DbType.UInt64:
|
||||
case SqlType.UInt64:
|
||||
return Bind_Int64(i, (long)Convert.ToUInt64(obj));
|
||||
case DbType.Single:
|
||||
case DbType.Double:
|
||||
case DbType.Decimal:
|
||||
case SqlType.Single:
|
||||
case SqlType.Double:
|
||||
case SqlType.Decimal:
|
||||
return Interop.sqlite3_bind_double(handle, i, Convert.ToDouble(obj));
|
||||
case DbType.Binary:
|
||||
case SqlType.Binary:
|
||||
byte[] b = (byte[])obj;
|
||||
return Interop.sqlite3_bind_blob(handle, i, b, b.Length, (IntPtr)(-1));
|
||||
default:
|
||||
@ -1067,14 +927,11 @@ namespace MCGalaxy.SQL {
|
||||
}
|
||||
|
||||
internal object GetValue(int index, SQLiteType typ) {
|
||||
if (typ.Type == DbType.DateTime) return GetDateTime(index);
|
||||
if (typ.Type == SqlType.DateTime) return GetDateTime(index);
|
||||
|
||||
switch (typ.Affinity) {
|
||||
case TypeAffinity.Blob:
|
||||
int n = Interop.sqlite3_column_bytes(handle, index);
|
||||
byte[] b = new byte[n];
|
||||
GetBytes(index, 0, b, 0, n);
|
||||
return b;
|
||||
return GetBytes(index);
|
||||
case TypeAffinity.Double:
|
||||
return GetDouble(index);
|
||||
case TypeAffinity.Int64:
|
||||
@ -1106,30 +963,26 @@ namespace MCGalaxy.SQL {
|
||||
return SQLiteConvert.ToDateTime(GetText(index));
|
||||
}
|
||||
|
||||
internal long GetBytes(int index, int srcOffset, byte[] dst, int dstOffset, int dstLen) {
|
||||
internal byte[] GetBytes(int index) {
|
||||
int srcLen = Interop.sqlite3_column_bytes(handle, index);
|
||||
if (dst == null) return srcLen;
|
||||
if (srcLen <= 0) return null;
|
||||
byte[] dst = new byte[srcLen];
|
||||
|
||||
int count = dstLen;
|
||||
if (count + dstOffset > dst.Length) count = dst.Length - dstOffset;
|
||||
if (count + srcOffset > srcLen) count = srcLen - srcOffset;
|
||||
|
||||
if (count <= 0) return 0;
|
||||
IntPtr src = Interop.sqlite3_column_blob(handle, index);
|
||||
Marshal.Copy((IntPtr)(src.ToInt64() + srcOffset), dst, dstOffset, count);
|
||||
return count;
|
||||
Marshal.Copy(src, dst, 0, srcLen);
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SQLiteTransaction : IDbTransaction {
|
||||
public sealed class SQLiteTransaction : ISqlTransaction
|
||||
{
|
||||
SQLiteConnection conn;
|
||||
|
||||
internal SQLiteTransaction(SQLiteConnection connection) {
|
||||
conn = connection;
|
||||
if (conn._transactionLevel++ == 0) {
|
||||
try {
|
||||
using (IDbCommand cmd = conn.CreateCommand()) {
|
||||
cmd.CommandText = "BEGIN IMMEDIATE";
|
||||
using (ISqlCommand cmd = conn.CreateCommand("BEGIN IMMEDIATE")) {
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
} catch (SQLiteException) {
|
||||
@ -1141,29 +994,25 @@ namespace MCGalaxy.SQL {
|
||||
}
|
||||
|
||||
bool disposed;
|
||||
public void Dispose() {
|
||||
public override void Dispose() {
|
||||
if (disposed) return;
|
||||
if (IsValid(false)) IssueRollback(false);
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public void Commit() {
|
||||
public override void Commit() {
|
||||
SQLiteConnection.Check(conn);
|
||||
IsValid(true);
|
||||
|
||||
if (--conn._transactionLevel == 0) {
|
||||
using (IDbCommand cmd = conn.CreateCommand()) {
|
||||
cmd.CommandText = "COMMIT";
|
||||
using (ISqlCommand cmd = conn.CreateCommand("COMMIT")) {
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
conn = null;
|
||||
}
|
||||
|
||||
public IDbConnection Connection { get { return conn; } }
|
||||
public IsolationLevel IsolationLevel { get { return IsolationLevel.Serializable; } }
|
||||
|
||||
public void Rollback() {
|
||||
public override void Rollback() {
|
||||
SQLiteConnection.Check(conn);
|
||||
IsValid(true);
|
||||
IssueRollback(true);
|
||||
@ -1173,8 +1022,7 @@ namespace MCGalaxy.SQL {
|
||||
if (conn == null) return;
|
||||
|
||||
try {
|
||||
using (IDbCommand cmd = conn.CreateCommand()) {
|
||||
cmd.CommandText = "ROLLBACK";
|
||||
using (ISqlCommand cmd = conn.CreateCommand("ROLLBACK")) {
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
} catch {
|
||||
@ -1189,7 +1037,7 @@ namespace MCGalaxy.SQL {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (conn.State != ConnectionState.Open) {
|
||||
if (conn.handle == IntPtr.Zero) {
|
||||
if (throwError) throw new SQLiteException("Connection was closed");
|
||||
return false;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user