CodeIgniterの学習 26 - sqlite3 (PDO経由) を CodeIgniterで半ば強引に使ってみる(実験)
今日は CodeIgniterで、PDOを使ってsqlite3を使ってみることにした。
他のかたが挑戦しているのも前に見かけた気がしたけど、取りあえず俺の作業ログも書いておく。
(2009/11/19追記)
CodeIgniterのフォーラムで、SQLite3 + CI 1.7.2の別の実装を見つけた。
スレッド: http://codeigniter.com/forums/viewthread/134706/
このスレッド内に書かれてるけど、
http://blog.trevorbramble.com/past/2009/9/20/codeigniter_sqlite3/
で投稿主さんのソースがダウンロード出来る。
俺はちょっと眺めただけだけど、こちらの投稿の方も参考にするといいかも。
(2009/11/19追記終わり)
目的
メインのデータベースとして使う気はさらさら無いのだが、
- デバグ用ログをsqlite3のファイルDBで保存したりとか、
- csv形式のデータエクスポートみたいに、sqlite形式でのデータエクスポートをしたりとか、(で他のバッチとかプログラムに噛ませたりとか)、
- 認証済みユーザー毎に専用のテンポラリDB(仮想DB)として使ったりとか、
- 別プログラムのsqlite3形式のDBをアップロードしてデータを読み込んで何か処理させたりとか
そういった付随用途で使うと面白いかもと思ったので、取りあえず使えるようにしてみる事にした。
元ネタを魔改造してみる
元ネタは、http://codeigniter.com/wiki/PDO_SQLite3/ です。
この元ネタは、system/database/drivers/sqlite/sqlite_driver.phpとかをベースにPDO化したソースなのだけれど、
ちょっとwiki上の記述が散漫になっているのと、
貼られた時期のソースと、現在の最新版のsqlite_driver.phpのソースとの構成に差違が結構あったので、
例によって整理+一部俺俺改造してみた。
なお、いつもの事ながら無保証です。
余興程度に思ってください。(そもそもあまりPDOもsqlite3もサワリ位しか知らないし。)
メインのDBで使ったり、複雑な使い方をするのは、全然オススメ出来ません。
(インスタンスをガバっとシリアライズしようとしても、PDOは「cannot serialize or unserialize PDO instances」とかエラーが出てシリアライズ出来ないし。クエリ結果のfield_dataがとれないので強引にエラーにならないようにしているし。)
まあ俺の目的程度での使い道ならあるかも。
使い方、設置方法
基本は、元ネタ http://codeigniter.com/wiki/PDO_SQLite3/ を参照のこと。1:新規作成ファイル
を作る。(作成先はapplication以下ではない、pdoディレクトリは新設。)
改造ソースの中身は下に貼っておく。
(元ネタ+整理+version1.6.3の sqlite_driver.php sqlite_result.php とマージ + 微妙に改造です。中身の解説は面倒なのでdiffでも取ってソースを見てね。)
2:新規作成ディレクトリ
DBの保存先用に、./application/data/sqlite3/ というディレクトリを作った。
この中に temp.db とか md5("ユーザーid+SALT").db とか作って保存するつもり。
ウチのディレクトリ構成は、http://d.hatena.ne.jp/dix3/20080919/1221815250 みたいにしているんで、
http経由で直接覗かれることはないけど、そうじゃない場合は.htaccess等で
RewriteEngine On RewriteBase / RewriteRule \.db$ - [F] #RewriteRule \.db$ - [R=404] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond $1 !^(index\.php|images|img|css|js|xajax_js|tmp|robots\.txt|.+\.gif$|.+\.jpg$|.+\.png$|.+\.js$|.+\.css$) RewriteRule ^(.*)$ /index.php/$1 [L]
とでもして、拡張子で禁止しておけばいいと思う。
3:DBとテーブルを準備する
本来の目的は上記のような事なのだが、
動作確認用にとりあえずデフォルトDBとして使ってみることにした。
ちょうどdb_session用のテーブルと、タスクリストの適当テーブルが有るので、
これを作ってみる。
シェル上で
cd ./application/data/sqlite3/
sqlite3 temp.db
と起動して、
CREATE TABLE IF NOT EXISTS `ci_sessions` ( session_id TEXT DEFAULT 0 NOT NULL PRIMARY KEY , ip_address TEXT DEFAULT 0 NOT NULL, user_agent TEXT NOT NULL, last_activity INTEGER DEFAULT 0 NOT NULL, session_data text default '' NOT NULL ); CREATE TABLE IF NOT EXISTS tasklist ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, user_name VARCHAR(128) NULL, title VARCHAR(255) NULL, note TEXT NULL, target_date DATETIME NULL, limit_date DATETIME NULL, del_flg INTEGER NOT NULL DEFAULT 0, created DATETIME NULL , modified DATETIME NULL );
を貼り付けてテーブルを作ってみる。
sqliteで準備されている型以外は勝手にTEXT型になってしまうが、気にしない。
作られたテーブルの中身はこんな感じ
sqlite> pragma table_info(ci_sessions); 0|session_id|TEXT|99|0|1 1|ip_address|TEXT|99|0|0 2|user_agent|TEXT|99||0 3|last_activity|INTEGER|99|0|0 4|session_data|text|99|''|0 sqlite> pragma table_info(tasklist); 0|id|INTEGER|99||1 1|user_name|VARCHAR(128)|0||0 2|title|VARCHAR(255)|0||0 3|note|TEXT|0||0 4|target_date|DATETIME|0||0 5|limit_date|DATETIME|0||0 6|del_flg|INTEGER|99|0|0 7|created|DATETIME|0||0 8|modified|DATETIME|0||0 sqlite>.quit
最後にパーミッションを変えておく
chown apache:apache temp.db
4)application/config/database.phpを変更し、デフォルトDBを切り替えておく
application/config/database.php に以下を変更、追記
<?php //上略 //$active_group = "default" $active_group = "temp";//defaultをtempに変更 $active_record = TRUE; //中略 $db['default']['dbcollat'] = "utf8_general_ci"; //tempという名前で呼べるようにした。 $db['temp']['hostname'] = ""; $db['temp']['username'] = ""; $db['temp']['password'] = ""; $db['temp']['database'] = "sqlite:" .APPPATH ."data/sqlite3/temp.db"; $db['temp']['dbdriver'] = "pdo"; $db['temp']['dbprefix'] = ""; $db['temp']['pconnect'] = FALSE; $db['temp']['db_debug'] = TRUE; $db['temp']['cache_on'] = FALSE; $db['temp']['cachedir'] = ""; $db['temp']['char_set'] = "utf8"; $db['temp']['dbcollat'] = "utf8_general_ci"; //下略 ?>
ちなみにデフォルトDBを変えなくても、ソース内(コントローラとか)で
<?php $this->db2hoge = $this->load->database('temp', TRUE); $query = $this->db2hoge -> get( 'tasklist' ); var_dump($query->result()); exit; ?>
みたいに $a = $this->load->database('temp', TRUE);
ってやるとどこでも別DBを呼べる。
var_dump($query->result());
array
0 =>
object(stdClass)[27]
public 'id' => string '1' (length=1)public 'user_name' => string '' (length=0)
public 'title' => string 'sqlite3を強引に使えるようにしてみた' (length=49)public 'note' => string '何となく動くみたいだね。' (length=36)
public 'target_date' => string '' (length=0)public 'limit_date' => string 'でも型はゆるゆる' (length=24)
public 'del_flg' => string '0' (length=1)public 'created' => string '' (length=0)
public 'modified' => string '' (length=0)1 =>
object(stdClass)[28]
public 'id' => string '2' (length=1)public 'user_name' => string '' (length=0)
public 'title' => string 'ああああああ' (length=18)public 'note' => string 'たのしいな' (length=15)
public 'target_date' => string 'ふがふが' (length=12)public 'limit_date' => string '' (length=0)
public 'del_flg' => string '0' (length=1)public 'created' => string '' (length=0)
public 'modified' => string '' (length=0)
ソース
sqlite3 PDO対応改変ソース2つはこんな感じ、長いけど貼っておく。
1)./system/database/drivers/pdo/pdo_driver.php
Wiki( http://codeigniter.com/wiki/PDO_SQLite3/ )上の情報を元にソースを集約し、
上記を元にCodeigniter 1.6.3の sqlite_driver.phpの書き方、並びに寄せるようにした。
ついでにsqlite_driver内のみに存在していたメソッド(trans_begin trans_rollback trans_commitとか)を追加。
他にlist_fieldsを取得出来るようにとかしている。
メソッドの出現順もsqlite_driver.phpと見比べられるように合わせている。
(09/08/14暫定追記)
pdo_driver.php内のロールバック部分については、コメント欄のmemoletさんの修正内容を参考にしてください。sqliteってトランザクション掛けた方が確か速いんだったっけ?
(暫定追記終わり)
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * Code Igniter * * An open source application development framework for PHP 4.3.2 or newer * * @package CodeIgniter * @author Rick Ellis * @copyright Copyright (c) 2006, pMachine, Inc. * @license http://www.codeignitor.com/user_guide/license.html * @link http://www.codeigniter.com * @since Version 1.0 * @filesource */ // ------------------------------------------------------------------------ /** * PDO Database Adapter Class * * Note: _DB is an extender class that the app controller * creates dynamically based on whether the active record * class is being used or not. * * @package CodeIgniter * @subpackage Drivers * @category Database * @author Dready * @link http://dready.jexiste.fr/dotclear/ */ /** * modified : dix3 at 08/10/17 * sqlite3を使えるようにする実験俺俺改造 なんとなく動くけど詳細未テスト * Wiki( http://codeigniter.com/wiki/PDO_SQLite3/ )上の情報を元にソースを集約し、 * 上記を元にCodeigniter 1.6.3の sqlite_driver.phpの書き方、並びに寄せるようにした。 * ついでにsqlite_driver内のみに存在していたメソッド(trans_begin trans_rollback trans_commitとか)を追加。 * 他にlist_fieldsを取得出来るようにとかしている。 * @link http://d.hatena.ne.jp/dix3/20081019/1224405470 */ class CI_DB_pdo_driver extends CI_DB { var $class_version = '0.1'; /** * The syntax to count rows is slightly different across different * database engines, so this string appears in each driver and is * used for the count_all() and count_all_results() functions. */ var $_count_string = "SELECT COUNT(*) AS "; var $_random_keyword = ' Random()'; // database specific random keyword /** * Non-persistent database connection * * @access private called by the base class * @return resource */ function db_connect() { $conn_id = FALSE; try { $conn_id = new PDO ( $this -> database, $this -> username, $this -> password ); log_message( 'debug', 'connecting ' . $this -> database ); } catch ( PDOException $e ) { log_message( 'debug', 'merde' ); log_message( 'error', $e -> getMessage() ); if ( $this -> db_debug ) { $this -> display_error( $e -> getMessage(), '', TRUE ); } } log_message( 'debug', print_r( $conn_id, TRUE ) ); if ( $conn_id ) { log_message( 'debug', 'connection ok' ); } return $conn_id; } // -------------------------------------------------------------------- /** * Persistent database connection * * @access private called by the base class * @return resource */ function db_pconnect() { try { $conn_id = new PDO ( $this -> database, $this -> username, $this -> password, array( PDO :: ATTR_PERSISTENT => TRUE ) ); } catch ( PDOException $e ) { log_message( 'error', $e -> getMessage() ); if ( $this -> db_debug ) { $this -> display_error( $e -> getMessage(), '', TRUE ); } return FALSE; } return $conn_id; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Select the database * * @access private called by the base class * @return resource */ function db_select() { return TRUE; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Set client character set * * @access public * @param string $ * @param string $ * @return resource */ function db_set_charset( $charset, $collation ) { // TODO - add support if needed return TRUE; } // -------------------------------------------------------------------- /** * Version number query string * * @access public * @return string */ function _version() { return $this -> conn_id -> getAttribute( constant( "PDO::ATTR_SERVER_VERSION" ) ); } // -------------------------------------------------------------------- /** * Execute the query * * @access private called by the base class * @param string $ an SQL query * @return resource */ function _execute( $sql ) { $sql = $this -> _prep_query( $sql ); log_message( 'debug', 'SQL : ' . $sql ); return @$this -> conn_id -> query( $sql ); // Do we really need to use error supression here? :( } // -------------------------------------------------------------------- /** * Prep the query * * If needed, each database adapter can prep the query string * * @access private called by execute() * @param string $ an SQL query * @return string */ function _prep_query( $sql ) { return $sql; } // -------------------------------------------------------------------- /** * Begin Transaction * * @access public * @return bool */ function trans_begin( $test_mode = FALSE ) { if ( ! $this -> trans_enabled ) { return TRUE; } // When transactions are nested we only begin/commit/rollback the outermost ones if ( $this -> _trans_depth > 0 ) { return TRUE; } // Reset the transaction failure flag. // If the $test_mode flag is set to TRUE transactions will be rolled back // even if the queries produce a successful result. $this -> _trans_failure = ( $test_mode === TRUE ) ? TRUE : FALSE; if($this -> conn_id){ $this -> conn_id -> beginTransaction(); } return TRUE; } // -------------------------------------------------------------------- /** * Commit Transaction * * @access public * @return bool */ function trans_commit() { if ( ! $this -> trans_enabled ) { return TRUE; } // When transactions are nested we only begin/commit/rollback the outermost ones if ( $this -> _trans_depth > 0 ) { return TRUE; } if($this -> conn_id){ $this -> conn_id -> commit(); } return TRUE; } // -------------------------------------------------------------------- /** * Rollback Transaction * * @access public * @return bool */ function trans_rollback() { if ( ! $this -> trans_enabled ) { return TRUE; } // When transactions are nested we only begin/commit/rollback the outermost ones if ( $this -> _trans_depth > 0 ) { return TRUE; } if($this -> conn_id){ $this -> conn_id -> rollback(); } return TRUE; } // -------------------------------------------------------------------- /** * Escape String * * @access public * @param string $ * @return string */ function escape_str( $str ) { if ( get_magic_quotes_gpc() ) { $str = stripslashes( $str ); } return $this -> conn_id -> quote( $str ); } // -------------------------------------------------------------------- /** * Affected Rows * * @access public * @return integer */ function affected_rows() { // todo:なんか返す return 0; } // -------------------------------------------------------------------- /** * Insert ID * * @access public * @return integer */ function insert_id() { return @$this -> conn_id -> lastInsertId(); } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * "Count All" query * * Generates a platform-specific query string that counts all records in * the specified database * * @access public * @param string $ * @return string */ function count_all( $table = '' ) { if ( $table == '' ) return '0'; $query = $this -> query( $this -> _count_string . $this -> _protect_identifiers( 'numrows' ) . " FROM " . $this -> _protect_identifiers( $this -> dbprefix . $table ) ); if ( $query -> num_rows() == 0 ) return '0'; $row = $query -> row(); return $row -> numrows; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * List table query * * Generates a platform-specific query string so that the table names can be fetched * * @access private * @param boolean $ * @return string */ function _list_tables( $prefix_limit = FALSE ) { $sql = "SELECT name from sqlite_master WHERE type='table'"; if ( $prefix_limit !== FALSE AND $this -> dbprefix != '' ) { $sql .= " AND 'name' LIKE '" . $this -> dbprefix . "%'"; } return $sql; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Show column query * * Generates a platform-specific query string so that the column names can be fetched * * @access public * @param string $ the table name * @return string */ function _list_columns( $table = '' ) { // Not supported return FALSE; } // -------------------------------------------------------------------- /** * Field data query * * Generates a platform-specific query so that the column data can be retrieved * * @access public * @param string $ the table name * @return object */ function _field_data( $table ) { return 'PRAGMA table_info(\'' . $this->_escape_table($table) . '\')'; } // -------------------------------------------------------------------- /** * The error message string * * @access private * @return string */ function _error_message() { $infos = $this -> conn_id -> errorInfo(); return $infos[2]; } // -------------------------------------------------------------------- /** * The error message number * * @access private * @return integer */ function _error_number() { $infos = $this -> conn_id -> errorInfo(); return $infos[1]; } // -------------------------------------------------------------------- /** * Escape Table Name * * This function adds backticks if the table name has a period * in it. Some DBs will get cranky unless periods are escaped * * @access private * @param string $ the table name * @return string */ function _escape_table( $table ) { if ( stristr( $table, '.' ) ) { $table = preg_replace( "/\./", '`.`', $table ); } return $table; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Protect Identifiers * * This function adds backticks if appropriate based on db type * * @access private * @param mixed $ the item to escape * @param boolean $ only affect the first word * @return mixed the item with backticks */ function _protect_identifiers( $item, $first_word_only = FALSE ) { if ( is_array( $item ) ) { $escaped_array = array(); foreach( $item as $k => $v ) { $escaped_array[$this -> _protect_identifiers( $k )] = $this -> _protect_identifiers( $v, $first_word_only ); } return $escaped_array; } // This function may get "item1 item2" as a string, and so // we may need "item1 item2" and not "item1 item2" if ( ctype_alnum( $item ) === FALSE ) { if ( strpos( $item, '.' ) !== FALSE ) { $aliased_tables = implode( ".", $this -> ar_aliased_tables ) . '.'; $table_name = substr( $item, 0, strpos( $item, '.' ) + 1 ); $item = ( strpos( $aliased_tables, $table_name ) !== FALSE ) ? $item = $item : $this -> dbprefix . $item; } // This function may get "field >= 1", and need it to return "field >= 1" $lbound = ( $first_word_only === TRUE ) ? '' : '|\s|\('; //$item = preg_replace( '/(^' . $lbound . ')([\w\d\-\_]+?)(\s|\)|$)/iS', '$1$2$3', $item ); $item = preg_replace( '/(^' . $lbound . ')([\w\d\-\_]+?)(\s|\)|$)/iuS', '$1$2$3', $item ); }else { return "{$item}"; } $exceptions = array( 'AS', '/', '-', '%', '+', '*', 'OR', 'IS' ); foreach ( $exceptions as $exception ) { if ( stristr( $item, " {$exception} " ) !== FALSE ) { // $item = preg_replace( '/ (' . preg_quote( $exception ) . ') /i', ' $1 ', $item ); $item = preg_replace( '/ (' . preg_quote( $exception ) . ') /iu', ' $1 ', $item ); } } return $item; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * From Tables * * This function implicitly groups FROM tables so there is no confusion * about operator precedence in harmony with SQL standards * * @access public * @param type $ * @return type */ function _from_tables( $tables ) { if ( ! is_array( $tables ) ) { $tables = array( $tables ); } return '(' . implode( ', ', $tables ) . ')'; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Insert statement * * Generates a platform-specific insert string from the supplied data * * @access public * @param string $ the table name * @param array $ the insert keys * @param array $ the insert values * @return string */ function _insert( $table, $keys, $values ) { return "INSERT INTO " . $this -> _escape_table( $table ) . " (" . implode( ', ', $keys ) . ") VALUES (" . implode( ', ', $values ) . ")"; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Update statement * * Generates a platform-specific update string from the supplied data * * @access public * @param string $ the table name * @param array $ the update data * @param array $ the where clause * @param array $ the orderby clause * @param array $ the limit clause * @return string */ function _update( $table, $values, $where, $orderby = array(), $limit = FALSE ) { foreach( $values as $key => $val ) { $valstr[] = $key . " = " . $val; } $limit = ( ! $limit ) ? '' : ' LIMIT ' . $limit; $orderby = ( count( $orderby ) >= 1 )?' ORDER BY ' . implode( ", ", $orderby ):''; $sql = "UPDATE " . $this -> _escape_table( $table ) . " SET " . implode( ', ', $valstr ); $sql .= ( $where != '' AND count( $where ) >= 1 ) ? " WHERE " . implode( " ", $where ) : ''; $sql .= $orderby . $limit; return $sql; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Truncate statement * * Generates a platform-specific truncate string from the supplied data * If the database does not support the truncate() command * This function maps to "DELETE FROM table" * * @access public * @param string $ the table name * @return string */ function _truncate( $table ) { return $this -> _delete( $table ); } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Delete statement * * Generates a platform-specific delete string from the supplied data * * @access public * @param string $ the table name * @param array $ the where clause * @param string $ the limit clause * @return string */ function _delete( $table, $where = array(), $like = array(), $limit = FALSE ) { $conditions = ''; if ( count( $where ) > 0 OR count( $like ) > 0 ) { $conditions = "\nWHERE "; $conditions .= implode( "\n", $this -> ar_where ); if ( count( $where ) > 0 && count( $like ) > 0 ) { $conditions .= " AND "; } $conditions .= implode( "\n", $like ); } $limit = ( ! $limit ) ? '' : ' LIMIT ' . $limit; return "DELETE FROM " . $table . $conditions . $limit; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Limit string * * Generates a platform-specific LIMIT clause * * @access public * @param string $ the sql query string * @param integer $ the number of rows to limit the query to * @param integer $ the offset value * @return string */ function _limit( $sql, $limit, $offset ) { if ( $offset == 0 ) { $offset = ''; }else { $offset .= ", "; } return $sql . "LIMIT " . $offset . $limit; } // -------------------------------------------------------------------- /** * Close DB Connection * * @access public * @param resource $ * @return void */ function _close( $conn_id ) { // Do nothing since PDO don't have close } // -------------------------------------------------------------------- /** * COPY FROM sqlite_driver.php * Rename a table * * Generates a platform-specific query so that a table can be renamed * * @access private * @param string $ the old table name * @param string $ the new table name * @return string */ function _rename_table( $table_name, $new_table_name ) { $sql = 'ALTER TABLE ' . $this -> db -> _protect_identifiers( $table_name ) . " RENAME TO " . $this -> db -> _protect_identifiers( $new_table_name ); return $sql; } // -------------------------------------------------------------------- /** * "Smart" Escape String * * Escapes data based on type * Sets boolean and null types * * @access public * @param string $ * @return integer */ function escape( $str ) { switch ( gettype( $str ) ) { case 'string': $str = $this -> escape_str( $str ); break; case 'boolean': $str = ( $str === FALSE ) ? 0 : 1; break; default: $str = ( $str === null ) ? 'NULL' : $str; break; } return $str; } // -------------------------------------------------------------------- /** * Show table query * * Generates a platform-specific query string so that the table names can be fetched * * @access private * @return string */ function _show_tables() { return "SELECT name from sqlite_master WHERE type='table'"; } // -------------------------------------------------------------------- /** * Show columnn query * * Generates a platform-specific query string so that the column names can be fetched * * @access private * @param string $ the table name * @return string */ function _show_columns( $table = '' ) { // Not supported return FALSE; } // -------------------------------------------------------------------- /** * Close DB Connection * * @access public * @param resource $ * @return void */ function destroy( $conn_id ) { $conn_id = null; } //list_fieldsをクエリを投げて取得 function list_fields($table) { $result_id = $this->_execute($this->_field_data($table)); $field_names = array(); foreach($result_id -> fetchAll( PDO :: FETCH_ASSOC ) as $v){ $field_names[] = $v['name']; } return $field_names; } } //endofclass /** * End of file pdo_driver.php */ /** * Location: ./system/database/drivers/pdo/pdo_driver.php */ ?>
2)./system/database/drivers/pdo/pdo_result.php
こちらの変更点も1)のpdo_driver.phpと同様。
あと、
テーブルの field_data ( $db->field_data('sometablename'); ) はとれるが、
クエリ結果の field_data ( $query->field_data(); ) はとれないので強引に決めうちで作るようにした。
これでとりあえずscaffoldingの編集画面は落ちなくなる。
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); /** * PDO Result Class * * This class extends the parent result class: CI_DB_result * * @category Database * @author Dready * @link http://dready.jexiste.fr/dotclear/ */ /** * modified : dix3 at 08/10/17 * sqlite3を使えるようにする実験俺俺改造 なんとなく動くけど詳細未テスト * Wiki( http://codeigniter.com/wiki/PDO_SQLite3/ )上の情報を元にソースを集約し、 * 上記を元にCodeigniter 1.6.3の sqlite_result.php の書き方、並びに寄せるようにした。 * 他にlist_fieldsを取得出来るようにとかしている。 * * テーブルの field_data ( $db->field_data('sometablename'); ) はとれるが、 * クエリ結果の field_data ( $query->field_data(); ) はとれないので強引に決めうちで作るようにした。 * だからこの結果をそのまま使うのはよろしくないが、とりあえずscaffoldingの編集画面は落ちなくなる。 * @link http://d.hatena.ne.jp/dix3/20081019/1224405470 */ class CI_DB_pdo_result extends CI_DB_result { var $pdo_results = ''; var $pdo_index = 0; /** * Number of rows in the result set * * pfff... that's ugly !!!!!!! * * PHP manual for PDO tell us about nom_rows : * "For most databases, PDOStatement::rowCount() does not return the number of rows affected by * a SELECT statement. Instead, use PDO::query() to issue a SELECT COUNT(*) statement with the * same predicates as your intended SELECT statement, then use PDOStatement::fetchColumn() to * retrieve the number of rows that will be returned. * * which means * 1/ select count(*) as c from table where $where * => numrows * 2/ select * from table where $where * => treatment * * Holy cow ! * * @access public * @return integer */ function num_rows() { if ( !$this -> pdo_results ) { $this -> pdo_results = $this -> result_id -> fetchAll( PDO :: FETCH_ASSOC ); } return sizeof( $this -> pdo_results ); } // -------------------------------------------------------------------- /** * Number of fields in the result set * * @access public * @return integer */ function num_fields() { if ( is_array( $this -> pdo_results ) ) { return sizeof( $this -> pdo_results[$this -> pdo_index] ); }else { return $this -> result_id -> columnCount(); } } // -------------------------------------------------------------------- /** * Fetch Field Names * * Generates an array of column names * * @access public * @return array */ function list_fields() { $field_names = array(); if(isset($this -> pdo_results[0])){ $table_info = $this -> pdo_results[0]; $field_names = array_keys($table_info); } return $field_names; } //COPY FROM sqlite_result.php // Deprecated function field_names() { return $this->list_fields(); } // -------------------------------------------------------------------- /** * Field data * * Generates an array of objects containing field meta-data * * @access public * @return array */ function field_data() { //テーブルのfield_dataはとれるが、 //クエリ結果のfield_dataはとれないので強引に決めうちで作るようにした //だからこの結果をそのまま使うのはよろしくないが、とりあえずscaffoldingの編集画面は落ちなくなる //とれない情報はダミーを突っ込んでいる $retval = array(); $table_info = $this -> pdo_results; if(isset($table_info[0]['name'])){ //テーブルのfield_dataはとれる for ( $i = 0; $i < count( $this -> pdo_results ); $i++ ) { $F = new stdClass(); $F->name = $table_info[$i]['name'] ; $F->type = strtolower($table_info[$i]['type']) ; $F->default = $table_info[$i]['dflt_value'] ; $F->maxlength = 0; $F->primary_key = $table_info[$i]['pk'] ; //$F->notnull= $table_info[$i]['notnull']; $retval[] = $F; } }else{ //クエリ結果のfield_dataはとれないので強引に決めうちで作るようにした //だからこの結果をそのまま使うのはよろしくないが、とりあえずscaffoldingの編集画面は落ちなくなる //var_dump($this -> pdo_results);exit; foreach($this -> pdo_results as $row){ foreach($row as $k => $v){ $F = new stdClass(); $F->name = $k ; $F->type = 'text' ;//text決め打ち $F->default = NULL ; //NULL決め打ち $F->maxlength = 0;//0決め打ち $F->primary_key = ("id" == $k ) ? "1" : "0" ; //id列がプライマリキーであること決め打ち $retval[] = $F; } } } return $retval; } // -------------------------------------------------------------------- /** * COPY FROM sqlite_result.php * Free the result * * @return null */ function free_result() { // Not implemented in SQLite } // -------------------------------------------------------------------- /** * Data Seek * * Moves the internal pointer to the desired offset. We call * this internally before fetching results to make sure the * result set starts at zero * * @access private * @return array */ function _data_seek($n = 0) { //todo:どうする //return sqlite_seek($this->result_id, $n); } // -------------------------------------------------------------------- /** * Result - associative array * * Returns the result set as an array * * @access private * @return array */ function _fetch_assoc() { if ( is_array( $this -> pdo_results ) ) { $i = $this -> pdo_index; $this -> pdo_index++; if ( isset( $this -> pdo_results[$i] ) ) { return $this -> pdo_results[$i]; } return null; } return $this -> result_id -> fetch( PDO :: FETCH_ASSOC ); } /** * Result - object * * Returns the result set as an object * * @access private * @return object */ function _fetch_object() { if ( is_array( $this -> pdo_results ) ) { $i = $this -> pdo_index; $this -> pdo_index++; if ( isset( $this -> pdo_results[$i] ) ) { $back = ''; foreach ( $this -> pdo_results[$i] as $key => $val ) { $back -> $key = $val; } return $back; } return null; } return $this -> result_id -> fetch( PDO :: FETCH_OBJ ); } } //endofclass /** * End of file pdo_result.php */ /** * Location: ./system/database/drivers/pdo/pdo_result.php */ ?>
動作確認
デフォルトDBを切り替えただけで、他のソースは全く変えていないのでコントローラとかは今日は貼らない。
ただ、pdoを使うと
$this -> db_session -> set_flashdata( "tasklist_edit_form", serialize( $this -> validation ) );
みたいにシリアライズしてごにょごにょすることは出来ない。php組み込みのオブジェクトはだめとのこと。
データは、scaffoldingで追加した。
ふむ、動いているようだ。
sqlite3のtemp.dbの中身も見てみる。
一応OKみたい。
dix3はsqlite3をサブDBとしてつかうほうほうをてにいれた!
(08/11/12 記述内 datas → dataに綴り誤りを修正)