/// <summary> /// コネクションオープン /// </summary> /// <returns>コネクション</returns> public IntPtr Open() { // すでに開いている場合、使いまわす if (IsOpen()) { return((IntPtr)connection); } // 新規オープン IntPtr con; if (SQLiteApi.sqlite3_open(path, out con) != SQLiteApi.SQLITE_OK) //if (SQLiteApi.sqlite3_open_v2(path, out con, 0x00000002 | 0x00020000, null) != SQLiteApi.SQLITE_OK) { throw new SQLiteException("Could not open database file: " + path); } // タイムアウト設定 if (SQLiteApi.sqlite3_busy_timeout(con, TIMEOUT) != SQLiteApi.SQLITE_OK) { throw new SQLiteException("Could not Set timeout: " + path); } connection = con; return((IntPtr)connection); }
/// <summary> /// バリュー取得 /// </summary> /// <param name="stmt">ステートメント</param> /// <param name="clmIndex">カラムインデックス</param> /// <returns>バリュー</returns> private static object GetValue(IntPtr stmt, int clmIndex) { // タイプごとに指定されたカラムのデータを抜き出す switch (SQLiteApi.sqlite3_column_type(stmt, clmIndex)) { case SQLiteApi.SQLITE_INTEGER: return(SQLiteApi.sqlite3_column_int64(stmt, clmIndex)); case SQLiteApi.SQLITE_TEXT: IntPtr text = SQLiteApi.sqlite3_column_text(stmt, clmIndex); return(Marshal.PtrToStringAnsi(text)); case SQLiteApi.SQLITE_FLOAT: return(SQLiteApi.sqlite3_column_double(stmt, clmIndex)); case SQLiteApi.SQLITE_BLOB: IntPtr blob = SQLiteApi.sqlite3_column_blob(stmt, clmIndex); int size = SQLiteApi.sqlite3_column_bytes(stmt, clmIndex); byte[] data = new byte[size]; Marshal.Copy(blob, data, 0, size); return(data); } return(null); }
/// <summary> /// ステップ実行 /// </summary> /// <param name="query">クエリ</param> /// <param name="bindList">バインドリスト</param> /// <param name="fetchPostAction">フェッチ後処理</param> /// <returns>行データ</returns> private IEnumerable <Dictionary <string, object> > ExecuteStep(string query, Dictionary <string, object> bindList = null, Action <IntPtr, Dictionary <string, object> > fetchPostAction = null) { // ポストアクション未指定なら、空アクションを設定 if (fetchPostAction == null) { fetchPostAction = (ptr, bind) => { }; } // コネクションオープン IntPtr con = System.IntPtr.Zero; try { con = Open(); // ステートメントオープン IntPtr stmt = OpenStmt(con, query); // パラメーターバインド BindParam(stmt, bindList); try { // カラムインデックス作成 int columnCount = SQLiteApi.sqlite3_column_count(stmt); Dictionary <int, string> clmIndex = new Dictionary <int, string>(); for (int i = 0; i < columnCount; i++) { clmIndex.Add(i, Marshal.PtrToStringAnsi(SQLiteApi.sqlite3_column_name(stmt, i))); } // 1行ずつデータを取得 Dictionary <string, object> dataRow = new Dictionary <string, object>(); while (SQLiteApi.sqlite3_step(stmt) == SQLiteApi.SQLITE_ROW) { // すべてのカラムのデータを取得し、カラム名をキーにした連想配列に設定 for (int i = 0; i < columnCount; i++) { dataRow[clmIndex[i]] = GetValue(stmt, i); } // データ返却 yield return(dataRow); // ポストアクション fetchPostAction(stmt, bindList); } } finally { CloseStmt(stmt); } } finally { Close(); } }
/// <summary> /// クローズステートメント /// </summary> /// <param name="stmt">ステートメント</param> private static void CloseStmt(IntPtr?stmt) { // 無効なステートメントは何もしない if (stmt == null) { return; } // ステートメントクローズのエラーは無視 SQLiteApi.sqlite3_finalize((IntPtr)stmt); }
/// <summary> /// クエリ逐次実行 /// </summary> /// <param name="con">コネクション</param> /// <param name="query">クエリ</param> /// <param name="isSkipExp">エラースキップフラグ</param> public static void Exec(IntPtr con, string query, bool isSkipExp = false) { IntPtr stmt; if (SQLiteApi.sqlite3_exec(con, query, IntPtr.Zero, IntPtr.Zero, out stmt) != SQLiteApi.SQLITE_OK) { if (!isSkipExp) { throw new SQLiteException("Could not exec SQL statement.", con); } } }
/// <summary> /// コンストラクタ /// </summary> /// <param name="message">メッセージ</param> /// <param name="db">DBコネクション</param> public SQLiteException(string message, System.IntPtr?db = null) : base(message) { // コネクション未設定なら何もしない if (db == null) { return; } // コネクションが有効なら付加情報を追加する System.IntPtr dbCon = (System.IntPtr)db; addMessage = string.Format("# errcode = {0} errmsg = {1}", SQLiteApi.sqlite3_errcode(dbCon), System.Runtime.InteropServices.Marshal.PtrToStringAnsi(SQLiteApi.sqlite3_errmsg(dbCon))); }
/// <summary> /// オープンステートメント /// </summary> /// <param name="con">DBコネクション</param> /// <param name="query">クエリ</param> /// <returns>ステートメント</returns> private static IntPtr OpenStmt(IntPtr con, string query) { IntPtr stmtHandle; SQLLog(query); if (SQLiteApi.sqlite3_prepare_v2(con, query, query.Length, out stmtHandle, IntPtr.Zero) != SQLiteApi.SQLITE_OK) { throw new SQLiteException("Prepare Error " + query, con); } return(stmtHandle); }
/// <summary> /// リセットステートメント /// </summary> /// <param name="stmt">ステートメント</param> private static void ResetStmt(IntPtr?stmt) { // 無効なステートメントは何もしない if (stmt == null) { return; } // ステートメントリセット if (SQLiteApi.sqlite3_reset((IntPtr)stmt) != SQLiteApi.SQLITE_OK) { throw new SQLiteException("Stmt Reset Error"); } }
/// <summary> /// クローズ /// </summary> public void Close() { // すでに閉じている場合何もしない if (!IsOpen()) { return; } IntPtr con = (IntPtr)connection; connection = null; // クローズエラーは何もしない SQLiteApi.sqlite3_close(con); }
/// <summary> /// クエリ遅延実行 /// </summary> /// <param name="con">コネクション</param> /// <param name="query">クエリ</param> /// <param name="bindList">バインドリスト</param> /// <param name="isSkipExp">エラースキップフラグ</param> public static void Execute(IntPtr con, string query, Dictionary <string, object> bindList = null, bool isSkipExp = false) { // ステートメントオープン IntPtr stmt = OpenStmt(con, query); // バインド BindParam(stmt, bindList); try { // 実行 if (SQLiteApi.sqlite3_step(stmt) != SQLiteApi.SQLITE_DONE) { if (!isSkipExp) { throw new SQLiteException("Could not execute SQL statement." + query, con); } } } finally { CloseStmt(stmt); } }
/// <summary> /// パラメーターバインド /// </summary> /// <param name="stmHandle">ステートメント</param> /// <param name="bindList">バインドリスト</param> private static void BindParam(IntPtr stmHandle, Dictionary <string, object> bindList) { int paramNo = 0; List <string> bindLog = new List <string>(); // リセット ResetStmt(stmHandle); // バインド対象がない場合何もしない if (bindList == null) { return; } // バインド対象を全件ループ foreach (KeyValuePair <string, object> bindData in bindList) { // パラメーターNoを算出 paramNo = SQLiteApi.sqlite3_bind_parameter_index(stmHandle, bindData.Key); if (bindData.Value != null) { bindLog.Add(bindData.Key + " value= " + bindData.Value.ToString()); } // string if (bindData.Value is string) { string strValue = bindData.Value.ToString(); ExecBind(() => SQLiteApi.sqlite3_bind_text16(stmHandle, paramNo, strValue, System.Text.Encoding.Unicode.GetByteCount(strValue), disablePtr)); continue; } // int if (bindData.Value is int) { ExecBind(() => SQLiteApi.sqlite3_bind_int(stmHandle, paramNo, ((int)bindData.Value))); continue; } // long if (bindData.Value is long) { ExecBind(() => SQLiteApi.sqlite3_bind_int64(stmHandle, paramNo, ((long)bindData.Value))); continue; } // double if (bindData.Value is double) { ExecBind(() => SQLiteApi.sqlite3_bind_double(stmHandle, paramNo, ((double)bindData.Value))); continue; } // blob if (bindData.Value is byte[]) { byte[] byteValue = (byte[])bindData.Value; ExecBind(() => SQLiteApi.sqlite3_bind_blob(stmHandle, paramNo, byteValue, byteValue.Length, disablePtr)); continue; } } SQLLog("BIND : " + string.Join(" # ", CollectionUtil.Collection2Array <string>(bindLog))); }