本文对FleaPHP发行包中的sqlite驱动程序进行了修订。满足在用户不实现定义数据库表结构的情况下直接在程序中使用数据库功能。
该修订目前尚未纳入FleaPHP的发行包,应用者请注意对代码的验证。
Fleaphp是一个简便快捷、执行效率理想、并且得到良好文档化的基于PHP语言的开发框架(Framework)。在半甲项目启动的时候,即选择Fleaphp作为快速开发框架。在研究Fleaphp时,我发现SQLite的驱动程序在某些代码下无法正确的工作。以下是导致问题的源代码:
Code
/** 以下代码来自Fleaphp论坛,http://www.fleaphp.org/bbs/viewthread.php?tid=2559&highlight=sqlite
*/
require('./FLEA/FLEA.php');
FLEA::init();
// 准备数据库连接信息
$dsn = array(
'driver' => 'sqlite',
'db' => 'test.db',
);
// 指定数据库连接设置,TableDataGateway 会自动取出 dbDSN 设置来连接数据库
set_app_inf('dbDSN', $dsn);
// 初始化 FleaPHP 运行环境
FLEA::init();
// 由于 FLEA_Db_TableDataGateway 并不是自动载入的,因此需要明确载入
FLEA::loadClass('FLEA_Db_TableDataGateway');
// 从 FLEA_Db_TableDataGateway 派生 Posts 类
class Posts extends FLEA_Db_TableDataGateway
{
// 指定数据表名称
var $tableName = 'posts';
// 指定主键字段名
var $primaryKey = 'post_id';
}
// 构造 Posts 实例
$modelPosts =& new Posts();
// 创建一条新记录,并返回新记录的主键值
$row = array(
'title' => 'First post',
'body' => 'First post body',
);
$newPostId = $modelPosts->create($row);//这句会出问题,请问如何解决?
echo $newPostId;
// 读取刚刚创建的新记录
$post = $modelPosts->findAll();
// 输出记录内容
dump($post);
分析上面的源代码,我发现了以下问题:
1、 源代码中没有声明表结构。依靠Fleaphp的数据库驱动模块自动创建数据表。
2、 源代码中没有指明主键,因此,无法依靠SQLite的主键取值自增加的特性来维护主键取值的不同
3、 以上代码在执行过程中,报错:“LAST_INSERTED_ID”函数找不到。通过查找手册,发现该函数原始为从MySQL驱动程序中开始使用。但SQLite并未提供相同名称的函数。因此代码执行出错。而FleaPHP发行包中,有相关代码,只是存在Bug。
要避免上述情况出现,实现定义好表结构,并指定主键就可以避免相关问题的出现。不过通过分析源代码,SQLite驱动程序中对于上述代码是可以正常支持的。因此,我对代码进行了如下修改。
Code
<?php
/**
* 定义 FLEA_Db_Driver_Sqlite 驱动,用PDO实现访问sqlite3数据库
* Editor by lonestone 2007 10 13
* Email:wangyong.yichang@gmail.com
* Version 0.1
* Modified by Banjia 2008-10-28
* Email: wellown@gmail.com
* version 0.2
*/
FLEA::loadClass('FLEA_Db_Driver_Abstract');
/**
* 用于 sqlite 使用pdo扩展的数据库驱动程序
*/
class FLEA_Db_Driver_Sqlite extends FLEA_Db_Driver_Abstract
{
/**
* 用于 genSeq()、dropSeq() 和 nextId() 的 SQL 查询语句
*/
//var $NEXT_ID_SQL = "UPDATE %s SET id = LAST_INSERT_ID(id + 1)";
// modified by Banjia
var $NEXT_ID_SQL = "UPDATE %s SET id = ( SELECT MAX(id) FROM %s ) +1 ";
//end of modify
var $CREATE_SEQ_SQL = "CREATE TABLE %s (id INT NOT NULL)";
var $INIT_SEQ_SQL = "INSERT INTO %s VALUES (%s)";
var $DROP_SEQ_SQL = "DROP TABLE %s";
/**
* 用于描绘 true、false 和 null 的数据库值
*/
var $TRUE_VALUE = 1;
var $FALSE_VALUE = 0;
var $NULL_VALUE = 'NULL';
/**
* 用于获取元数据的 SQL 查询语句
*/
var $META_COLUMNS_SQL = "SELECT sql FROM sqlite_master WHERE type='table' and name='%s'"; //sqlite 用这个表来保存数据库的SQL
/**
* 数据库连接信息
*
* @var array
*/
var $dsn = null;
/**
* 数据库连接句柄
*
* @var resource
*/
var $conn = null;
/**
* 所有 SQL 查询的日志
*
* @var array
*/
var $log = array();
/**
* 指示是否记录 SQL 语句(部署模式时该设置默认为 false)
*
* @var boolean
*/
var $enableLog = false;
/**
* 最后一次数据库操作的错误信息
*
* @var mixed
*/
var $lasterr = null;
/**
* 最后一次数据库操作的错误代码
*
* @var mixed
*/
var $lasterrcode = null;
/**
* 最近一次插入操作或者 nextId() 操作返回的插入 ID
*
* @var mixed
*/
var $_insertId = null;
/**
* 指示事务启动次数
*
* @var int
*/
var $_transCount = 0;
/**
* 指示事务是否提交
*
* @var boolean
*/
var $_transCommit = true;
/**
* 构造函数
*
* @param array $dsn
*/
function FLEA_Db_Driver_Sqlite( $dsn = false )
{
$tmp = ( array )$dsn;
unset( $tmp['password'] );
$this->dsn = $dsn;
$this->enableLog = !defined( 'DEPLOY_MODE' ) || DEPLOY_MODE != true;
if ( !function_exists( 'log_message' ) )
{
$this->enableLog = false;
}
}
/**
* 连接数据库
*
* @param array $dsn
* @return boolean
*/
function connect( $dsn = false )
{
$dsn = $dsn? $dsn : $this->dsn;
$this->conn = false;
if ( file_exists( $dsn['db'] ) )
{
try{
$this->conn = new PDO( 'sqlite2:' . $dsn['db'] ); //链接sqlite2
} catch (PDOException $e) {
}
if ( !$this->conn ) $this->conn = new PDO( 'sqlite:' . $dsn['db'] ); //失败后尝试sqlite3
if ( is_object( $this->conn ) )
{
return $this->conn;
}
}
FLEA::loadClass( 'FLEA_Db_Exception_SqlQuery' );
__THROW( new FLEA_Db_Exception_SqlQuery( "connect('{$dsn['db']}') failed! debug message:" . $ex->getMessage() ) );
return false;
}
/**
* 关闭数据库连接
*/
function close()
{
$this->conn = null;
$this->lasterr = null;
$this->lasterrcode = null;
$this->_insertId = null;
$this->_transCount = 0;
$this->_transCommit = true;
}
/**
* 执行一个查询,返回一个 resource 或者 boolean 值
*
* @param string $sql
* @param array $inputarr
* @param boolean $throw 指示查询出错时是否抛出异常
* @return resource |boolean
*/
function execute( $sql, $inputarr = null, $throw = true )
{
if ( substr( $sql, 0, 11 ) == "INSERT INTO" )
{
// 删除SQL中的指定的表,SQLITE不支持在插入中语句有表名在前面
$len1 = strpos( $sql, '(' );
$len2 = strpos( $sql, ')' );
$len3 = strpos( $sql, 'VALUES' );
$temp = array();
if ( $len2 < $len3 )
{
$temp[] = substr( $sql, 0, $len1 );
$temp[] = substr( $sql, $len1, $len2 - $len1 );
$temp[] = substr( $sql, $len2 );
$temp[1] = eregi_replace( "[a-z_0-9]+\\.", "", $temp[1] );
$sql = implode( $temp );
}
}
if ( is_array( $inputarr ) )
{
$sql = $this->_prepareSql( $sql, $inputarr );
}
if ( $this->enableLog )
{
$this->log[] = $sql;
log_message( "sql:\n{$sql}", 'debug' );
}
$result = $this->conn->query( $sql );
if ( $result !== false )
{
$this->lasterr = null;
$this->lasterrcode = null;
return $result;
}
$this->lasterrcode = $this->conn->errorCode();
$this->lasterr = $this->conn->errorInfo();
if ( !$throw )
{
return false;
}
FLEA::loadClass( 'FLEA_Db_Exception_SqlQuery' );
__THROW( new FLEA_Db_Exception_SqlQuery( $sql, $this->lasterr[2], $this->lasterrcode ) );
return false;
}
/**
* 转义字符串
*
* @param string $value
* @return mixed
*/
function qstr( $value )
{
if ( is_bool( $value ) )
{
return $value ? $this->TRUE_VALUE : $this->FALSE_VALUE;
}
if ( is_null( $value ) )
{
return $this->NULL_VALUE;
}
return $this->conn->quote( $value );
}
/**
* 将数据表名字转换为完全限定名
*
* @param string $tableName
* @return string
*/
function qtable( $tableName )
{
return $tableName; //SQLite 对转换支持不是很好,经常出错
}
/**
* 将字段名转换为完全限定名,避免因为字段名和数据库关键词相同导致的错误
*
* @param string $fieldName
* @param string $tableName
* @return string
*/
function qfield( $fieldName, $tableName = null )
{
$pos = strpos( $fieldName, '.' );
if ( $pos !== false )
{
$tableName = substr( $fieldName, 0, $pos );
$fieldName = substr( $fieldName, $pos + 1 );
}
if ( $tableName != '' )
{
if ( $fieldName != '*' )
{
return "{$tableName}.{$fieldName}";
}
else
{
return "{$tableName}.*";
}
}
else
{
if ( $fieldName != '*' )
{
return "{$fieldName}";
}
else
{
return "*";
}
}
}
/**
* 一次性将多个字段名转换为完全限定名
*
* @param string $ |array $fields
* @param string $tableName
* @return string
*/
function qfields( $fields, $tableName = null )
{
if ( !is_array( $fields ) )
{
$fields = explode( ',', $fields );
}
$return = array();
foreach ( $fields as $fieldName )
{
$fieldName = trim( $fieldName );
if ( $fieldName == '' )
{
continue;
}
$pos = strpos( $fieldName, '.' );
if ( $pos !== false )
{
$tableName = substr( $fieldName, 0, $pos );
$fieldName = substr( $fieldName, $pos + 1 );
}
if ( $tableName != '' )
{
if ( $fieldName != '*' )
{
$return[] = "{$tableName}.{$fieldName}";
}
else
{
$return[] = "{$tableName}.*";
}
}
else
{
if ( $fieldName != '*' )
{
$return[] = "{$fieldName}";
}
else
{
$return[] = '*';
}
}
}
return implode( ', ', $return );
}
/**
* 为数据表产生下一个序列值
*
* @param string $seqName
* @param string $startValue
* @return int
*/
function nextId( $seqName = 'sdboseq', $startValue = 1 )
{
$result = $this->execute( sprintf( $this->NEXT_ID_SQL, $seqName, $seqName ), null, false );//Modified by Banjia
echo "sql is". sprintf( $this->NEXT_ID_SQL, $seqName, $seqName ). "\n";
dump ($result);
if ( $result === false )
{
if ( !$this->createSeq( $seqName, $startValue ) )
{
return false;
}
$this->execute( sprintf( $this->NEXT_ID_SQL, $seqName, $seqName ) );//Modified by Banjia
}
//$id = $this->insertId();
//$result = $this->getRow( sprintf("select max(id) as id from %s", $seqName) );
$id = $this->getOne( sprintf("select max(id) as id from %s", $seqName) );
if ( 0 )//张晓京填写的补充测试代码
{
dump( $id );
echo "==== new id is ====". $id . "\n";
}
if ( $id )
{
return $id;
}
if ( $this->execute( sprintf( $this->INIT_SEQ_SQL, $seqName, $startValue ) ) )
{
return $startValue;
}
return false;
}
/**
* 创建一个新的序列,成功返回 true,失败返回 false
*
* @param string $seqName
* @param int $startValue
* @return boolean
*/
function createSeq( $seqName = 'sdboseq', $startValue = 1 )
{
if ( $this->execute( sprintf( $this->CREATE_SEQ_SQL, $seqName ) ) )
{
return $this->execute( sprintf( $this->INIT_SEQ_SQL, $seqName, $startValue - 1 ) );
}
else
{
return false;
}
}
/**
* 删除一个序列
* 具体的实现与数据库系统有关。
*
* @param string $seqName
*/
function dropSeq( $seqName = 'sdboseq' )
{
return $this->execute( sprintf( $this->DROP_SEQ_SQL, $seqName ) );
}
/**
* 获取自增字段的最后一个值
*
* @return mixed
*/
function insertId( $seqName)
{
return $this->conn->lastInsertId();
}
/**
* 返回最近一次数据库操作受到影响的记录数
*
* @return int
*/
function affectedRows()
{
return $this->conn->exec(); //这里仅对select有效
}
/**
* 从记录集中返回一行数据
*
* @param resouce $res
* @return array
*/
function fetchRow( $res )
{
$row = $res->fetch();
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
return $temp;
}
/**
* 从记录集中返回一行数据,字段名作为键名
*
* @param resouce $res
* @return array
*/
function fetchAssoc( $res )
{
$row = $res->fetch( PDO::FETCH_ASSOC );
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
return $temp;
}
/**
* 释放查询句柄
*
* @param resource $res
* @return boolean
*/
function freeRes( $res )
{
// return sqlite_free_result($res);
return true; //sqlite 没有这样的函数
}
/**
* 进行限定记录集的查询
*
* @param string $sql
* @param int $length
* @param int $offset
* @return resource
*/
function selectLimit( $sql, $length = null, $offset = null )
{
if ( $offset !== null )
{
$sql .= "\nLIMIT " . ( int )$offset;
if ( $length !== null )
{
$sql .= ', ' . ( int )$length;
}
else
{
$sql .= ', 4294967294';
}
}elseif ( $length !== null )
{
$sql .= "\nLIMIT " . ( int )$length;
}
return $this->execute( $sql );
}
/**
* 执行一个查询,返回查询结果记录集
*
* @param string $ |resource $sql
* @return array
*/
function & getAll( $sql )
{
if ( is_object( $sql ) )
{
$res = $sql;
}
else
{
$res = $this->execute( $sql );
}
$data = array();
while ( $row = $res->fetch( PDO::FETCH_ASSOC ) )
{
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
$data[] = $temp;
}
return $data;
}
/**
* 执行一个查询,返回分组后的查询结果记录集
* $groupBy 参数如果为字符串或整数,表示结果集根据 $groupBy 参数指定的字段进行分组。
如果 $groupBy 参数为 true,则表示根据每行记录的第一个字段进行分组。
*
* @param string $ |resource $sql
* @param string $ |int|boolean $groupBy
* @return array
*/
function & getAllGroupBy( $sql, $groupBy )
{
if ( is_object( $sql ) )
{
$res = $sql;
}
else
{
$res = $this->execute( $sql );
}
$data = array();
$row = $res->fetch( PDO::FETCH_ASSOC );
if ( $row != false )
{
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
$row = $temp;
if ( $groupBy === true )
{
$groupBy = key( $row );
}
do
{
$rkv = $row[$groupBy];
unset( $row[$groupBy] );
$data[$rkv][] = $row;
}
while ( $row = $res->fetch( PDO::FETCH_ASSOC ) );
}
return $data;
}
/**
* 执行一个查询,返回查询结果记录集、指定字段的值集合以及以该字段值分组后的记录集
*
* @param string $ |resource $sql
* @param string $field
* @param array $fieldValues
* @param array $reference
* @return array
*/
function getAllWithFieldRefs( $sql, $field, & $fieldValues, & $reference )
{
if ( is_object( $sql ) )
{
$res = $sql;
}
else
{
$res = $this->execute( $sql );
}
$fieldValues = array();
$reference = array();
$offset = 0;
$data = array();
while ( $row = $res->fetch( PDO::FETCH_ASSOC ) )
{
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
$row = $temp;
$fieldValue = $row[$field];
unset( $row[$field] );
$data[$offset] = $row;
$fieldValues[$offset] = $fieldValue;
$reference[$fieldValue] = & $data[$offset];
$offset++;
}
return $data;
}
/**
* 执行一个查询,并将数据按照指定字段分组后与 $assocRowset 记录集组装在一起
*
* @param string $ |resource $sql
* @param array $assocRowset
* @param string $mappingName
* @param boolean $oneToOne
* @param string $refKeyName
* @param mixed $limit
*/
function assemble( $sql, & $assocRowset, $mappingName, $oneToOne, $refKeyName, $limit = null )
{
if ( is_object( $sql ) )
{
$res = $sql;
}
else
{
if ( $limit !== null )
{
if ( is_array( $limit ) )
{
list( $length, $offset ) = $limit;
}
else
{
$length = $limit;
$offset = 0;
}
$res = $this->selectLimit( $sql, $length, $offset );
}
else
{
$res = $this->execute( $sql );
}
}
if ( $oneToOne )
{
// 一对一组装数据
while ( $row = $res->fetch( PDO::FETCH_ASSOC ) )
{
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
$row = $temp;
$rkv = $row[$refKeyName];
unset( $row[$refKeyName] );
$assocRowset[$rkv][$mappingName] = $row;
}
}
else
{
// 一对多组装数据
while ( $row = $res->fetch( PDO::FETCH_ASSOC ) )
{
$rkv = $row[$refKeyName];
unset( $row[$refKeyName] );
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
$assocRowset[$rkv][$mappingName][] = $temp;
}
}
}
/**
* 执行查询,返回第一条记录的第一个字段
*
* @param string $ |resource $sql
* @return mixed
*/
function getOne( $sql )
{
if ( is_object( $sql ) )
{
$res = $sql;
}
else
{
$res = $this->execute( $sql );
}
$row = $res->fetch( PDO::FETCH_NUM );
// sqlite_free_result($res);
return isset( $row[0] ) ? $row[0] : null;
}
/**
* 执行查询,返回第一条记录
*
* @param string $ |resource $sql
* @return mixed
*/
function & getRow( $sql )
{
if ( is_object( $sql ) )
{
$res = $sql;
}
else
{
$res = $this->execute( $sql );
}
$row = $res->fetch( PDO::FETCH_ASSOC );
$temp = array();
foreach( $row as $key => $value )
{
$key = eregi_replace( '^[a-z0-9_]+\.', '', $key );
$temp[$key] = $value;
}
return $temp;
}
/**
* 执行查询,返回结果集的指定列
*
* @param string $ |resource $sql
* @param int $col 要返回的列,0 为第一列
* @return mixed
*/
function & getCol( $sql, $col = 0 )
{
if ( is_object( $sql ) )
{
$res = $sql;
}
else
{
$res = $this->execute( $sql );
}
$data = array();
while ( $row = $res->fetch( PDO::FETCH_NUM ) )
{
$data[] = $row[$col];
}
return $data;
}
/**
* 返回指定表(或者视图)的元数据
*
* 部分代码参考 ADOdb 实现。
* 每个字段包含下列属性:
*
* name: 字段名
scale: 小数位数
* type: 字段类型
* simpleType: 简单字段类型(与数据库无关)
maxLength: 最大长度
notNull: 是否不允许保存 NULL 值
primaryKey: 是否是主键
autoIncrement: 是否是自动增量字段
binary: 是否是二进制数据
* unsigned: 是否是无符号数值
hasDefault: 是否有默认值
defaultValue: 默认值
*
* @param string $table
* @return array
*/
function & metaColumns( $table )
{
/**
* C 长度小于等于 250 的字符串
* X 长度大于 250 的字符串
* B 二进制数据
N 数值或者浮点数
* D 日期
* T TimeStamp
* L 逻辑布尔值
I 整数
* R 自动增量或计数器
*/
static $typeMap = array( 'BIT' => 'I',
'TINYINT' => 'I',
'BOOL' => 'L',
'BOOLEAN' => 'L',
'SMALLINT' => 'I',
'MEDIUMINT' => 'I',
'INT' => 'I',
'INTEGER' => 'I',
'BIGINT' => 'I',
'FLOAT' => 'N',
'DOUBLE' => 'N',
'DOUBLEPRECISION' => 'N',
'FLOAT' => 'N',
'DECIMAL' => 'N',
'DEC' => 'N',
'DATE' => 'D',
'DATETIME' => 'T',
'TIMESTAMP' => 'T',
'TIME' => 'T',
'YEAR' => 'I',
'CHAR' => 'C',
'NCHAR' => 'C',
'VARCHAR' => 'C',
'NVARCHAR' => 'C',
'BINARY' => 'B',
'VARBINARY' => 'B',
'TINYBLOB' => 'X',
'TINYTEXT' => 'X',
'BLOB' => 'X',
'TEXT' => 'X',
'MEDIUMBLOB' => 'X',
'MEDIUMTEXT' => 'X',
'LONGBLOB' => 'X',
'LONGTEXT' => 'X',
'ENUM' => 'C',
'SET' => 'C',
);
$rs = $this->execute( sprintf( $this->META_COLUMNS_SQL, $table ) );
//dump ($rs );
if ( !$rs )
{
return false;
}
$retarr = array();
$sql = $rs->fetch( PDO::FETCH_NUM );
$sql = $sql[0];
$firstPar = strpos( $sql, '(' );
$endPar = strrpos( $sql, ')' )-1;
$sql = substr( $sql, ( $firstPar + 1 ), ( $endPar - $firstPar ) );
$sql = str_replace( "\n", '', $sql );
$sql = str_replace( "'", '', $sql );
// add by zhangxj
$sql = str_replace("[", '', $sql );
$sql = str_replace("]", '', $sql );
// end of add
$ligne = explode( ',', $sql );
// get index key
$sql = "select sql from sqlite_master where type='index' and tbl_name='$table'";
$rs = $this->execute( $sql );
$sql = $rs->fetch( PDO::FETCH_NUM );
$sql = $sql[0];
$firstPar = strpos( $sql, '(' );
$endPar = strrpos( $sql, ')' )-1;
$sql = substr( $sql, ( $firstPar + 1 ), ( $endPar - $firstPar ) );
$sql = str_replace( "\n", '', $sql );
$sql = str_replace( "'", '', $sql );
$temp = explode( ',', $sql );
$index = array();
foreach ( $temp as $value )
{
$value = trim( $value );
if ( $value )
{
$index[$value] = true;
}
}
while ( list( $ligneNum, $cont ) = each( $ligne ) )
{
$row = explode( ' ', trim( $cont ) );
$field = array();
$field['name'] = $row[0];
$type = $row[1];
$field['scale'] = null;
$queryArray = false;
if ( preg_match( '/^(.+)\((\d+),(\d+)/', $type, $queryArray ) )
{
$field['type'] = $queryArray[1];
$field['maxLength'] = is_numeric( $queryArray[2] ) ? $queryArray[2] : -1;
$field['scale'] = is_numeric( $queryArray[3] ) ? $queryArray[3] : -1;
}elseif ( preg_match( '/^(.+)\((\d+)/', $type, $queryArray ) )
{
$field['type'] = $queryArray[1];
$field['maxLength'] = is_numeric( $queryArray[2] ) ? $queryArray[2] : -1;
}elseif ( preg_match( '/^(enum)\((.*)\)$/i', $type, $queryArray ) )
{
$field['type'] = $queryArray[1];
$arr = explode( ",", $queryArray[2] );
$field['enums'] = $arr;
$zlen = max( array_map( "strlen", $arr ) ) - 2; // PHP >= 4.0.6
$field['maxLength'] = ( $zlen > 0 ) ? $zlen : 1;
}
else
{
$field['type'] = $type;
$field['maxLength'] = -1;
}
$field['simpleType'] = $typeMap[strtoupper( $field['type'] )];
if ( $field['simpleType'] == 'C' && $field['maxLength'] > 250 )
{
$field['simpleType'] = 'X';
}
$temp = eregi( 'PRIMARY[[:space:]]KEY', $cont );
$field['primaryKey'] = $temp || $index[$row[0]];
$field['notNull'] = $field['primaryKey'] || ( strtoupper( $row[2] ) == 'NOT' );
$field['autoIncrement'] = $temp;
if ( $field['autoIncrement'] )
{
$field['simpleType'] = 'R';
}
$field['binary'] = ( strpos( $type, 'blob' ) !== false );
$field['unsigned'] = ( strpos( $type, 'unsigned' ) !== false );
if ( !$field['binary'] )
{
$d = $row[4];
if ( $d != '' && $d != 'NULL' )
{
$field['hasDefault'] = true;
$field['defaultValue'] = $d;
}
else
{
$field['hasDefault'] = false;
}
}
$retarr[strtoupper( $field['name'] )] = $field;
}
// dump ( $retarr );
return $retarr;
}
/**
* 返回数据库可以接受的日期格式
*
* @param int $timestamp
*/
function dbTimeStamp( $timestamp )
{
return date( 'Y-m-d H:i:s', $timestamp );
}
/**
* 启动事务
*/
function startTrans()
{
$this->_transCount += 1;
try{
$this->conn->rollBack();
}
catch(PDOException $e)
{}
$this->conn->beginTransaction();
}
/**
* 完成事务,根据查询是否出错决定是提交事务还是回滚事务
*
* 如果 $commitOnNoErrors 参数为 true,当事务中所有查询都成功完成时,则提交事务,否则回滚事务
* 如果 $commitOnNoErrors 参数为 false,则强制回滚事务
*
* @param $commitOnNoErrors 指示在没有错误时是否提交事务
*/
function completeTrans( $commitOnNoErrors = true )
{
if ( $this->_transCount < 1 )
{
return;
}
if ( $this->_transCount > 1 )
{
$this->_transCount -= 1;
return;
}
$this->_transCount = 0;
if ( $this->_transCommit && $commitOnNoErrors )
{
$this->conn->commit();
}
else
{
$this->conn->rollBack();
}
}
/**
* 强制指示在调用 completeTrans() 时回滚事务
*/
function failTrans()
{
$this->_transCommit = true;
}
/**
* 反复事务是否失败的状态
*/
function hasFailedTrans()
{
if ( $this->_transCount > 0 )
{
return $this->_transCommit === false;
}
return false;
}
/**
* 根据 SQL 语句和提供的参数数组,生成最终的 SQL 语句
*
* @param string $sql
* @param array $inputarr
* @return string
*/
function _prepareSql( $sql, & $inputarr )
{
$sqlarr = explode( '?', $sql );
$sql = '';
$ix = 0;
foreach ( $inputarr as $v )
{
$sql .= $sqlarr[$ix];
$typ = gettype( $v );
if ( $typ == 'string' )
{
$sql .= $this->qstr( $v );
}
else if ( $typ == 'double' )
{
$sql .= $this->qstr( str_replace( ',', '.', $v ) );
}
else if ( $typ == 'boolean' )
{
$sql .= $v ? $this->TRUE_VALUE : $this->FALSE_VALUE;
}
else if ( $v === null )
{
$sql .= 'NULL';
}
else
{
$sql .= $v;
}
$ix += 1;
}
if ( isset( $sqlarr[$ix] ) )
{
$sql .= $sqlarr[$ix];
}
return $sql;
}
}
以上源代码经过测试可以满足对Sqlite数据库进行操作的目的。可以保存到文件中,放在Fleaphp发行包的db/driver目录下以sqlite.php为文件名后使用。