//
// Copyright (c) 2009-2012 Krueger Systems, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if WINDOWS_PHONE && !USE_WP8_NATIVE_SQLITE
#define USE_CSHARP_SQLITE
#endif
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
#if USE_CSHARP_SQLITE
using Sqlite3 = Community.CsharpSqlite.Sqlite3;
using Sqlite3DatabaseHandle = Community.CsharpSqlite.Sqlite3.sqlite3;
using Sqlite3Statement = Community.CsharpSqlite.Sqlite3.Vdbe;
#elif USE_WP8_NATIVE_SQLITE
using Sqlite3 = Sqlite.Sqlite3;
using Sqlite3DatabaseHandle = Sqlite.Database;
using Sqlite3Statement = Sqlite.Statement;
#else
using Sqlite3DatabaseHandle = System.IntPtr;
using Sqlite3Statement = System.IntPtr;
#endif
///
/// SQLite4Unity3d´Â Unity ȯ°æ¿¡¼ SQLite¸¦ ½±°Ô »ç¿ëÇÒ ¼ö ÀÖ°Ô ÇØÁÖ´Â ¶óÀ̺귯¸®ÀÔ´Ï´Ù.
/// ÀÌ Å¬·¡½º´Â SQLite µ¥ÀÌÅͺ£À̽º¿¡ ´ëÇÑ ¿¬°áÀ» °ü¸®ÇÕ´Ï´Ù.
///
namespace SQLite4Unity3d
{
///
/// SQLite ÀÛ¾÷ Áß ¹ß»ýÇÏ´Â ¿¹¿Ü¸¦ ó¸®Çϱâ À§ÇÑ Å¬·¡½ºÀÔ´Ï´Ù.
///
public class SQLiteException : Exception
{
public SQLite3.Result Result { get; private set; }
protected SQLiteException(SQLite3.Result r, string message) : base(message)
{
Result = r;
}
public static SQLiteException New(SQLite3.Result r, string message)
{
return new SQLiteException(r, message);
}
}
///
/// NOT NULL Á¦¾à Á¶°Ç À§¹Ý ½Ã ¹ß»ýÇÏ´Â ¿¹¿Ü¸¦ ó¸®Çϱâ À§ÇÑ Å¬·¡½ºÀÔ´Ï´Ù.
///
public class NotNullConstraintViolationException : SQLiteException
{
public IEnumerable Columns { get; protected set; }
protected NotNullConstraintViolationException(SQLite3.Result r, string message)
: this(r, message, null, null)
{
}
protected NotNullConstraintViolationException(SQLite3.Result r, string message, TableMapping mapping, object obj)
: base(r, message)
{
if (mapping != null && obj != null)
{
this.Columns = from c in mapping.Columns
where c.IsNullable == false && c.GetValue(obj) == null
select c;
}
}
public static new NotNullConstraintViolationException New(SQLite3.Result r, string message)
{
return new NotNullConstraintViolationException(r, message);
}
public static NotNullConstraintViolationException New(SQLite3.Result r, string message, TableMapping mapping, object obj)
{
return new NotNullConstraintViolationException(r, message, mapping, obj);
}
public static NotNullConstraintViolationException New(SQLiteException exception, TableMapping mapping, object obj)
{
return new NotNullConstraintViolationException(exception.Result, exception.Message, mapping, obj);
}
}
///
/// SQLite µ¥ÀÌÅͺ£À̽º ÆÄÀÏÀ» ¿±â À§ÇÑ ¿É¼ÇµéÀ» Á¤ÀÇÇÕ´Ï´Ù.
///
[Flags]
public enum SQLiteOpenFlags
{
ReadOnly = 1, ReadWrite = 2, Create = 4,
NoMutex = 0x8000, FullMutex = 0x10000,
SharedCache = 0x20000, PrivateCache = 0x40000,
ProtectionComplete = 0x00100000,
ProtectionCompleteUnlessOpen = 0x00200000,
ProtectionCompleteUntilFirstUserAuthentication = 0x00300000,
ProtectionNone = 0x00400000
}
///
/// Å×ÀÌºí »ý¼º ½Ã »ç¿ëµÇ´Â Ç÷¡±×ÀÔ´Ï´Ù.
///
[Flags]
public enum CreateFlags
{
None = 0,
ImplicitPK = 1, // create a primary key for field called 'Id' (Orm.ImplicitPkName)
ImplicitIndex = 2, // create an index for fields ending in 'Id' (Orm.ImplicitIndexSuffix)
AllImplicit = 3, // do both above
AutoIncPK = 4 // force PK field to be auto inc
}
///
/// SQLite µ¥ÀÌÅͺ£À̽º¿¡ ´ëÇÑ ¿¸° ¿¬°áÀ» ³ªÅ¸³À´Ï´Ù.
///
public partial class SQLiteConnection : IDisposable
{
private bool _open;
private TimeSpan _busyTimeout;
private Dictionary _mappings = null;
private Dictionary _tables = null;
private System.Diagnostics.Stopwatch _sw;
private TimeSpan _elapsed = default(TimeSpan);
private int _transactionDepth = 0;
private Random _rand = new Random();
public Sqlite3DatabaseHandle Handle { get; private set; }
internal static readonly Sqlite3DatabaseHandle NullHandle = default(Sqlite3DatabaseHandle);
public string DatabasePath { get; private set; }
// µ¿±âÈ °´Ã¼ÀÇ »çÀüÀÔ´Ï´Ù.
//
// µ¥ÀÌÅͺ£À̽º ÆÄÀÏ ¼Õ»óÀ» ¹æÁöÇϱâ À§ÇØ µ¥ÀÌÅͺ£À̽º ÆÄÀÏ¿¡ *µ¿±âÀûÀ¸·Î* Á¢±ÙÇØ¾ß ÇÕ´Ï´Ù.
// À̸¦ À§ÇØ °¢ µ¥ÀÌÅͺ£À̽º ÆÄÀÏ¿¡ ´ëÇÑ µ¿±âÈ °´Ã¼¸¦ »ý¼ºÇÏ°í ¸ðµç ¿¬°á °£¿¡ °øÀ¯Çϱâ À§ÇØ
// Á¤Àû »çÀü¿¡ ÀúÀåÇÕ´Ï´Ù.
// »çÀüÀÇ Å°´Â µ¥ÀÌÅͺ£À̽º ÆÄÀÏ °æ·ÎÀ̰í, °ªÀº lock() ¹®¿¡¼ »ç¿ëÇÒ °´Ã¼ÀÔ´Ï´Ù.
//
// »ç¿ë »ç·Ê:
// - µ¥ÀÌÅͺ£À̽º ÆÄÀÏ Àá±ÝÀº ¾Ï½ÃÀûÀ¸·Î ÀÚµ¿À¸·Î ÀÌ·ç¾îÁý´Ï´Ù.
// - ±³Âø »óŸ¦ ¹æÁöÇϱâ À§ÇØ ÀÀ¿ë ÇÁ·Î±×·¥Àº ´ÙÀ½°ú °°Àº ¹æ¹ýÀ¸·Î ¸í½ÃÀûÀ¸·Î µ¥ÀÌÅͺ£À̽º ÆÄÀÏÀ» Àá±Û ¼ö ÀÖ½À´Ï´Ù:
// - RunInTransaction(Action)Àº Æ®·£Àè¼Ç Áß¿¡ µ¥ÀÌÅͺ£À̽º¸¦ Àá±Þ´Ï´Ù(»ðÀÔ/¾÷µ¥ÀÌÆ®¿ë).
// - RunInDatabaseLock(Action)Àº ºñ½ÁÇÏ°Ô µ¥ÀÌÅͺ£À̽º¸¦ Àá±×Áö¸¸ Æ®·£Àè¼ÇÀº ¾ø½À´Ï´Ù(Äõ¸®¿ë).
private static Dictionary syncObjects = new Dictionary();
#region debug tracing
public bool Trace { get; set; }
public bool TimeExecution { get; set; }
public delegate void TraceHandler(string message);
public event TraceHandler TraceEvent;
internal void InvokeTrace(string message)
{
if (TraceEvent != null)
{
TraceEvent(message);
}
}
public delegate void TimeExecutionHandler(TimeSpan executionTime, TimeSpan totalExecutionTime);
public event TimeExecutionHandler TimeExecutionEvent;
internal void InvokeTimeExecution(TimeSpan executionTime, TimeSpan totalExecutionTime)
{
if (TimeExecutionEvent != null)
{
TimeExecutionEvent(executionTime, totalExecutionTime);
}
}
#endregion
public bool StoreDateTimeAsTicks { get; private set; }
///
/// »õ·Î¿î SQLiteConnectionÀ» »ý¼ºÇϰí ÁöÁ¤µÈ °æ·ÎÀÇ SQLite µ¥ÀÌÅͺ£À̽º¸¦ ¿±´Ï´Ù.
///
///
/// µ¥ÀÌÅͺ£À̽º ÆÄÀÏÀÇ °æ·Î¸¦ ÁöÁ¤ÇÕ´Ï´Ù.
///
///
/// DateTime ¼Ó¼ºÀ» ƽ(true) ¶Ç´Â ¹®ÀÚ¿(false)·Î ÀúÀåÇÒÁö ÁöÁ¤ÇÕ´Ï´Ù.
/// »õ ÇÁ·ÎÁ§Æ®¿¡¼´Â ¹Ýµå½Ã true·Î ¼³Á¤ÇÏ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. false´Â ÀÌÀü ¹öÀü°úÀÇ È£È¯¼ºÀ» À§ÇÑ °ÍÀÔ´Ï´Ù.
/// true·Î ¼³Á¤ÇÏ¸é ¼º´ÉÀÌ Å©°Ô Çâ»óµÇ¸ç ´ÜÁ¡ÀÌ ¾ø½À´Ï´Ù.
///
///
///
/// // ±âº» µ¥ÀÌÅͺ£À̽º ¿¬°á »ý¼º
/// var db = new SQLiteConnection(Application.persistentDataPath + "/myDatabase.db", true);
///
/// // Å×ÀÌºí »ý¼º
/// db.CreateTable<Person>();
///
///
public SQLiteConnection(string databasePath, bool storeDateTimeAsTicks = false)
: this(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks)
{
}
///
/// »õ·Î¿î SQLiteConnectionÀ» »ý¼ºÇϰí ÁöÁ¤µÈ °æ·ÎÀÇ SQLite µ¥ÀÌÅͺ£À̽º¸¦ ¿±´Ï´Ù.
///
///
/// µ¥ÀÌÅͺ£À̽º ÆÄÀÏÀÇ °æ·Î¸¦ ÁöÁ¤ÇÕ´Ï´Ù.
///
///
/// µ¥ÀÌÅͺ£À̽º¸¦ ¿©´Â ¹æ¹ýÀ» ÁöÁ¤ÇÏ´Â Ç÷¡±×ÀÔ´Ï´Ù.
///
///
/// DateTime ¼Ó¼ºÀ» ƽ(true) ¶Ç´Â ¹®ÀÚ¿(false)·Î ÀúÀåÇÒÁö ÁöÁ¤ÇÕ´Ï´Ù.
/// »õ ÇÁ·ÎÁ§Æ®¿¡¼´Â ¹Ýµå½Ã true·Î ¼³Á¤ÇÏ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. false´Â ÀÌÀü ¹öÀü°úÀÇ È£È¯¼ºÀ» À§ÇÑ °ÍÀÔ´Ï´Ù.
/// true·Î ¼³Á¤ÇÏ¸é ¼º´ÉÀÌ Å©°Ô Çâ»óµÇ¸ç ´ÜÁ¡ÀÌ ¾ø½À´Ï´Ù.
///
///
///
/// // Àбâ Àü¿ë ¸ðµå·Î µ¥ÀÌÅͺ£À̽º ¿±â
/// var dbReadOnly = new SQLiteConnection(
/// Application.persistentDataPath + "/myDatabase.db",
/// SQLiteOpenFlags.ReadOnly,
/// true);
///
///
public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false)
{
if (string.IsNullOrEmpty(databasePath))
throw new ArgumentException("Must be specified", "databasePath");
DatabasePath = databasePath;
mayCreateSyncObject(databasePath);
#if NETFX_CORE
SQLite3.SetDirectory(/*temp directory type*/2, Windows.Storage.ApplicationData.Current.TemporaryFolder.Path);
#endif
Sqlite3DatabaseHandle handle;
#if SILVERLIGHT || USE_CSHARP_SQLITE
var r = SQLite3.Open (databasePath, out handle, (int)openFlags, IntPtr.Zero);
#else
// open using the byte[]
// in the case where the path may include Unicode
// force open to using UTF-8 using sqlite3_open_v2
var databasePathAsBytes = GetNullTerminatedUtf8(DatabasePath);
var r = SQLite3.Open(databasePathAsBytes, out handle, (int)openFlags, IntPtr.Zero);
#endif
Handle = handle;
if (r != SQLite3.Result.OK)
{
throw SQLiteException.New(r, String.Format("Could not open database file: {0} ({1})", DatabasePath, r));
}
_open = true;
StoreDateTimeAsTicks = storeDateTimeAsTicks;
BusyTimeout = TimeSpan.FromSeconds(0.1);
}
static SQLiteConnection()
{
if (_preserveDuringLinkMagic)
{
var ti = new ColumnInfo();
ti.Name = "magic";
}
}
///
/// ÁÖ¾îÁø µ¥ÀÌÅͺ£À̽º °æ·Î¿¡ ´ëÇÑ µ¿±âÈ °´Ã¼¸¦ »ý¼ºÇÕ´Ï´Ù(¾ÆÁ÷ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì).
///
/// µ¥ÀÌÅͺ£À̽º ÆÄÀÏ °æ·Î
void mayCreateSyncObject(string databasePath)
{
if (!syncObjects.ContainsKey(databasePath))
{
syncObjects[databasePath] = new object();
}
}
///
/// µ¥ÀÌÅͺ£À̽º ÆÄÀÏÀ» ¾÷µ¥ÀÌÆ®Çϱâ À§ÇÑ µ¿±âÈ °´Ã¼¸¦ °¡Á®¿É´Ï´Ù.
///
/// µ¿±âÈ °´Ã¼.
public object SyncObject { get { return syncObjects[DatabasePath]; } }
///
/// È®Àå ±â´É ·Îµå¸¦ Ȱ¼ºÈ ¶Ç´Â ºñȰ¼ºÈÇÕ´Ï´Ù.
///
/// 1À̸é Ȱ¼ºÈ, 0ÀÌ¸é ºñȰ¼ºÈ
///
///
/// // SQLite È®Àå ±â´É Ȱ¼ºÈ
/// db.EnableLoadExtension(1);
///
///
public void EnableLoadExtension(int onoff)
{
SQLite3.Result r = SQLite3.EnableLoadExtension(Handle, onoff);
if (r != SQLite3.Result.OK)
{
string msg = SQLite3.GetErrmsg(Handle);
throw SQLiteException.New(r, msg);
}
}
///
/// ¹®ÀÚ¿À» UTF-8·Î ÀÎÄÚµùÇϰí NULL Á¾·á ¹ÙÀÌÆ®¸¦ Ãß°¡ÇÕ´Ï´Ù.
///
/// ÀÎÄÚµùÇÒ ¹®ÀÚ¿
/// NULL Á¾·áµÈ UTF-8 ¹ÙÀÌÆ® ¹è¿
static byte[] GetNullTerminatedUtf8(string s)
{
var utf8Length = System.Text.Encoding.UTF8.GetByteCount(s);
var bytes = new byte[utf8Length + 1];
utf8Length = System.Text.Encoding.UTF8.GetBytes(s, 0, s.Length, bytes, 0);
return bytes;
}
///
/// MonoTouch ¸µÄ¿°¡ º¼ ¼ö ÀÖÁö¸¸ ½ÇÇàÇÏÁö ¾Ê±â¸¦ ¹Ù¶ó´Â Äڵ带 ³ª¿ÇÏ´Â µ¥ »ç¿ëµË´Ï´Ù.
///
#pragma warning disable 649
static bool _preserveDuringLinkMagic;
#pragma warning restore 649
///
/// Å×À̺íÀÌ Àá°åÀ» ¶§ ÁöÁ¤µÈ ½Ã°£ µ¿¾È ´ë±âÇÏ´Â ºñÁö Çڵ鷯¸¦ ¼³Á¤ÇÕ´Ï´Ù.
/// Çڵ鷯´Â ÀÇ ÃÑ ½Ã°£ÀÌ ´©ÀûµÉ ¶§±îÁö ¿©·¯ ¹ø ´ë±âÇÕ´Ï´Ù.
///
///
///
/// // ´ë±â ½Ã°£ ¼³Á¤
/// db.BusyTimeout = TimeSpan.FromSeconds(5);
///
///
public TimeSpan BusyTimeout
{
get { return _busyTimeout; }
set
{
_busyTimeout = value;
if (Handle != NullHandle)
{
SQLite3.BusyTimeout(Handle, (int)_busyTimeout.TotalMilliseconds);
}
}
}
///
/// ¿¬°áÀÌ ÇöÀç ÀÌÇØÇϴ ŸÀÔ¿¡¼ Å×À̺í·ÎÀÇ ¸ÅÇÎÀ» ¹ÝȯÇÕ´Ï´Ù.
///
public IEnumerable TableMappings
{
get
{
return _tables != null ? _tables.Values : Enumerable.Empty();
}
}
///
/// ÁÖ¾îÁø ŸÀÔ¿¡ ´ëÇØ ÀÚµ¿ »ý¼ºµÈ ¸ÅÇÎÀ» °Ë»öÇÕ´Ï´Ù.
///
///
/// µ¥ÀÌÅͺ£À̽º¿¡ ´ëÇÑ ¸ÅÇÎÀÌ ¹ÝȯµÇ´Â ŸÀÔÀÔ´Ï´Ù.
///
///
/// ¸í¸í ±ÔÄ¢¿¡ µû¶ó ¾Ï½ÃÀû PK¿Í À妽º¸¦ Çã¿ëÇÏ´Â ¼±ÅÃÀû Ç÷¡±×
///
///
/// ¸ÅÇÎÀº µ¥ÀÌÅͺ£À̽º ¿ÀÇ ½ºÅ°¸¶¸¦ ³ªÅ¸³»¸ç °´Ã¼ÀÇ ¼Ó¼ºÀ» ¼³Á¤Çϰí
/// °¡Á®¿À´Â ¸Þ¼µå¸¦ Æ÷ÇÔÇÕ´Ï´Ù.
///
///
///
/// // Person Ŭ·¡½º¿¡ ´ëÇÑ ¸ÅÇÎ ¾ò±â
/// var mapping = db.GetMapping(typeof(Person));
///
/// // ¸ÅÇÎÀÇ Å×À̺í À̸§ È®ÀÎ
/// Console.WriteLine("Å×À̺í À̸§: " + mapping.TableName);
///
///
public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None)
{
if (_mappings == null)
{
_mappings = new Dictionary();
}
TableMapping map;
if (!_mappings.TryGetValue(type.FullName, out map))
{
map = new TableMapping(type, createFlags);
_mappings[type.FullName] = map;
}
return map;
}
///
/// ÁÖ¾îÁø ŸÀÔ¿¡ ´ëÇØ ÀÚµ¿ »ý¼ºµÈ ¸ÅÇÎÀ» °Ë»öÇÕ´Ï´Ù.
///
///
/// ¸ÅÇÎÀº µ¥ÀÌÅͺ£À̽º ¿ÀÇ ½ºÅ°¸¶¸¦ ³ªÅ¸³»¸ç °´Ã¼ÀÇ ¼Ó¼ºÀ» ¼³Á¤Çϰí
/// °¡Á®¿À´Â ¸Þ¼µå¸¦ Æ÷ÇÔÇÕ´Ï´Ù.
///
///
///
/// // Á¦³×¸¯ ŸÀÔÀ¸·Î ¸ÅÇÎ ¾ò±â
/// var mapping = db.GetMapping<Person>();
///
///
public TableMapping GetMapping()
{
return GetMapping(typeof(T));
}
private struct IndexedColumn
{
public int Order;
public string ColumnName;
}
private struct IndexInfo
{
public string IndexName;
public string TableName;
public bool Unique;
public List Columns;
}
///
/// µ¥ÀÌÅͺ£À̽º¿¡¼ "drop table" ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù. ÀÌ ÀÛ¾÷Àº º¹±¸ÇÒ ¼ö ¾ø½À´Ï´Ù.
///
///
///
/// // Person Å×ÀÌºí »èÁ¦
/// db.DropTable<Person>();
///
///
public int DropTable()
{
var map = GetMapping(typeof(T));
var query = string.Format("drop table if exists \"{0}\"", map.TableName);
return Execute(query);
}
///
/// µ¥ÀÌÅͺ£À̽º¿¡¼ "create table if not exists" ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù.
/// ¶ÇÇÑ Å×ÀÌºí ¿¿¡ ÁöÁ¤µÈ À妽º¸¦ »ý¼ºÇÕ´Ï´Ù.
/// ÁöÁ¤µÈ ŸÀÔ¿¡¼ ÀÚµ¿À¸·Î »ý¼ºµÈ ½ºÅ°¸¶¸¦ »ç¿ëÇÕ´Ï´Ù.
/// ³ªÁß¿¡ GetMappingÀ» È£ÃâÇÏ¿© ÀÌ ½ºÅ°¸¶¿¡ ¾×¼¼½ºÇÒ ¼ö ÀÖ½À´Ï´Ù.
///
///
/// µ¥ÀÌÅͺ£À̽º ½ºÅ°¸¶¿¡ Ãß°¡µÈ Ç׸ñÀÇ ¼ö¸¦ ¹ÝȯÇÕ´Ï´Ù.
///
///
///
/// // Person Ŭ·¡½º¸¦ Ç¥ÇöÇÏ´Â Å×ÀÌºí »ý¼º
/// db.CreateTable<Person>();
///
/// // ¾Ï½ÃÀû À妽º »ý¼º ¿É¼Ç »ç¿ë
/// db.CreateTable<Person>(CreateFlags.ImplicitIndex);
///
///
public int CreateTable(CreateFlags createFlags = CreateFlags.None)
{
return CreateTable(typeof(T), createFlags);
}
///
/// µ¥ÀÌÅͺ£À̽º¿¡¼ "create table if not exists" ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù.
/// ¶ÇÇÑ Å×ÀÌºí ¿¿¡ ÁöÁ¤µÈ À妽º¸¦ »ý¼ºÇÕ´Ï´Ù.
/// ÁöÁ¤µÈ ŸÀÔ¿¡¼ ÀÚµ¿À¸·Î »ý¼ºµÈ ½ºÅ°¸¶¸¦ »ç¿ëÇÕ´Ï´Ù.
/// ³ªÁß¿¡ GetMappingÀ» È£ÃâÇÏ¿© ÀÌ ½ºÅ°¸¶¿¡ ¾×¼¼½ºÇÒ ¼ö ÀÖ½À´Ï´Ù.
///
/// µ¥ÀÌÅͺ£À̽º Å×À̺í·Î ¹Ý¿µÇÒ Å¸ÀÔÀÔ´Ï´Ù.
/// ¸í¸í ±ÔÄ¢¿¡ µû¸¥ ¾Ï½ÃÀû PK ¹× À妽º¸¦ Çã¿ëÇÏ´Â ¼±ÅÃÀû Ç÷¡±×ÀÔ´Ï´Ù.
///
/// µ¥ÀÌÅͺ£À̽º ½ºÅ°¸¶¿¡ Ãß°¡µÈ Ç׸ñÀÇ ¼ö¸¦ ¹ÝȯÇÕ´Ï´Ù.
///
///
///
/// // Type °´Ã¼¸¦ »ç¿ëÇÏ¿© Å×ÀÌºí »ý¼º
/// db.CreateTable(typeof(Person), CreateFlags.AutoIncPK);
///
///
public int CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None)
{
if (_tables == null)
{
_tables = new Dictionary();
}
TableMapping map;
if (!_tables.TryGetValue(ty.FullName, out map))
{
map = GetMapping(ty, createFlags);
_tables.Add(ty.FullName, map);
}
var query = "create table if not exists \"" + map.TableName + "\"(\n";
var decls = map.Columns.Select(p => Orm.SqlDecl(p, StoreDateTimeAsTicks));
var decl = string.Join(",\n", decls.ToArray());
query += decl;
query += ")";
var count = Execute(query);
if (count == 0)
{ //Possible bug: This always seems to return 0?
// Table already exists, migrate it
MigrateTable(map);
}
var indexes = new Dictionary();
foreach (var c in map.Columns)
{
foreach (var i in c.Indices)
{
var iname = i.Name ?? map.TableName + "_" + c.Name;
IndexInfo iinfo;
if (!indexes.TryGetValue(iname, out iinfo))
{
iinfo = new IndexInfo
{
IndexName = iname,
TableName = map.TableName,
Unique = i.Unique,
Columns = new List()
};
indexes.Add(iname, iinfo);
}
if (i.Unique != iinfo.Unique)
throw new Exception("All the columns in an index must have the same value for their Unique property");
iinfo.Columns.Add(new IndexedColumn
{
Order = i.Order,
ColumnName = c.Name
});
}
}
foreach (var indexName in indexes.Keys)
{
var index = indexes[indexName];
string[] columnNames = new string[index.Columns.Count];
if (index.Columns.Count == 1)
{
columnNames[0] = index.Columns[0].ColumnName;
}
else
{
index.Columns.Sort((lhs, rhs) => {
return lhs.Order - rhs.Order;
});
for (int i = 0, end = index.Columns.Count; i < end; ++i)
{
columnNames[i] = index.Columns[i].ColumnName;
}
}
count += CreateIndex(indexName, index.TableName, columnNames, index.Unique);
}
return count;
}
///
/// ÁöÁ¤µÈ Å×À̺í°ú ¿¿¡ ´ëÇÑ À妽º¸¦ »ý¼ºÇÕ´Ï´Ù.
///
/// »ý¼ºÇÒ À妽ºÀÇ À̸§
/// µ¥ÀÌÅͺ£À̽º Å×À̺í À̸§
/// À妽ÌÇÒ ¿ À̸§ ¹è¿
/// À妽º°¡ °íÀ¯ÇØ¾ß ÇÏ´ÂÁö ¿©ºÎ
///
///
/// // ¿©·¯ ¿¿¡ ´ëÇÑ °íÀ¯ À妽º »ý¼º
/// db.CreateIndex("personNameIndex", "Person", new[] { "FirstName", "LastName" }, true);
///
///
public int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false)
{
const string sqlFormat = "create {2} index if not exists \"{3}\" on \"{0}\"(\"{1}\")";
var sql = String.Format(sqlFormat, tableName, string.Join("\", \"", columnNames), unique ? "unique" : "", indexName);
return Execute(sql);
}
///
/// ÁöÁ¤µÈ Å×À̺í°ú ¿¿¡ ´ëÇÑ À妽º¸¦ »ý¼ºÇÕ´Ï´Ù.
///
/// »ý¼ºÇÒ À妽ºÀÇ À̸§
/// µ¥ÀÌÅͺ£À̽º Å×À̺í À̸§
/// À妽ÌÇÒ ¿ À̸§
/// À妽º°¡ °íÀ¯ÇØ¾ß ÇÏ´ÂÁö ¿©ºÎ
///
///
/// // ´ÜÀÏ ¿¿¡ ´ëÇÑ À妽º »ý¼º
/// db.CreateIndex("emailIndex", "Person", "Email", true);
///
///
public int CreateIndex(string indexName, string tableName, string columnName, bool unique = false)
{
return CreateIndex(indexName, tableName, new string[] { columnName }, unique);
}
///
/// ÁöÁ¤µÈ Å×À̺í°ú ¿¿¡ ´ëÇÑ À妽º¸¦ »ý¼ºÇÕ´Ï´Ù.
///
/// µ¥ÀÌÅͺ£À̽º Å×À̺í À̸§
/// À妽ÌÇÒ ¿ À̸§
/// À妽º°¡ °íÀ¯ÇØ¾ß ÇÏ´ÂÁö ¿©ºÎ
///
///
/// // Å×À̺í°ú ¿ À̸§¿¡¼ À妽º À̸§ ÀÚµ¿ »ý¼º
/// db.CreateIndex("Person", "Age", false);
/// // »ý¼ºµÈ À妽º À̸§Àº "Person_Age"
///
///
public int CreateIndex(string tableName, string columnName, bool unique = false)
{
return CreateIndex(tableName + "_" + columnName, tableName, columnName, unique);
}
///
/// ÁöÁ¤µÈ Å×À̺í°ú ¿¿¡ ´ëÇÑ À妽º¸¦ »ý¼ºÇÕ´Ï´Ù.
///
/// µ¥ÀÌÅͺ£À̽º Å×À̺í À̸§
/// À妽ÌÇÒ ¿ À̸§ ¹è¿
/// À妽º°¡ °íÀ¯ÇØ¾ß ÇÏ´ÂÁö ¿©ºÎ
///
///
/// // Å×À̺í°ú ¿©·¯ ¿ À̸§¿¡¼ À妽º À̸§ ÀÚµ¿ »ý¼º
/// db.CreateIndex("Person", new[] { "FirstName", "LastName" }, true);
/// // »ý¼ºµÈ À妽º À̸§Àº "Person_FirstName_LastName"
///
///
public int CreateIndex(string tableName, string[] columnNames, bool unique = false)
{
return CreateIndex(tableName + "_" + string.Join("_", columnNames), tableName, columnNames, unique);
}
///
/// ÁöÁ¤µÈ °´Ã¼ ¼Ó¼º¿¡ ´ëÇÑ À妽º¸¦ »ý¼ºÇÕ´Ï´Ù.
/// ¿¹½Ã: CreateIndex<Client>(c => c.Name);
///
/// µ¥ÀÌÅͺ£À̽º Å×ÀÌºí¿¡ ¹Ý¿µÇÒ Å¸ÀÔ.
/// À妽ÌÇÒ ¼Ó¼º
/// À妽º°¡ °íÀ¯ÇØ¾ß ÇÏ´ÂÁö ¿©ºÎ
///
///
/// // ¶÷´Ù ½ÄÀ» »ç¿ëÇÏ¿© ¼Ó¼º¿¡ ´ëÇÑ À妽º »ý¼º
/// db.CreateIndex<Person>(p => p.Email, true);
///
///
public void CreateIndex(Expression> property, bool unique = false)
{
MemberExpression mx;
if (property.Body.NodeType == ExpressionType.Convert)
{
mx = ((UnaryExpression)property.Body).Operand as MemberExpression;
}
else
{
mx = (property.Body as MemberExpression);
}
var propertyInfo = mx.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
}
var propName = propertyInfo.Name;
var map = GetMapping();
var colName = map.FindColumnWithPropertyName(propName).Name;
CreateIndex(map.TableName, colName, unique);
}
///
/// µ¥ÀÌÅͺ£À̽º Å×ÀÌºí ¿¿¡ ´ëÇÑ Á¤º¸¸¦ ÀúÀåÇϴ Ŭ·¡½ºÀÔ´Ï´Ù.
///
public class ColumnInfo
{
// public int cid { get; set; }
///
/// ¿ÀÇ À̸§ÀÔ´Ï´Ù.
///
[Column("name")]
public string Name { get; set; }
// [Column ("type")]
// public string ColumnType { get; set; }
///
/// NULL °ª Çã¿ë ¿©ºÎ¸¦ ³ªÅ¸³À´Ï´Ù. 0À̸é NULL Çã¿ë, 1À̸é NOT NULLÀÔ´Ï´Ù.
///
public int notnull { get; set; }
// public string dflt_value { get; set; }
// public int pk { get; set; }
public override string ToString()
{
return Name;
}
}
///
/// ÁöÁ¤µÈ Å×À̺íÀÇ ¿ Á¤º¸¸¦ °¡Á®¿É´Ï´Ù.
///
/// Å×À̺íÀÇ À̸§
/// Å×À̺íÀÇ ¸ðµç ¿¿¡ ´ëÇÑ Á¤º¸ ¸ñ·Ï
///
///
/// // Person Å×À̺íÀÇ ¿ Á¤º¸ °¡Á®¿À±â
/// var columns = db.GetTableInfo("Person");
/// foreach (var column in columns) {
/// Console.WriteLine("¿ À̸§: " + column.Name);
/// }
///
///
public List GetTableInfo(string tableName)
{
var query = "pragma table_info(\"" + tableName + "\")";
return Query(query);
}
///
/// ±âÁ¸ Å×ÀÌºí ±¸Á¶¸¦ ÇöÀç ¸ÅÇÎµÈ °´Ã¼ ±¸Á¶¿Í ÀÏÄ¡Çϵµ·Ï ¾÷µ¥ÀÌÆ®ÇÕ´Ï´Ù.
/// »õ·Î¿î ¿ÀÌ ÀÖÀ¸¸é Å×ÀÌºí¿¡ Ãß°¡ÇÕ´Ï´Ù.
///
/// Å×ÀÌºí ¸ÅÇÎ Á¤º¸
void MigrateTable(TableMapping map)
{
var existingCols = GetTableInfo(map.TableName);
var toBeAdded = new List();
foreach (var p in map.Columns)
{
var found = false;
foreach (var c in existingCols)
{
found = (string.Compare(p.Name, c.Name, StringComparison.OrdinalIgnoreCase) == 0);
if (found)
break;
}
if (!found)
{
toBeAdded.Add(p);
}
}
foreach (var p in toBeAdded)
{
var addCol = "alter table \"" + map.TableName + "\" add column " + Orm.SqlDecl(p, StoreDateTimeAsTicks);
Execute(addCol);
}
}
///
/// »õ·Î¿î SQLiteCommand¸¦ »ý¼ºÇÕ´Ï´Ù. ¼ºê Ŭ·¡½º Á¦°øÀ» À§ÇØ ÀçÁ¤ÀÇÇÒ ¼ö ÀÖ½À´Ï´Ù.
///
///
protected virtual SQLiteCommand NewCommand()
{
return new SQLiteCommand(this);
}
///
/// Àμö°¡ ÀÖ´Â ¸í·É ÅØ½ºÆ®·Î »õ SQLiteCommand¸¦ »ý¼ºÇÕ´Ï´Ù.
/// ¸í·É ÅØ½ºÆ®¿¡¼ °¢ Àμö¿¡ ´ëÇØ '?' ¸¦ ¹èÄ¡ÇÕ´Ï´Ù.
///
///
/// ¿ÏÀüÈ÷ À̽ºÄÉÀÌÇÁµÈ SQL.
///
///
/// ¸í·É ÅØ½ºÆ®¿¡¼ '?'ÀÇ ÃâÇöÀ» ´ëüÇÏ´Â Àμö.
///
///
/// °´Ã¼
///
///
///
/// // ÆÄ¶ó¹ÌÅͰ¡ ÀÖ´Â ¸í·É »ý¼º
/// var cmd = db.CreateCommand("SELECT * FROM Person WHERE Id = ?", 1);
/// var person = cmd.ExecuteQuery<Person>().FirstOrDefault();
///
///
public SQLiteCommand CreateCommand(string cmdText, params object[] ps)
{
if (!_open)
throw SQLiteException.New(SQLite3.Result.Error, "Cannot create commands from unopened database");
var cmd = NewCommand();
cmd.CommandText = cmdText;
foreach (var o in ps)
{
cmd.Bind(o);
}
return cmd;
}
///
/// Àμö°¡ ÀÖ´Â ¸í·É ÅØ½ºÆ®(SQL)·Î SQLiteCommand¸¦ »ý¼ºÇÏ°í ½ÇÇàÇÕ´Ï´Ù.
/// ¸í·É ÅØ½ºÆ®¿¡¼ °¢ Àμö¿¡ ´ëÇØ '?'¸¦ ¹èÄ¡ÇÑ ´ÙÀ½ ÇØ´ç ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù.
/// ÇàÀÌ ¹ÝȯµÉ °ÍÀ¸·Î ¿¹»óÇÏÁö ¾ÊÀ» ¶§ Query ´ë½Å ÀÌ ¸Þ¼µå¸¦ »ç¿ëÇϼ¼¿ä.
/// ÀÌ·¯ÇÑ °æ¿ì¿¡´Â INSERT, UPDATE ¹× DELETE°¡ Æ÷ÇԵ˴ϴÙ.
/// ¿¬°áÀÇ Trace ¶Ç´Â TimeExecution ¼Ó¼ºÀ» ¼³Á¤ÇÏ¿© ½ÇÇàÀ» ÇÁ·ÎÆÄÀϸµÇÒ ¼ö ÀÖ½À´Ï´Ù.
///
///
/// ¿ÏÀüÈ÷ À̽ºÄÉÀÌÇÁµÈ SQL.
///
///
/// Äõ¸®¿¡¼ '?'ÀÇ ÃâÇöÀ» ´ëüÇÏ´Â Àμö.
///
///
/// ÀÌ ½ÇÇàÀÇ °á°ú·Î µ¥ÀÌÅͺ£À̽º¿¡¼ ¼öÁ¤µÈ Çà ¼ö.
///
///
///
/// // SQL Äõ¸® Á÷Á¢ ½ÇÇà
/// int rowsAffected = db.Execute("UPDATE Person SET Name = ? WHERE Id = ?", "È«±æµ¿", 1);
/// Console.WriteLine($"¾÷µ¥ÀÌÆ®µÈ Çà ¼ö: {rowsAffected}");
///
///
public int Execute(string query, params object[] args)
{
var cmd = CreateCommand(query, args);
if (TimeExecution)
{
if (_sw == null)
{
_sw = new Stopwatch();
}
_sw.Reset();
_sw.Start();
}
var r = cmd.ExecuteNonQuery();
if (TimeExecution)
{
_sw.Stop();
_elapsed += _sw.Elapsed;
this.InvokeTimeExecution(_sw.Elapsed, _elapsed);
}
return r;
}
///
/// SQL Äõ¸®¸¦ ½ÇÇàÇÏ°í ½ºÄ®¶ó °á°ú¸¦ ¹ÝȯÇÕ´Ï´Ù.
///
/// ¹ÝȯµÇ´Â ½ºÄ®¶ó °á°úÀÇ Å¸ÀÔ
/// ½ÇÇàÇÒ SQL Äõ¸®
/// Äõ¸® ÆÄ¶ó¹ÌÅÍ
/// Äõ¸® °á°úÀÇ Ã¹ ¹øÂ° ¿, ù ¹øÂ° Çà °ª
///
///
/// // ½ºÄ®¶ó °ª °¡Á®¿À±â
/// int count = db.ExecuteScalar<int>("SELECT COUNT(*) FROM Person");
/// string name = db.ExecuteScalar<string>("SELECT Name FROM Person WHERE Id = ?", 1);
///
///
public T ExecuteScalar(string query, params object[] args)
{
var cmd = CreateCommand(query, args);
if (TimeExecution)
{
if (_sw == null)
{
_sw = new Stopwatch();
}
_sw.Reset();
_sw.Start();
}
var r = cmd.ExecuteScalar();
if (TimeExecution)
{
_sw.Stop();
_elapsed += _sw.Elapsed;
this.InvokeTimeExecution(_sw.Elapsed, _elapsed);
}
return r;
}
///
/// Àμö°¡ ÀÖ´Â ¸í·É ÅØ½ºÆ®(SQL)·Î SQLiteCommand¸¦ »ý¼ºÇÏ°í ½ÇÇàÇÕ´Ï´Ù.
/// ¸í·É ÅØ½ºÆ®¿¡¼ °¢ Àμö¿¡ ´ëÇØ '?'¸¦ ¹èÄ¡ÇÑ ´ÙÀ½ ÇØ´ç ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù.
/// ÁöÁ¤µÈ ŸÀÔ¿¡ ´ëÇØ ÀÚµ¿À¸·Î »ý¼ºµÈ ¸ÅÇÎÀ» »ç¿ëÇÏ¿© °¢ °á°ú ÇàÀ» ¹ÝȯÇÕ´Ï´Ù.
///
///
/// ¿ÏÀüÈ÷ À̽ºÄÉÀÌÇÁµÈ SQL.
///
///
/// Äõ¸®¿¡¼ '?'ÀÇ ÃâÇöÀ» ´ëüÇÏ´Â Àμö.
///
///
/// Äõ¸®¿¡ ÀÇÇØ ¹ÝȯµÈ °¢ Çà¿¡ ´ëÇØ ÇϳªÀÇ °á°ú¸¦ °®´Â ¿°Å °¡´É.
///
///
///
/// // Á¶°Ç¿¡ ¸Â´Â ¸ðµç Person °´Ã¼ Á¶È¸
/// var adults = db.Query<Person>("SELECT * FROM Person WHERE Age >= ?", 18);
/// foreach (var person in adults) {
/// Console.WriteLine($"¼ºÀÎ: {person.Name}, {person.Age}¼¼");
/// }
///
///
public List Query(string query, params object[] args) where T : new()
{
var cmd = CreateCommand(query, args);
return cmd.ExecuteQuery();
}
///
/// Àμö°¡ ÀÖ´Â ¸í·É ÅØ½ºÆ®(SQL)·Î SQLiteCommand¸¦ »ý¼ºÇÏ°í ½ÇÇàÇÕ´Ï´Ù.
/// ¸í·É ÅØ½ºÆ®¿¡¼ °¢ Àμö¿¡ ´ëÇØ '?'¸¦ ¹èÄ¡ÇÑ ´ÙÀ½ ÇØ´ç ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù.
/// ÁöÁ¤µÈ ŸÀÔ¿¡ ´ëÇØ ÀÚµ¿À¸·Î »ý¼ºµÈ ¸ÅÇÎÀ» »ç¿ëÇÏ¿© °¢ °á°ú ÇàÀ» ¹ÝȯÇÕ´Ï´Ù.
///
///
/// ¿ÏÀüÈ÷ À̽ºÄÉÀÌÇÁµÈ SQL.
///
///
/// Äõ¸®¿¡¼ '?'ÀÇ ÃâÇöÀ» ´ëüÇÏ´Â Àμö.
///
///
/// Äõ¸®¿¡ ÀÇÇØ ¹ÝȯµÈ °¢ Çà¿¡ ´ëÇØ ÇϳªÀÇ °á°ú¸¦ °®´Â ¿°Å °¡´É.
/// ¿°ÅÀÚ´Â MoveNext¸¦ È£ÃâÇÒ ¶§¸¶´Ù sqlite3_stepÀ» È£ÃâÇϹǷÎ,
/// ¿°ÅÀÚÀÇ ¼ö¸í µ¿¾È µ¥ÀÌÅͺ£À̽º ¿¬°áÀÌ ¿·Á ÀÖ¾î¾ß ÇÕ´Ï´Ù.
///
///
///
/// // ´ë¿ë·® µ¥ÀÌÅ͸¦ Áö¿¬ ·ÎµùÀ¸·Î ó¸®
/// var query = db.DeferredQuery<Person>("SELECT * FROM Person");
/// using (var enumerator = query.GetEnumerator()) {
/// while (enumerator.MoveNext()) {
/// var person = enumerator.Current;
/// ProcessPerson(person);
/// }
/// }
///
///
public IEnumerable DeferredQuery(string query, params object[] args) where T : new()
{
var cmd = CreateCommand(query, args);
return cmd.ExecuteDeferredQuery();
}
///
/// Àμö°¡ ÀÖ´Â ¸í·É ÅØ½ºÆ®(SQL)·Î SQLiteCommand¸¦ »ý¼ºÇÏ°í ½ÇÇàÇÕ´Ï´Ù.
/// ¸í·É ÅØ½ºÆ®¿¡¼ °¢ Àμö¿¡ ´ëÇØ '?'¸¦ ¹èÄ¡ÇÑ ´ÙÀ½ ÇØ´ç ¸í·ÉÀ» ½ÇÇàÇÕ´Ï´Ù.
/// ÁöÁ¤µÈ ¸ÅÇÎÀ» »ç¿ëÇÏ¿© °¢ °á°ú ÇàÀ» ¹ÝȯÇÕ´Ï´Ù.
/// ÀÌ ÇÔ¼ö´Â ³»¼º(introspection)À» ÅëÇØ µ¥ÀÌÅͺ£À̽º¸¦ Äõ¸®Çϱâ À§ÇØ
/// ¶óÀ̺귯¸®¿¡¼¸¸ »ç¿ëµË´Ï´Ù. ÀϹÝÀûÀ¸·Î »ç¿ëµÇÁö ¾Ê½À´Ï´Ù.
///
///
/// °á°ú ÇàÀ» °´Ã¼·Î º¯È¯ÇÏ´Â µ¥ »ç¿ëÇÒ .
///
///
/// ¿ÏÀüÈ÷ À̽ºÄÉÀÌÇÁµÈ SQL.
///
///
/// Äõ¸®¿¡¼ '?'ÀÇ ÃâÇöÀ» ´ëüÇÏ´Â Àμö.
///
///
/// Äõ¸®¿¡ ÀÇÇØ ¹ÝȯµÈ °¢ Çà¿¡ ´ëÇØ ÇϳªÀÇ °á°ú¸¦ °®´Â ¿°Å °¡´É.
///
///
///
/// // ¸ÅÇÎ °´Ã¼¸¦ »ç¿ëÇØ Äõ¸® ½ÇÇà
/// var map = db.GetMapping(typeof(Person));
/// var results = db.Query(map, "SELECT * FROM Person WHERE Id = ?", 1);
/// if (results.Count > 0) {
/// var person = results[0] as Person;
/// }
///
///
public List