From 647d47ccb46fc7b9bbcdebe568aae1352b1cc6d8 Mon Sep 17 00:00:00 2001 From: thinkphp Date: Sun, 17 Mar 2013 18:56:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E4=B8=AD=E9=97=B4?= =?UTF-8?q?=E5=B1=82=E6=94=B9=E4=B8=BAPDO=20=E5=A2=9E=E5=8A=A0Think\Db\Lit?= =?UTF-8?q?e=20=E7=94=A8=E4=BA=8E=E6=93=8D=E4=BD=9C=E5=8E=9F=E7=94=9FSQL?= =?UTF-8?q?=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Think/Db.php | 879 +++------------------------------- Think/Db/Driver.php | 943 +++++++++++++++++++++++++++++++++++++ Think/Db/Driver/Ibase.php | 339 ------------- Think/Db/Driver/Mongo.php | 752 ----------------------------- Think/Db/Driver/Mssql.php | 334 ------------- Think/Db/Driver/Mysql.php | 303 +----------- Think/Db/Driver/Mysqli.php | 345 -------------- Think/Db/Driver/Oracle.php | 215 +-------- Think/Db/Driver/Pdo.php | 447 ------------------ Think/Db/Driver/Pgsql.php | 256 +--------- Think/Db/Driver/Sqlite.php | 202 +------- Think/Db/Driver/Sqlsrv.php | 205 +------- Think/Db/Lite.php | 387 +++++++++++++++ 13 files changed, 1440 insertions(+), 4167 deletions(-) create mode 100644 Think/Db/Driver.php delete mode 100644 Think/Db/Driver/Ibase.php delete mode 100644 Think/Db/Driver/Mongo.php delete mode 100644 Think/Db/Driver/Mssql.php delete mode 100644 Think/Db/Driver/Mysqli.php delete mode 100644 Think/Db/Driver/Pdo.php create mode 100644 Think/Db/Lite.php diff --git a/Think/Db.php b/Think/Db.php index 59fe884a..62e5e5ba 100644 --- a/Think/Db.php +++ b/Think/Db.php @@ -19,861 +19,94 @@ namespace Think; * @author liu21st */ class Db { - // 数据库类型 - protected $dbType = null; - // 是否自动释放查询结果 - protected $autoFree = false; - // 当前操作所属的模型名 - protected $model = '_think_'; - // 是否使用永久连接 - protected $pconnect = false; - // 当前SQL指令 - protected $queryStr = ''; - protected $modelSql = []; - // 最后插入ID - protected $lastInsID = null; - // 返回或者影响记录数 - protected $numRows = 0; - // 返回字段数 - protected $numCols = 0; - // 事务指令数 - protected $transTimes = 0; - // 错误信息 - protected $error = ''; - // 数据库连接ID 支持多个连接 - protected $linkID = []; - // 当前连接ID - protected $_linkID = null; - // 当前查询ID - protected $queryID = null; - // 是否已经连接数据库 - protected $connected = false; - // 数据库连接参数配置 - protected $config = ''; - // 数据库表达式 - protected $comparison = ['eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN']; - // 查询表达式 - protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%'; - protected $conf = []; + static private $instance = []; /** * 取得数据库类实例 * @static * @access public * @return mixed 返回数据库驱动类 */ - public static function getInstance($config) { - static $_instance = []; + public static function getInstance($config=[]) { + $md5 = md5(serialize($config)); + if(!isset(self::$instance[$md5])) { + $options = self::parseConfig($config); + $class = 'Think\\Db\\Driver\\'.ucwords($options['dbms']); + if(class_exists($class)) { + self::$instance[$md5] = new $class($options); + }else{ + Error::halt('_DB_TYPE_INVALID_:'.$options['dbms']); + } + } + return self::$instance[$md5]; + } + + /** + * Lite版本数据库引擎 仅支持原生SQL 包括query和execute方法 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function lite($config=[]) { + static $_instance = []; $md5 = md5(serialize($config)); if(!isset($_instance[$md5])) { - $Db = new Db(); - $_instance[$md5] = $Db->factory($config); + $_instance[$md5] = new Think\Db\Lite(self::parseConfig($config)); } return $_instance[$md5]; } - /** - * 加载数据库 支持配置文件或者 DSN - * @access public - * @param mixed $db_config 数据库配置信息 - * @return string - */ - public function factory($db_config='') { - $this->conf = Config::get(); - // 读取数据库配置 - $db_config = $this->parseConfig($db_config); - if(empty($db_config['dbms'])) - throw_exception(Lang::get('_NO_DB_CONFIG_')); - // 数据库类型 - $db_type = strtolower($db_config['dbms']); - $class = '\Think\Db\Driver\\'. ucwords($db_type); - // 检查驱动类 - if(class_exists($class)) { - $db = new $class($db_config); - // 获取当前的数据库类型 - if( 'pdo' != $db_type ) - $db->dbType = strtoupper($db_type); - else - $db->dbType = $this->_getDsnType($db_config['dsn']); - }else { - // 类没有定义 - throw_exception(Lang::get('_NO_DB_DRIVER_').': ' . $class); + static public function parseConfig($config=[]){ + if(empty($config)) { + $config = Config::get(); } - return $db; - } - - /** - * 根据DSN获取数据库类型 返回大写 - * @access protected - * @param string $dsn dsn字符串 - * @return string - */ - protected function _getDsnType($dsn) { - $match = explode(':',$dsn); - $dbType = strtoupper(trim($match[0])); - return $dbType; - } - - /** - * 分析数据库配置信息,支持数组和DSN - * @access private - * @param mixed $db_config 数据库配置信息 - * @return string - */ - private function parseConfig($db_config='') { - if ( !empty($db_config) && is_string($db_config)) { - // 如果DSN字符串则进行解析 - $db_config = $this->parseDSN($db_config); - }elseif(is_array($db_config)) { // 数组配置 - $db_config = array_change_key_case($db_config); - $db_config = [ - 'dbms' => $db_config['db_type'], - 'username' => $db_config['db_user'], - 'password' => $db_config['db_pwd'], - 'hostname' => $db_config['db_host'], - 'hostport' => $db_config['db_port'], - 'database' => $db_config['db_name'], - 'dsn' => $db_config['db_dsn'], - 'params' => $db_config['db_params'], - ]; - }elseif(empty($db_config)) { - // 如果配置为空,读取配置文件设置 - if( isset($this->conf['db_dsn']) && $this->conf['db_dsn'] && 'pdo' != strtolower($this->conf['db_type']) ) { // 如果设置了DB_DSN 则优先 - $db_config = $this->parseDSN($this->conf['db_dsn']); - }else{ - $db_config = array ( - 'dbms' => $this->conf['db_type'], - 'username' => $this->conf['db_user'], - 'password' => $this->conf['db_pwd'], - 'hostname' => $this->conf['db_host'], - 'hostport' => $this->conf['db_port'], - 'database' => $this->conf['db_name'], - 'dsn' => isset($this->conf['db_dsn'])?$this->conf['db_dsn']:'', - 'params' => isset($this->conf['db_params'])?$this->conf['db_params']:'', - ); - } + if(is_string($config)) { + return self::parseDsn($config); } - return $db_config; - } - - /** - * 初始化数据库连接 - * @access protected - * @param boolean $master 主服务器 - * @return void - */ - protected function initConnect($master=true) { - if(empty($this->conf)) { - $this->conf = Config::get(); - } - - if(1 == $this->conf['db_deploy_type']) - // 采用分布式数据库 - $this->_linkID = $this->multiConnect($master); - else - // 默认单数据库 - if ( !$this->connected ) $this->_linkID = $this->connect(); - } - - /** - * 连接分布式服务器 - * @access protected - * @param boolean $master 主服务器 - * @return void - */ - protected function multiConnect($master=false) { - static $_config = []; - if(empty($_config)) { - // 缓存分布式数据库配置解析 - foreach ($this->config as $key=>$val){ - $_config[$key] = explode(',',$val); - } - } - // 数据库读写是否分离 - if($this->conf['db_rw_separate']){ - // 主从式采用读写分离 - if($master) - // 主服务器写入 - $r = floor(mt_rand(0,$this->conf['db_master_num']-1)); - else{ - if(is_numeric($this->conf['db_slave_no'])) {// 指定服务器读 - $r = $this->conf['db_slave_no']; - }else{ - // 读操作连接从服务器 - $r = floor(mt_rand($this->conf['db_master_num'],count($_config['hostname'])-1)); // 每次随机连接的数据库 - } - } - }else{ - // 读写操作不区分服务器 - $r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库 - } - $db_config = [ - 'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], - 'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], - 'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], - 'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], - 'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], - 'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], - 'params' => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0], - ]; - return $this->connect($db_config,$r); + return [ + 'dbms' => $config['db_type'], + 'dsn' => $config['db_dsn'], + 'username' => $config['db_user'], + 'password' => $config['db_pwd'], + 'hostname' => $config['db_host'], + 'hostport' => $config['db_port'], + 'database' => $config['db_name'], + 'params' => $config['db_params'], + 'charset' => $config['db_charset'], + 'deploy' => $config['db_deploy'], + 'socket' => $config['db_unix_socket'], + ]; } /** * DSN解析 - * 格式: mysql://username:passwd@localhost:3306/DbName + * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8 * @static * @access public * @param string $dsnStr * @return array */ - public function parseDSN($dsnStr) { + static public function parseDsn($dsnStr) { if( empty($dsnStr) ){return false;} $info = parse_url($dsnStr); - if($info['scheme']){ - $dsn = [ + if(!$info) { + return false; + } + $dsn = [ 'dbms' => $info['scheme'], 'username' => isset($info['user']) ? $info['user'] : '', 'password' => isset($info['pass']) ? $info['pass'] : '', 'hostname' => isset($info['host']) ? $info['host'] : '', 'hostport' => isset($info['port']) ? $info['port'] : '', - 'database' => isset($info['path']) ? substr($info['path'],1) : '' - ]; - }else { - preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); - $dsn = [ - 'dbms' => $matches[1], - 'username' => $matches[2], - 'password' => $matches[3], - 'hostname' => $matches[4], - 'hostport' => $matches[5], - 'database' => $matches[6] - ]; - } + 'database' => isset($info['path']) ? substr($info['path'],1) : '', + 'charset' => isset($info['fragment'])?$info['fragment']:'', + ]; $dsn['dsn'] = ''; // 兼容配置信息数组 + if(isset($info['query'])) { + parse_str($info['query'],$dsn['params']); + }else{ + $dsn['params'] = []; + } return $dsn; } - - /** - * 数据库调试 记录当前SQL - * @access protected - */ - protected function debug() { - $this->modelSql[$this->model] = $this->queryStr; - $this->model = '_think_'; - // 记录操作结束时间 - Debug::remark('queryEndTime','time'); - Log::record($this->queryStr.' [ RunTime:'.Debug::getUseTime('queryStartTime','queryEndTime').'s ]','SQL'); - } - - /** - * 设置锁机制 - * @access protected - * @return string - */ - protected function parseLock($lock=false) { - if(!$lock) return ''; - if('ORACLE' == $this->dbType) { - return ' FOR UPDATE NOWAIT '; - } - return ' FOR UPDATE '; - } - - /** - * set分析 - * @access protected - * @param array $data - * @return string - */ - protected function parseSet($data) { - foreach ($data as $key=>$val){ - $value = $this->parseValue($val); - if(is_scalar($value)) // 过滤非标量数据 - $set[] = $this->parseKey($key).'='.$value; - } - return ' SET '.implode(',',$set); - } - - /** - * 字段名分析 - * @access protected - * @param string $key - * @return string - */ - protected function parseKey(&$key) { - return $key; - } - - /** - * value分析 - * @access protected - * @param mixed $value - * @return string - */ - protected function parseValue($value) { - if(is_string($value)) { - $value = '\''.$this->escapeString($value).'\''; - }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ - $value = $this->escapeString($value[1]); - }elseif(is_array($value)) { - $value = array_map(array($this, 'parseValue'),$value); - }elseif(is_bool($value)){ - $value = $value ? '1' : '0'; - }elseif(is_null($value)){ - $value = 'null'; - } - return $value; - } - - /** - * field分析 - * @access protected - * @param mixed $fields - * @return string - */ - protected function parseField($fields) { - if(is_string($fields) && strpos($fields,',')) { - $fields = explode(',',$fields); - } - if(is_array($fields)) { - // 完善数组方式传字段名的支持 - // 支持 'field1'=>'field2' 这样的字段别名定义 - $array = []; - foreach ($fields as $key=>$field){ - if(!is_numeric($key)) - $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); - else - $array[] = $this->parseKey($field); - } - $fieldsStr = implode(',', $array); - }elseif(is_string($fields) && !empty($fields)) { - $fieldsStr = $this->parseKey($fields); - }else{ - $fieldsStr = '*'; - } - //TODO 如果是查询全部字段,并且是join的方式,那么就把要查的表加个别名,以免字段被覆盖 - return $fieldsStr; - } - - /** - * table分析 - * @access protected - * @param mixed $table - * @return string - */ - protected function parseTable($tables) { - if(is_array($tables)) {// 支持别名定义 - $array = []; - foreach ($tables as $table=>$alias){ - if(!is_numeric($table)) - $array[] = $this->parseKey($table).' '.$this->parseKey($alias); - else - $array[] = $this->parseKey($table); - } - $tables = $array; - }elseif(is_string($tables)){ - $tables = explode(',',$tables); - array_walk($tables, array(&$this, 'parseKey')); - } - return implode(',',$tables); - } - - /** - * where分析 - * @access protected - * @param mixed $where - * @return string - */ - protected function parseWhere($where) { - $whereStr = ''; - if(is_string($where)) { - // 直接使用字符串条件 - $whereStr = $where; - }else{ // 使用数组表达式 - $operate = isset($where['_logic'])?strtoupper($where['_logic']):''; - if(in_array($operate,['AND','OR','XOR'])){ - // 定义逻辑运算规则 例如 OR XOR AND NOT - $operate = ' '.$operate.' '; - unset($where['_logic']); - }else{ - // 默认进行 AND 运算 - $operate = ' AND '; - } - foreach ($where as $key=>$val){ - $whereStr .= '( '; - if(0===strpos($key,'_')) { - // 解析特殊条件表达式 - $whereStr .= $this->parseThinkWhere($key,$val); - }else{ - // 查询字段的安全过滤 - if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){ - throw_exception(L('_EXPRESS_ERROR_').':'.$key); - } - // 多条件支持 - $multi = is_array($val) && isset($val['_multi']); - $key = trim($key); - if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段 - $array = explode('|',$key); - $str = []; - foreach ($array as $m=>$k){ - $v = $multi?$val[$m]:$val; - $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; - } - $whereStr .= implode(' OR ',$str); - }elseif(strpos($key,'&')){ - $array = explode('&',$key); - $str = []; - foreach ($array as $m=>$k){ - $v = $multi?$val[$m]:$val; - $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; - } - $whereStr .= implode(' AND ',$str); - }else{ - $whereStr .= $this->parseWhereItem($this->parseKey($key),$val); - } - } - $whereStr .= ' )'.$operate; - } - $whereStr = substr($whereStr,0,-strlen($operate)); - } - return empty($whereStr)?'':' WHERE '.$whereStr; - } - - // where子单元分析 - protected function parseWhereItem($key,$val) { - $whereStr = ''; - if(is_array($val)) { - if(is_string($val[0])) { - if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算 - $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); - }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找 - if(is_array($val[1])) { - $likeLogic = isset($val[2])?strtoupper($val[2]):'OR'; - if(in_array($likeLogic,['AND','OR','XOR'])){ - $likeStr = $this->comparison[strtolower($val[0])]; - $like = []; - foreach ($val[1] as $item){ - $like[] = $key.' '.$likeStr.' '.$this->parseValue($item); - } - $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')'; - } - }else{ - $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); - } - }elseif('exp'==strtolower($val[0])){ // 使用表达式 - $whereStr .= ' ('.$key.' '.$val[1].') '; - }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 - if(isset($val[2]) && 'exp'==$val[2]) { - $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1]; - }else{ - if(is_string($val[1])) { - $val[1] = explode(',',$val[1]); - } - $zone = implode(',',$this->parseValue($val[1])); - $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; - } - }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 - $data = is_string($val[1])? explode(',',$val[1]):$val[1]; - $whereStr .= ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )'; - }else{ - throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); - } - }else { - $count = count($val); - $rule = isset($val[$count-1])?strtoupper($val[$count-1]):''; - if(in_array($rule,['AND','OR','XOR'])) { - $count = $count -1; - }else{ - $rule = 'AND'; - } - for($i=0;$i<$count;$i++) { - $data = is_array($val[$i])?$val[$i][1]:$val[$i]; - if('exp'==strtolower($val[$i][0])) { - $whereStr .= '('.$key.' '.$data.') '.$rule.' '; - }else{ - $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; - $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; - } - } - $whereStr = substr($whereStr,0,-4); - } - }else { - //对字符串类型字段采用模糊匹配 - if($this->conf['db_like_fields'] && preg_match('/('.$this->conf['db_like_fields'].')/i',$key)) { - $val = '%'.$val.'%'; - $whereStr .= $key.' LIKE '.$this->parseValue($val); - }else { - $whereStr .= $key.' = '.$this->parseValue($val); - } - } - return $whereStr; - } - - /** - * 特殊条件分析 - * @access protected - * @param string $key - * @param mixed $val - * @return string - */ - protected function parseThinkWhere($key,$val) { - $whereStr = ''; - switch($key) { - case '_string': - // 字符串模式查询条件 - $whereStr = $val; - break; - case '_complex': - // 复合查询条件 - $whereStr = substr($this->parseWhere($val),6); - break; - case '_query': - // 字符串模式查询条件 - parse_str($val,$where); - if(isset($where['_logic'])) { - $op = ' '.strtoupper($where['_logic']).' '; - unset($where['_logic']); - }else{ - $op = ' AND '; - } - $array = []; - foreach ($where as $field=>$data) - $array[] = $this->parseKey($field).' = '.$this->parseValue($data); - $whereStr = implode($op,$array); - break; - } - return $whereStr; - } - - /** - * limit分析 - * @access protected - * @param mixed $lmit - * @return string - */ - protected function parseLimit($limit) { - return !empty($limit)? ' LIMIT '.$limit.' ':''; - } - - /** - * join分析 - * @access protected - * @param mixed $join - * @return string - */ - protected function parseJoin($join) { - $joinStr = ''; - if(!empty($join)) { - if(is_array($join)) { - foreach ($join as $key=>$_join){ - if(false !== stripos($_join,'JOIN')) - $joinStr .= ' '.$_join; - else - $joinStr .= ' LEFT JOIN ' .$_join; - } - }else{ - $joinStr .= ' LEFT JOIN ' .$join; - } - } - //将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀和后缀 - $joinStr = preg_replace("/__([A-Z_-]+)__/esU",Config::get('db_prefix').".strtolower('$1')",$joinStr); - return $joinStr; - } - - /** - * order分析 - * @access protected - * @param mixed $order - * @return string - */ - protected function parseOrder($order) { - if(is_array($order)) { - $array = []; - foreach ($order as $key=>$val){ - if(is_numeric($key)) { - $array[] = $this->parseKey($val); - }else{ - $array[] = $this->parseKey($key).' '.$val; - } - } - $order = implode(',',$array); - } - return !empty($order)? ' ORDER BY '.$order:''; - } - - /** - * group分析 - * @access protected - * @param mixed $group - * @return string - */ - protected function parseGroup($group) { - return !empty($group)? ' GROUP BY '.$group:''; - } - - /** - * having分析 - * @access protected - * @param string $having - * @return string - */ - protected function parseHaving($having) { - return !empty($having)? ' HAVING '.$having:''; - } - - /** - * comment分析 - * @access protected - * @param string $comment - * @return string - */ - protected function parseComment($comment) { - return !empty($comment)? ' /* '.$comment.' */':''; - } - - /** - * distinct分析 - * @access protected - * @param mixed $distinct - * @return string - */ - protected function parseDistinct($distinct) { - return !empty($distinct)? ' DISTINCT ' :''; - } - - /** - * union分析 - * @access protected - * @param mixed $union - * @return string - */ - protected function parseUnion($union) { - if(empty($union)) return ''; - if(isset($union['_all'])) { - $str = 'UNION ALL '; - unset($union['_all']); - }else{ - $str = 'UNION '; - } - foreach ($union as $u){ - $sql[] = $str.(is_array($u)?$this->buildSelectSql($u):$u); - } - return implode(' ',$sql); - } - - /** - * 插入记录 - * @access public - * @param mixed $data 数据 - * @param array $options 参数表达式 - * @param boolean $replace 是否replace - * @return false | integer - */ - public function insert($data,$options=[],$replace=false) { - $values = $fields = []; - $this->model = $options['model']; - foreach ($data as $key=>$val){ - $value = $this->parseValue($val); - if(is_scalar($value)) { // 过滤非标量数据 - $values[] = $value; - $fields[] = $this->parseKey($key); - } - } - $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; - $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); - $sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql); - } - - /** - * 通过Select方式插入记录 - * @access public - * @param string $fields 要插入的数据表字段名 - * @param string $table 要插入的数据表名 - * @param array $option 查询数据参数 - * @return false | integer - */ - public function selectInsert($fields,$table,$options=[]) { - $this->model = $options['model']; - if(is_string($fields)) $fields = explode(',',$fields); - array_walk($fields, [$this, 'parseKey']); - $sql = 'INSERT INTO '.$this->parseTable($table).' ('.implode(',', $fields).') '; - $sql .= $this->buildSelectSql($options); - return $this->execute($sql); - } - - /** - * 更新记录 - * @access public - * @param mixed $data 数据 - * @param array $options 表达式 - * @return false | integer - */ - public function update($data,$options) { - $this->model = $options['model']; - $sql = 'UPDATE ' - .$this->parseTable($options['table']) - .$this->parseSet($data) - .$this->parseWhere(!empty($options['where'])?$options['where']:'') - .$this->parseOrder(!empty($options['order'])?$options['order']:'') - .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false) - .$this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql); - } - - /** - * 删除记录 - * @access public - * @param array $options 表达式 - * @return false | integer - */ - public function delete($options=[]) { - $this->model = $options['model']; - $sql = 'DELETE FROM ' - .$this->parseTable($options['table']) - .$this->parseWhere(!empty($options['where'])?$options['where']:'') - .$this->parseOrder(!empty($options['order'])?$options['order']:'') - .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false) - .$this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql); - } - - /** - * 查找记录 - * @access public - * @param array $options 表达式 - * @return mixed - */ - public function select($options=[]) { - $this->model = $options['model']; - $sql = $this->buildSelectSql($options); - $cache = isset($options['cache'])?$options['cache']:false; - if($cache) { // 查询缓存检测 - $key = is_string($cache['key'])?$cache['key']:md5($sql); - $value = S($key,'',$cache); - if(false !== $value) { - return $value; - } - } - $result = $this->query($sql); - if($cache && false !== $result ) { // 查询缓存写入 - S($key,$result,$cache); - } - return $result; - } - - /** - * 生成查询SQL - * @access public - * @param array $options 表达式 - * @return string - */ - public function buildSelectSql($options=[]) { - if(isset($options['page'])) { - // 根据页数计算limit - if(strpos($options['page'],',')) { - list($page,$listRows) = explode(',',$options['page']); - }else{ - $page = $options['page']; - } - $page = $page?$page:1; - $listRows= isset($listRows)?$listRows:(is_numeric($options['limit'])?$options['limit']:20); - $offset = $listRows*((int)$page-1); - $options['limit'] = $offset.','.$listRows; - } - $sql = $this->parseSql($this->selectSql,$options); - $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); - return $sql; - } - - /** - * 替换SQL语句中表达式 - * @access public - * @param array $options 表达式 - * @return string - */ - public function parseSql($sql,$options=[]){ - $sql = str_replace( - ['%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%COMMENT%'], - [ - $this->parseTable($options['table']), - $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), - $this->parseField(!empty($options['field'])?$options['field']:'*'), - $this->parseJoin(!empty($options['join'])?$options['join']:''), - $this->parseWhere(!empty($options['where'])?$options['where']:''), - $this->parseGroup(!empty($options['group'])?$options['group']:''), - $this->parseHaving(!empty($options['having'])?$options['having']:''), - $this->parseOrder(!empty($options['order'])?$options['order']:''), - $this->parseLimit(!empty($options['limit'])?$options['limit']:''), - $this->parseUnion(!empty($options['union'])?$options['union']:''), - $this->parseComment(!empty($options['comment'])?$options['comment']:'') - ],$sql); - return $sql; - } - - /** - * 获取最近一次查询的sql语句 - * @param string $model 模型名 - * @access public - * @return string - */ - public function getLastSql($model='') { - return $model?$this->modelSql[$model]:$this->queryStr; - } - - /** - * 获取最近插入的ID - * @access public - * @return string - */ - public function getLastInsID() { - return $this->lastInsID; - } - - /** - * 获取最近的错误信息 - * @access public - * @return string - */ - public function getError() { - return $this->error; - } - - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL字符串 - * @return string - */ - public function escapeString($str) { - return addslashes($str); - } - - /** - * 设置当前操作模型 - * @access public - * @param string $model 模型名 - * @return void - */ - public function setModel($model){ - $this->model = $model; - } - - /** - * 析构方法 - * @access public - */ - public function __destruct() { - // 释放查询 - if ($this->queryID){ - $this->free(); - } - // 关闭连接 - $this->close(); - } - - // 关闭数据库 由驱动类定义 - public function close(){} } \ No newline at end of file diff --git a/Think/Db/Driver.php b/Think/Db/Driver.php new file mode 100644 index 00000000..63212cbc --- /dev/null +++ b/Think/Db/Driver.php @@ -0,0 +1,943 @@ + +// +---------------------------------------------------------------------- +// $Id$ +namespace Think\Db; +use Think\Config; +use Think\Debug; +use Think\Log; +use PDO; +class Driver { + // PDO操作实例 + protected $PDOStatement = null; + // 当前操作所属的模型名 + protected $model = '_think_'; + // 当前SQL指令 + protected $queryStr = ''; + protected $modelSql = []; + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 数据库连接ID 支持多个连接 + protected $linkID = []; + // 当前连接ID + protected $_linkID = null; + // 当前查询ID + protected $queryID = null; + // 数据库连接参数配置 + protected $config = []; + // 数据库表达式 + protected $comparison = ['eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN']; + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%'; + protected $queryTimes = 0; + protected $executeTimes = 0; + // PDO连接参数 + protected $options = [ + PDO::ATTR_CASE => PDO::CASE_LOWER, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, + PDO::ATTR_STRINGIFY_FETCHES => false, + ]; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = []; + } + $this->config['params'] = $this->options+$this->config['params']; + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + try{ + if(empty($config['dsn'])) { + $config['dsn'] = $config['dbms'].':dbname='.$config['database'].';host='.$config['hostname']; + if(!empty($config['hostport'])) { + $config['dsn'] .= ';port='.$config['hostport']; + }elseif(!empty($config['socket'])){ + $config['dsn'] .= ';unix_socket='.$config['socket']; + } + } + $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']); + }catch (\PDOException $e) { + throw_exception($e->getMessage()); + } + if(!empty($config['charset'])) { + $this->linkID[$linkNum]->exec('SET NAMES '.$config['charset']); + } + // 注销数据库连接配置信息 + if(1 != $config['deploy']) $this->config = []; + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->PDOStatement = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str,$bind=[]) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + $this->queryTimes++; + // 记录开始执行时间 + Debug::remark('queryStartTime','time'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) + throw_exception($this->error()); + $result = $this->PDOStatement->execute($bind); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + return $this->getResult(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str,$bind=[]) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + $this->executeTimes++; + // 记录开始执行时间 + Debug::remark('queryStartTime','time'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) { + throw_exception($this->error()); + } + $result = $this->PDOStatement->execute($bind); + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = $this->PDOStatement->rowCount(); + if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) { + $this->lastInsID = $this->getLastInsertId(); + } + return $this->numRows; + } + } + + /** + * 获取最后插入id + * @access public + * @return integer + */ + public function getLastInsertId() { + return $this->_linkID->lastInsertId(); + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->_linkID->beginTransaction(); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = $this->_linkID->commit(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = $this->_linkID->rollback(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getResult() { + //返回数据集 + $result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC); + $this->numRows = count( $result ); + return $result; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + if($this->PDOStatement) { + $error = $this->PDOStatement->errorInfo(); + $this->error = $error[2]; + }else{ + $this->error = ''; + } + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + Log::record($this->error,'ERR'); + return $this->error; + } + + /** + * 设置锁机制 + * @access protected + * @return string + */ + protected function parseLock($lock=false) { + return $lock? ' FOR UPDATE ' : ''; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) // 过滤非标量数据 + $set[] = $this->parseKey($key).'='.$value; + } + return ' SET '.implode(',',$set); + } + + /** + * 字段名分析 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + return $key; + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = '\''.$this->escapeString($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escapeString($value[1]); + }elseif(is_array($value)) { + $value = array_map([$this, 'parseValue'],$value); + }elseif(is_bool($value)){ + $value = $value ? '1' : '0'; + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return string + */ + protected function parseField($fields) { + if(is_string($fields) && strpos($fields,',')) { + $fields = explode(',',$fields); + } + if(is_array($fields)) { + // 完善数组方式传字段名的支持 + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = []; + foreach ($fields as $key=>$field){ + if(!is_numeric($key)) + $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); + else + $array[] = $this->parseKey($field); + } + $fieldsStr = implode(',', $array); + }elseif(is_string($fields) && !empty($fields)) { + $fieldsStr = $this->parseKey($fields); + }else{ + $fieldsStr = '*'; + } + //TODO 如果是查询全部字段,并且是join的方式,那么就把要查的表加个别名,以免字段被覆盖 + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param mixed $table + * @return string + */ + protected function parseTable($tables) { + if(is_array($tables)) {// 支持别名定义 + $array = []; + foreach ($tables as $table=>$alias){ + if(!is_numeric($table)) + $array[] = $this->parseKey($table).' '.$this->parseKey($alias); + else + $array[] = $this->parseKey($table); + } + $tables = $array; + }elseif(is_string($tables)){ + $tables = explode(',',$tables); + array_walk($tables, [&$this, 'parseKey']); + } + return implode(',',$tables); + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return string + */ + protected function parseWhere($where) { + $whereStr = ''; + if(is_string($where)) { + // 直接使用字符串条件 + $whereStr = $where; + }else{ // 使用数组表达式 + $operate = isset($where['_logic'])?strtoupper($where['_logic']):''; + if(in_array($operate,['AND','OR','XOR'])){ + // 定义逻辑运算规则 例如 OR XOR AND NOT + $operate = ' '.$operate.' '; + unset($where['_logic']); + }else{ + // 默认进行 AND 运算 + $operate = ' AND '; + } + foreach ($where as $key=>$val){ + $whereStr .= '( '; + if(0===strpos($key,'_')) { + // 解析特殊条件表达式 + $whereStr .= $this->parseThinkWhere($key,$val); + }else{ + // 查询字段的安全过滤 + if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){ + throw_exception(L('_EXPRESS_ERROR_').':'.$key); + } + // 多条件支持 + $multi = is_array($val) && isset($val['_multi']); + $key = trim($key); + if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段 + $array = explode('|',$key); + $str = []; + foreach ($array as $m=>$k){ + $v = $multi?$val[$m]:$val; + $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; + } + $whereStr .= implode(' OR ',$str); + }elseif(strpos($key,'&')){ + $array = explode('&',$key); + $str = []; + foreach ($array as $m=>$k){ + $v = $multi?$val[$m]:$val; + $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; + } + $whereStr .= implode(' AND ',$str); + }else{ + $whereStr .= $this->parseWhereItem($this->parseKey($key),$val); + } + } + $whereStr .= ' )'.$operate; + } + $whereStr = substr($whereStr,0,-strlen($operate)); + } + return empty($whereStr)?'':' WHERE '.$whereStr; + } + + // where子单元分析 + protected function parseWhereItem($key,$val) { + $whereStr = ''; + if(is_array($val)) { + if(is_string($val[0])) { + if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算 + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找 + if(is_array($val[1])) { + $likeLogic = isset($val[2])?strtoupper($val[2]):'OR'; + if(in_array($likeLogic,['AND','OR','XOR'])){ + $likeStr = $this->comparison[strtolower($val[0])]; + $like = []; + foreach ($val[1] as $item){ + $like[] = $key.' '.$likeStr.' '.$this->parseValue($item); + } + $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')'; + } + }else{ + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + } + }elseif('exp'==strtolower($val[0])){ // 使用表达式 + $whereStr .= ' ('.$key.' '.$val[1].') '; + }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 + if(isset($val[2]) && 'exp'==$val[2]) { + $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1]; + }else{ + if(is_string($val[1])) { + $val[1] = explode(',',$val[1]); + } + $zone = implode(',',$this->parseValue($val[1])); + $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; + } + }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $whereStr .= ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )'; + }else{ + throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); + } + }else { + $count = count($val); + $rule = isset($val[$count-1])?strtoupper($val[$count-1]):''; + if(in_array($rule,['AND','OR','XOR'])) { + $count = $count -1; + }else{ + $rule = 'AND'; + } + for($i=0;$i<$count;$i++) { + $data = is_array($val[$i])?$val[$i][1]:$val[$i]; + if('exp'==strtolower($val[$i][0])) { + $whereStr .= '('.$key.' '.$data.') '.$rule.' '; + }else{ + $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; + $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; + } + } + $whereStr = substr($whereStr,0,-4); + } + }else { + //对字符串类型字段采用模糊匹配 + if($this->conf['db_like_fields'] && preg_match('/('.$this->conf['db_like_fields'].')/i',$key)) { + $val = '%'.$val.'%'; + $whereStr .= $key.' LIKE '.$this->parseValue($val); + }else { + $whereStr .= $key.' = '.$this->parseValue($val); + } + } + return $whereStr; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $whereStr = ''; + switch($key) { + case '_string': + // 字符串模式查询条件 + $whereStr = $val; + break; + case '_complex': + // 复合查询条件 + $whereStr = substr($this->parseWhere($val),6); + break; + case '_query': + // 字符串模式查询条件 + parse_str($val,$where); + if(isset($where['_logic'])) { + $op = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + $op = ' AND '; + } + $array = []; + foreach ($where as $field=>$data) + $array[] = $this->parseKey($field).' = '.$this->parseValue($data); + $whereStr = implode($op,$array); + break; + } + return $whereStr; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + return !empty($limit)? ' LIMIT '.$limit.' ':''; + } + + /** + * join分析 + * @access protected + * @param mixed $join + * @return string + */ + protected function parseJoin($join) { + $joinStr = ''; + if(!empty($join)) { + if(is_array($join)) { + foreach ($join as $key=>$_join){ + if(false !== stripos($_join,'JOIN')) + $joinStr .= ' '.$_join; + else + $joinStr .= ' LEFT JOIN ' .$_join; + } + }else{ + $joinStr .= ' LEFT JOIN ' .$join; + } + } + //将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀和后缀 + $joinStr = preg_replace("/__([A-Z_-]+)__/esU",Config::get('db_prefix').".strtolower('$1')",$joinStr); + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + if(is_array($order)) { + $array = []; + foreach ($order as $key=>$val){ + if(is_numeric($key)) { + $array[] = $this->parseKey($val); + }else{ + $array[] = $this->parseKey($key).' '.$val; + } + } + $order = implode(',',$array); + } + return !empty($order)? ' ORDER BY '.$order:''; + } + + /** + * group分析 + * @access protected + * @param mixed $group + * @return string + */ + protected function parseGroup($group) { + return !empty($group)? ' GROUP BY '.$group:''; + } + + /** + * having分析 + * @access protected + * @param string $having + * @return string + */ + protected function parseHaving($having) { + return !empty($having)? ' HAVING '.$having:''; + } + + /** + * comment分析 + * @access protected + * @param string $comment + * @return string + */ + protected function parseComment($comment) { + return !empty($comment)? ' /* '.$comment.' */':''; + } + + /** + * distinct分析 + * @access protected + * @param mixed $distinct + * @return string + */ + protected function parseDistinct($distinct) { + return !empty($distinct)? ' DISTINCT ' :''; + } + + /** + * union分析 + * @access protected + * @param mixed $union + * @return string + */ + protected function parseUnion($union) { + if(empty($union)) return ''; + if(isset($union['_all'])) { + $str = 'UNION ALL '; + unset($union['_all']); + }else{ + $str = 'UNION '; + } + foreach ($union as $u){ + $sql[] = $str.(is_array($u)?$this->buildSelectSql($u):$u); + } + return implode(' ',$sql); + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insert($data,$options=[],$replace=false) { + $values = $fields = []; + $this->model = $options['model']; + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + $sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,!empty($options['bind'])?$options['bind']:[]); + } + + /** + * 通过Select方式插入记录 + * @access public + * @param string $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @param array $option 查询数据参数 + * @return false | integer + */ + public function selectInsert($fields,$table,$options=[]) { + $this->model = $options['model']; + if(is_string($fields)) $fields = explode(',',$fields); + array_walk($fields, [$this, 'parseKey']); + $sql = 'INSERT INTO '.$this->parseTable($table).' ('.implode(',', $fields).') '; + $sql .= $this->buildSelectSql($options); + return $this->execute($sql); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $this->model = $options['model']; + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseOrder(!empty($options['order'])?$options['order']:'') + .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,!empty($options['bind'])?$options['bind']:[]); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=[]) { + $this->model = $options['model']; + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseOrder(!empty($options['order'])?$options['order']:'') + .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,!empty($options['bind'])?$options['bind']:[]); + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return mixed + */ + public function select($options=[]) { + $this->model = $options['model']; + $sql = $this->buildSelectSql($options); + $cache = isset($options['cache'])?$options['cache']:false; + if($cache) { // 查询缓存检测 + $key = is_string($cache['key'])?$cache['key']:md5($sql); + $value = S($key,'',$cache); + if(false !== $value) { + return $value; + } + } + $result = $this->query($sql,!empty($options['bind'])?$options['bind']:[]); + if($cache && false !== $result ) { // 查询缓存写入 + S($key,$result,$cache); + } + return $result; + } + + /** + * 生成查询SQL + * @access public + * @param array $options 表达式 + * @return string + */ + public function buildSelectSql($options=[]) { + if(isset($options['page'])) { + // 根据页数计算limit + if(strpos($options['page'],',')) { + list($page,$listRows) = explode(',',$options['page']); + }else{ + $page = $options['page']; + } + $page = $page?$page:1; + $listRows= isset($listRows)?$listRows:(is_numeric($options['limit'])?$options['limit']:20); + $offset = $listRows*((int)$page-1); + $options['limit'] = $offset.','.$listRows; + } + $sql = $this->parseSql($this->selectSql,$options); + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + return $sql; + } + + /** + * 替换SQL语句中表达式 + * @access public + * @param array $options 表达式 + * @return string + */ + public function parseSql($sql,$options=[]){ + $sql = str_replace( + ['%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%COMMENT%'], + [ + $this->parseTable($options['table']), + $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), + $this->parseField(!empty($options['field'])?$options['field']:'*'), + $this->parseJoin(!empty($options['join'])?$options['join']:''), + $this->parseWhere(!empty($options['where'])?$options['where']:''), + $this->parseGroup(!empty($options['group'])?$options['group']:''), + $this->parseHaving(!empty($options['having'])?$options['having']:''), + $this->parseOrder(!empty($options['order'])?$options['order']:''), + $this->parseLimit(!empty($options['limit'])?$options['limit']:''), + $this->parseUnion(!empty($options['union'])?$options['union']:''), + $this->parseComment(!empty($options['comment'])?$options['comment']:'') + ],$sql); + return $sql; + } + + /** + * 获取最近一次查询的sql语句 + * @param string $model 模型名 + * @access public + * @return string + */ + public function getLastSql($model='') { + return $model?$this->modelSql[$model]:$this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->lastInsID; + } + + /** + * 获取最近的错误信息 + * @access public + * @return string + */ + public function getError() { + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escapeString($str) { + return addslashes($str); + } + + /** + * 设置当前操作模型 + * @access public + * @param string $model 模型名 + * @return void + */ + public function setModel($model){ + $this->model = $model; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + $this->modelSql[$this->model] = $this->queryStr; + $this->model = '_think_'; + // 记录操作结束时间 + Debug::remark('queryEndTime','time'); + Log::record($this->queryStr.' [ RunTime:'.Debug::getUseTime('queryStartTime','queryEndTime').'s ]','SQL'); + } + + /** + * 初始化数据库连接 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function initConnect($master=true) { + if(1 == $this->config['deploy']) + // 采用分布式数据库 + $this->_linkID = $this->multiConnect($master); + else + // 默认单数据库 + if ( !$this->_linkID ) $this->_linkID = $this->connect(); + } + + /** + * 连接分布式服务器 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function multiConnect($master=false) { + static $_config = []; + if(empty($_config)) { + // 缓存分布式数据库配置解析 + foreach ($this->config as $key=>$val){ + $_config[$key] = explode(',',$val); + } + } + // 数据库读写是否分离 + if(Config::get('db_rw_separate')){ + // 主从式采用读写分离 + if($master) + // 主服务器写入 + $r = floor(mt_rand(0,Config::get('db_master_num')-1)); + else{ + if(is_numeric(Config::get('db_slave_no'))) {// 指定服务器读 + $r = Config::get('db_slave_no'); + }else{ + // 读操作连接从服务器 + $r = floor(mt_rand(Config::get('db_master_num'),count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + } + }else{ + // 读写操作不区分服务器 + $r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + $db_config = [ + 'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], + 'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], + 'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], + 'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], + 'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], + 'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], + 'params' => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0], + ]; + return $this->connect($db_config,$r); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 释放查询 + if ($this->queryID){ + $this->free(); + } + // 关闭连接 + $this->close(); + } +} \ No newline at end of file diff --git a/Think/Db/Driver/Ibase.php b/Think/Db/Driver/Ibase.php deleted file mode 100644 index 2c0acf14..00000000 --- a/Think/Db/Driver/Ibase.php +++ /dev/null @@ -1,339 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace Think\Db\Driver; -use Think\Db; -/** - * Firebird数据库驱动 - * @category Extend - * @package Extend - * @subpackage Driver.Db - * @author 剑雷 - */ -class Ibase extends Db{ - - protected $selectSql = 'SELECT %LIMIT% %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%'; - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config='') { - if ( !extension_loaded('interbase') ) { - throw_exception(L('_NOT_SUPPERT_').':Interbase or Firebird'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = array(); - } - } - } - - /** - * 连接数据库方法 - * @access public - * @throws ThinkExecption - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; - $conn = $pconnect ? 'ibase_pconnect':'ibase_connect'; - // 处理不带端口号的socket连接情况 - $host = $config['hostname'].($config['hostport']?"/{$config['hostport']}":''); - $this->linkID[$linkNum] = $conn($host.':'.$config['database'], $config['username'], $config['password'],C('DB_CHARSET'),0,3); - if ( !$this->linkID[$linkNum]) { - throw_exception(ibase_errmsg()); - } - // 标记连接成功 - $this->connected = true; - // 注销数据库连接配置信息 - if(1 != Config::get('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - ibase_free_result($this->queryID); - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = ibase_query($this->_linkID, $str); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_write',1); - // 记录开始执行时间 - G('queryStartTime'); - $result = ibase_query($this->_linkID, $str) ; - $this->debug(); - if ( false === $result) { - $this->error(); - return false; - } else { - $this->numRows = ibase_affected_rows($this->_linkID); - $this->lastInsID =0; - return $this->numRows; - } - } - - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - ibase_trans( IBASE_DEFAULT, $this->_linkID); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = ibase_commit($this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result =ibase_rollback($this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * BLOB字段解密函数 Firebird特有 - * @access public - * @param $blob 待解密的BLOB - * @return 二进制数据 - */ - public function BlobDecode($blob) { - $maxblobsize = 262144; - $blob_data = ibase_blob_info($this->_linkID, $blob ); - $blobid = ibase_blob_open($this->_linkID, $blob ); - if( $blob_data[0] > $maxblobsize ) { - $realblob = ibase_blob_get($blobid, $maxblobsize); - while($string = ibase_blob_get($blobid, 8192)){ - $realblob .= $string; - } - } else { - $realblob = ibase_blob_get($blobid, $blob_data[0]); - } - ibase_blob_close( $blobid ); - return( $realblob ); - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = array(); - while ( $row = ibase_fetch_assoc($this->queryID)) { - $result[] = $row; - } - //剑雷 2007.12.30 自动解密BLOB字段 - //取BLOB字段清单 - $bloblist = array(); - $fieldCount = ibase_num_fields($this->queryID); - for ($i = 0; $i < $fieldCount; $i++) { - $col_info = ibase_field_info($this->queryID, $i); - if ($col_info['type']=='BLOB') { - $bloblist[]=trim($col_info['name']); - } - } - //如果有BLOB字段,就进行解密处理 - if (!empty($bloblist)) { - $i=0; - foreach ($result as $row) { - foreach($bloblist as $field) { - if (!empty($row[$field])) $result[$i][$field]=$this->BlobDecode($row[$field]); - } - $i++; - } - } - return $result; - } - - /** - * 取得数据表的字段信息 - * @access public - */ - public function getFields($tableName) { - $result = $this->query('SELECT RDB$FIELD_NAME AS FIELD, RDB$DEFAULT_VALUE AS DEFAULT1, RDB$NULL_FLAG AS NULL1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME=UPPER(\''.$tableName.'\') ORDER By RDB$FIELD_POSITION'); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $info[trim($val['FIELD'])] = array( - 'name' => trim($val['FIELD']), - 'type' => '', - 'notnull' => (bool) ($val['NULL1'] ==1), // 1表示不为Null - 'default' => $val['DEFAULT1'], - 'primary' => false, - 'autoinc' => false, - ); - } - } - //剑雷 取表字段类型 - $sql='select first 1 * from '. $tableName; - $rs_temp = ibase_query ($this->_linkID, $sql); - $fieldCount = ibase_num_fields($rs_temp); - - for ($i = 0; $i < $fieldCount; $i++) - { - $col_info = ibase_field_info($rs_temp, $i); - $info[trim($col_info['name'])]['type']=$col_info['type']; - } - ibase_free_result ($rs_temp); - - //剑雷 取表的主键 - $sql='select b.rdb$field_name as FIELD_NAME from rdb$relation_constraints a join rdb$index_segments b -on a.rdb$index_name=b.rdb$index_name -where a.rdb$constraint_type=\'PRIMARY KEY\' and a.rdb$relation_name=UPPER(\''.$tableName.'\')'; - $rs_temp = ibase_query ($this->_linkID, $sql); - while ($row=ibase_fetch_object($rs_temp)) { - $info[trim($row->FIELD_NAME)]['primary']=True; - } - ibase_free_result ($rs_temp); - - return $info; - } - - /** - * 取得数据库的表信息 - * @access public - */ - public function getTables($dbName='') { - $sql='SELECT DISTINCT RDB$RELATION_NAME FROM RDB$RELATION_FIELDS WHERE RDB$SYSTEM_FLAG=0'; - $result = $this->query($sql); - $info = array(); - foreach ($result as $key => $val) { - $info[$key] = trim(current($val)); - } - return $info; - } - - /** - * 关闭数据库 - * @access public - */ - public function close() { - if ($this->_linkID){ - ibase_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error() { - $this->error = ibase_errmsg(); - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - ThinkLog::record($this->error,'ERR'); - return $this->error; - } - - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL指令 - * @return string - */ - public function escapeString($str) { - return str_replace("'", "''", $str); - } - - /** - * limit - * @access public - * @param $limit limit表达式 - * @return string - */ - public function parseLimit($limit) { - $limitStr = ''; - if(!empty($limit)) { - $limit = explode(',',$limit); - if(count($limit)>1) { - $limitStr = ' FIRST '.($limit[1]-$limit[0]).' SKIP '.$limit[0].' '; - }else{ - $limitStr = ' FIRST '.$limit[0].' '; - } - } - return $limitStr; - } -} \ No newline at end of file diff --git a/Think/Db/Driver/Mongo.php b/Think/Db/Driver/Mongo.php deleted file mode 100644 index b0d9ea31..00000000 --- a/Think/Db/Driver/Mongo.php +++ /dev/null @@ -1,752 +0,0 @@ - -// +---------------------------------------------------------------------- - -namespace Think\Db\Driver; -use Think\Db; -/** - * Mongo数据库驱动 必须配合MongoModel使用 - * @category Extend - * @package Extend - * @subpackage Driver.Db - * @author liu21st - */ -class Mongo extends Db{ - - protected $_mongo = null; // MongoDb Object - protected $_collection = null; // MongoCollection Object - protected $_dbName = ''; // dbName - protected $_collectionName = ''; // collectionName - protected $_cursor = null; // MongoCursor Object - protected $comparison = array('neq'=>'ne','ne'=>'ne','gt'=>'gt','egt'=>'gte','gte'=>'gte','lt'=>'lt','elt'=>'lte','lte'=>'lte','in'=>'in','not in'=>'nin','nin'=>'nin'); - - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config=''){ - if ( !class_exists('mongo') ) { - throw_exception(L('_NOT_SUPPERT_').':mongo'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = array(); - } - } - } - - /** - * 连接数据库方法 - * @access public - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $host = 'mongodb://'.($config['username']?"{$config['username']}":'').($config['password']?":{$config['password']}@":'').$config['hostname'].($config['hostport']?":{$config['hostport']}":'').'/'.($config['database']?"{$config['database']}":''); - try{ - $this->linkID[$linkNum] = new mongo( $host,$config['params']); - }catch (MongoConnectionException $e){ - throw_exception($e->getmessage()); - } - // 标记连接成功 - $this->connected = true; - // 注销数据库连接配置信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 切换当前操作的Db和Collection - * @access public - * @param string $collection collection - * @param string $db db - * @param boolean $master 是否主服务器 - * @return void - */ - public function switchCollection($collection,$db='',$master=true){ - // 当前没有连接 则首先进行数据库连接 - if ( !$this->_linkID ) $this->initConnect($master); - try{ - if(!empty($db)) { // 传人Db则切换数据库 - // 当前MongoDb对象 - $this->_dbName = $db; - $this->_mongo = $this->_linkID->selectDb($db); - } - // 当前MongoCollection对象 - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.getCollection('.$collection.')'; - } - if($this->_collectionName != $collection) { - N('db_read',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->_collection = $this->_mongo->selectCollection($collection); - $this->debug(); - $this->_collectionName = $collection; // 记录当前Collection名称 - } - }catch (MongoException $e){ - throw_exception($e->getMessage()); - } - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - $this->_cursor = null; - } - - /** - * 执行命令 - * @access public - * @param array $command 指令 - * @return array - */ - public function command($command=array()) { - N('db_write',1); - $this->queryStr = 'command:'.json_encode($command); - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_mongo->command($command); - $this->debug(); - if(!$result['ok']) { - throw_exception($result['errmsg']); - } - return $result; - } - - /** - * 执行语句 - * @access public - * @param string $code sql指令 - * @param array $args 参数 - * @return mixed - */ - public function execute($code,$args=array()) { - N('db_write',1); - $this->queryStr = 'execute:'.$code; - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_mongo->execute($code,$args); - $this->debug(); - if($result['ok']) { - return $result['retval']; - }else{ - throw_exception($result['errmsg']); - } - } - - /** - * 关闭数据库 - * @access public - */ - public function close() { - if($this->_linkID) { - $this->_linkID->close(); - $this->_linkID = null; - $this->_mongo = null; - $this->_collection = null; - $this->_cursor = null; - } - } - - /** - * 数据库错误信息 - * @access public - * @return string - */ - public function error() { - $this->error = $this->_mongo->lastError(); - ThinkLog::record($this->error,'ERR'); - return $this->error; - } - - /** - * 插入记录 - * @access public - * @param mixed $data 数据 - * @param array $options 参数表达式 - * @param boolean $replace 是否replace - * @return false | integer - */ - public function insert($data,$options=array(),$replace=false) { - if(isset($options['table'])) { - $this->switchCollection($options['table']); - } - $this->model = $options['model']; - N('db_write',1); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.insert('; - $this->queryStr .= $data?json_encode($data):'{}'; - $this->queryStr .= ')'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $replace? $this->_collection->save($data,true): $this->_collection->insert($data,true); - $this->debug(); - if($result) { - $_id = $data['_id']; - if(is_object($_id)) { - $_id = $_id->__toString(); - } - $this->lastInsID = $_id; - } - return $result; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - /** - * 插入多条记录 - * @access public - * @param array $dataList 数据 - * @param array $options 参数表达式 - * @return bool - */ - public function insertAll($dataList,$options=array()) { - if(isset($options['table'])) { - $this->switchCollection($options['table']); - } - $this->model = $options['model']; - N('db_write',1); - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_collection->batchInsert($dataList); - $this->debug(); - return $result; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - /** - * 生成下一条记录ID 用于自增非MongoId主键 - * @access public - * @param string $pk 主键名 - * @return integer - */ - public function mongo_next_id($pk) { - N('db_read',1); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find({},{'.$pk.':1}).sort({'.$pk.':-1}).limit(1)'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_collection->find(array(),array($pk=>1))->sort(array($pk=>-1))->limit(1); - $this->debug(); - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - $data = $result->getNext(); - return isset($data[$pk])?$data[$pk]+1:1; - } - - /** - * 更新记录 - * @access public - * @param mixed $data 数据 - * @param array $options 表达式 - * @return bool - */ - public function update($data,$options) { - if(isset($options['table'])) { - $this->switchCollection($options['table']); - } - $this->model = $options['model']; - N('db_write',1); - $query = $this->parseWhere($options['where']); - $set = $this->parseSet($data); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.update('; - $this->queryStr .= $query?json_encode($query):'{}'; - $this->queryStr .= ','.json_encode($set).')'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_collection->update($query,$set,array("multiple" => true)); - $this->debug(); - return $result; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - /** - * 删除记录 - * @access public - * @param array $options 表达式 - * @return false | integer - */ - public function delete($options=array()) { - if(isset($options['table'])) { - $this->switchCollection($options['table']); - } - $query = $this->parseWhere($options['where']); - $this->model = $options['model']; - N('db_write',1); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove('.json_encode($query).')'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_collection->remove($query); - $this->debug(); - return $result; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - /** - * 清空记录 - * @access public - * @param array $options 表达式 - * @return false | integer - */ - public function clear($options=array()){ - if(isset($options['table'])) { - $this->switchCollection($options['table']); - } - $this->model = $options['model']; - N('db_write',1); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove({})'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_collection->drop(); - $this->debug(); - return $result; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - /** - * 查找记录 - * @access public - * @param array $options 表达式 - * @return iterator - */ - public function select($options=array()) { - if(isset($options['table'])) { - $this->switchCollection($options['table'],'',false); - } - $cache = isset($options['cache'])?$options['cache']:false; - if($cache) { // 查询缓存检测 - $key = is_string($cache['key'])?$cache['key']:md5(serialize($options)); - $value = S($key,'','',$cache['type']); - if(false !== $value) { - return $value; - } - } - $this->model = $options['model']; - N('db_query',1); - $query = $this->parseWhere($options['where']); - $field = $this->parseField($options['field']); - try{ - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find('; - $this->queryStr .= $query? json_encode($query):'{}'; - $this->queryStr .= $field? ','.json_encode($field):''; - $this->queryStr .= ')'; - } - // 记录开始执行时间 - G('queryStartTime'); - $_cursor = $this->_collection->find($query,$field); - if($options['order']) { - $order = $this->parseOrder($options['order']); - if(C('DB_SQL_LOG')) { - $this->queryStr .= '.sort('.json_encode($order).')'; - } - $_cursor = $_cursor->sort($order); - } - if(isset($options['page'])) { // 根据页数计算limit - if(strpos($options['page'],',')) { - list($page,$length) = explode(',',$options['page']); - }else{ - $page = $options['page']; - } - $page = $page?$page:1; - $length = isset($length)?$length:(is_numeric($options['limit'])?$options['limit']:20); - $offset = $length*((int)$page-1); - $options['limit'] = $offset.','.$length; - } - if(isset($options['limit'])) { - list($offset,$length) = $this->parseLimit($options['limit']); - if(!empty($offset)) { - if(C('DB_SQL_LOG')) { - $this->queryStr .= '.skip('.intval($offset).')'; - } - $_cursor = $_cursor->skip(intval($offset)); - } - if(C('DB_SQL_LOG')) { - $this->queryStr .= '.limit('.intval($length).')'; - } - $_cursor = $_cursor->limit(intval($length)); - } - $this->debug(); - $this->_cursor = $_cursor; - $resultSet = iterator_to_array($_cursor); - if($cache && $resultSet ) { // 查询缓存写入 - S($key,$resultSet,$cache['expire'],$cache['type']); - } - return $resultSet; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - /** - * 查找某个记录 - * @access public - * @param array $options 表达式 - * @return array - */ - public function find($options=array()){ - if(isset($options['table'])) { - $this->switchCollection($options['table'],'',false); - } - $cache = isset($options['cache'])?$options['cache']:false; - if($cache) { // 查询缓存检测 - $key = is_string($cache['key'])?$cache['key']:md5(serialize($options)); - $value = S($key,'','',$cache['type']); - if(false !== $value) { - return $value; - } - } - $this->model = $options['model']; - N('db_query',1); - $query = $this->parseWhere($options['where']); - $fields = $this->parseField($options['field']); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne('; - $this->queryStr .= $query?json_encode($query):'{}'; - $this->queryStr .= $fields?','.json_encode($fields):''; - $this->queryStr .= ')'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_collection->findOne($query,$fields); - $this->debug(); - if($cache && $result ) { // 查询缓存写入 - S($key,$result,$cache['expire'],$cache['type']); - } - return $result; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - /** - * 统计记录数 - * @access public - * @param array $options 表达式 - * @return iterator - */ - public function count($options=array()){ - if(isset($options['table'])) { - $this->switchCollection($options['table'],'',false); - } - $this->model = $options['model']; - N('db_query',1); - $query = $this->parseWhere($options['where']); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName; - $this->queryStr .= $query?'.find('.json_encode($query).')':''; - $this->queryStr .= '.count()'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $count = $this->_collection->count($query); - $this->debug(); - return $count; - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - } - - public function group($keys,$initial,$reduce,$options=array()){ - $this->_collection->group($keys,$initial,$reduce,$options); - } - - /** - * 取得数据表的字段信息 - * @access public - * @return array - */ - public function getFields($collection=''){ - if(!empty($collection) && $collection != $this->_collectionName) { - $this->switchCollection($collection,'',false); - } - N('db_query',1); - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne()'; - } - try{ - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_collection->findOne(); - $this->debug(); - } catch (MongoCursorException $e) { - throw_exception($e->getMessage()); - } - if($result) { // 存在数据则分析字段 - $info = array(); - foreach ($result as $key=>$val){ - $info[$key] = array( - 'name'=>$key, - 'type'=>getType($val), - ); - } - return $info; - } - // 暂时没有数据 返回false - return false; - } - - /** - * 取得当前数据库的collection信息 - * @access public - */ - public function getTables(){ - if(C('DB_SQL_LOG')) { - $this->queryStr = $this->_dbName.'.getCollenctionNames()'; - } - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $list = $this->_mongo->listCollections(); - $this->debug(); - $info = array(); - foreach ($list as $collection){ - $info[] = $collection->getName(); - } - return $info; - } - - /** - * set分析 - * @access protected - * @param array $data - * @return string - */ - protected function parseSet($data) { - $result = array(); - foreach ($data as $key=>$val){ - if(is_array($val)) { - switch($val[0]) { - case 'inc': - $result['$inc'][$key] = (int)$val[1]; - break; - case 'set': - case 'unset': - case 'push': - case 'pushall': - case 'addtoset': - case 'pop': - case 'pull': - case 'pullall': - $result['$'.$val[0]][$key] = $val[1]; - break; - default: - $result['$set'][$key] = $val; - } - }else{ - $result['$set'][$key] = $val; - } - } - return $result; - } - - /** - * order分析 - * @access protected - * @param mixed $order - * @return array - */ - protected function parseOrder($order) { - if(is_string($order)) { - $array = explode(',',$order); - $order = array(); - foreach ($array as $key=>$val){ - $arr = explode(' ',trim($val)); - if(isset($arr[1])) { - $arr[1] = $arr[1]=='asc'?1:-1; - }else{ - $arr[1] = 1; - } - $order[$arr[0]] = $arr[1]; - } - } - return $order; - } - - /** - * limit分析 - * @access protected - * @param mixed $limit - * @return array - */ - protected function parseLimit($limit) { - if(strpos($limit,',')) { - $array = explode(',',$limit); - }else{ - $array = array(0,$limit); - } - return $array; - } - - /** - * field分析 - * @access protected - * @param mixed $fields - * @return array - */ - public function parseField($fields){ - if(empty($fields)) { - $fields = array(); - } - if(is_string($fields)) { - $fields = explode(',',$fields); - } - return $fields; - } - - /** - * where分析 - * @access protected - * @param mixed $where - * @return array - */ - public function parseWhere($where){ - $query = array(); - foreach ($where as $key=>$val){ - if('_id' != $key && 0===strpos($key,'_')) { - // 解析特殊条件表达式 - $query = $this->parseThinkWhere($key,$val); - }else{ - // 查询字段的安全过滤 - if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){ - throw_exception(L('_ERROR_QUERY_').':'.$key); - } - $key = trim($key); - if(strpos($key,'|')) { - $array = explode('|',$key); - $str = array(); - foreach ($array as $k){ - $str[] = $this->parseWhereItem($k,$val); - } - $query['$or'] = $str; - }elseif(strpos($key,'&')){ - $array = explode('&',$key); - $str = array(); - foreach ($array as $k){ - $str[] = $this->parseWhereItem($k,$val); - } - $query = array_merge($query,$str); - }else{ - $str = $this->parseWhereItem($key,$val); - $query = array_merge($query,$str); - } - } - } - return $query; - } - - /** - * 特殊条件分析 - * @access protected - * @param string $key - * @param mixed $val - * @return string - */ - protected function parseThinkWhere($key,$val) { - $query = array(); - switch($key) { - case '_query': // 字符串模式查询条件 - parse_str($val,$query); - if(isset($query['_logic']) && strtolower($query['_logic']) == 'or' ) { - unset($query['_logic']); - $query['$or'] = $query; - } - break; - case '_string':// MongoCode查询 - $query['$where'] = new MongoCode($val); - break; - } - return $query; - } - - /** - * where子单元分析 - * @access protected - * @param string $key - * @param mixed $val - * @return array - */ - protected function parseWhereItem($key,$val) { - $query = array(); - if(is_array($val)) { - if(is_string($val[0])) { - $con = strtolower($val[0]); - if(in_array($con,array('neq','ne','gt','egt','gte','lt','lte','elt'))) { // 比较运算 - $k = '$'.$this->comparison[$con]; - $query[$key] = array($k=>$val[1]); - }elseif('like'== $con){ // 模糊查询 采用正则方式 - $query[$key] = new MongoRegex("/".$val[1]."/"); - }elseif('mod'==$con){ // mod 查询 - $query[$key] = array('$mod'=>$val[1]); - }elseif('regex'==$con){ // 正则查询 - $query[$key] = new MongoRegex($val[1]); - }elseif(in_array($con,array('in','nin','not in'))){ // IN NIN 运算 - $data = is_string($val[1])? explode(',',$val[1]):$val[1]; - $k = '$'.$this->comparison[$con]; - $query[$key] = array($k=>$data); - }elseif('all'==$con){ // 满足所有指定条件 - $data = is_string($val[1])? explode(',',$val[1]):$val[1]; - $query[$key] = array('$all'=>$data); - }elseif('between'==$con){ // BETWEEN运算 - $data = is_string($val[1])? explode(',',$val[1]):$val[1]; - $query[$key] = array('$gte'=>$data[0],'$lte'=>$data[1]); - }elseif('not between'==$con){ - $data = is_string($val[1])? explode(',',$val[1]):$val[1]; - $query[$key] = array('$lt'=>$data[0],'$gt'=>$data[1]); - }elseif('exp'==$con){ // 表达式查询 - $query['$where'] = new MongoCode($val[1]); - }elseif('exists'==$con){ // 字段是否存在 - $query[$key] =array('$exists'=>(bool)$val[1]); - }elseif('size'==$con){ // 限制属性大小 - $query[$key] =array('$size'=>intval($val[1])); - }elseif('type'==$con){ // 限制字段类型 1 浮点型 2 字符型 3 对象或者MongoDBRef 5 MongoBinData 7 MongoId 8 布尔型 9 MongoDate 10 NULL 15 MongoCode 16 32位整型 17 MongoTimestamp 18 MongoInt64 如果是数组的话判断元素的类型 - $query[$key] =array('$type'=>intval($val[1])); - }else{ - $query[$key] = $val; - } - return $query; - } - } - $query[$key] = $val; - return $query; - } -} \ No newline at end of file diff --git a/Think/Db/Driver/Mssql.php b/Think/Db/Driver/Mssql.php deleted file mode 100644 index 851e8a3d..00000000 --- a/Think/Db/Driver/Mssql.php +++ /dev/null @@ -1,334 +0,0 @@ - -// +---------------------------------------------------------------------- -namespace Think\Db\Driver; -use Think\Db; -/** - * MSsql数据库驱动 要求sqlserver2005 - * @category Extend - * @package Extend - * @subpackage Driver.Db - * @author liu21st - */ -class Mssql extends Db{ - protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config=''){ - if ( !function_exists('mssql_connect') ) { - throw_exception(L('_NOT_SUPPERT_').':mssql'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = array(); - } - } - } - - /** - * 连接数据库方法 - * @access public - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; - $conn = $pconnect ? 'mssql_pconnect':'mssql_connect'; - // 处理不带端口号的socket连接情况 - $sepr = IS_WIN ? ',' : ':'; - $host = $config['hostname'].($config['hostport']?$sepr."{$config['hostport']}":''); - $this->linkID[$linkNum] = $conn( $host, $config['username'], $config['password']); - if ( !$this->linkID[$linkNum] ) throw_exception("Couldn't connect to SQL Server on $host"); - if ( !empty($config['database']) && !mssql_select_db($config['database'], $this->linkID[$linkNum]) ) { - throw_exception("Couldn't open database '".$config['database']); - } - // 标记连接成功 - $this->connected = true; - //注销数据库安全信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - mssql_free_result($this->queryID); - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = mssql_query($str, $this->_linkID); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = mssql_num_rows($this->queryID); - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_write',1); - // 记录开始执行时间 - G('queryStartTime'); - $result = mssql_query($str, $this->_linkID); - $this->debug(); - if ( false === $result ) { - $this->error(); - return false; - } else { - $this->numRows = mssql_rows_affected($this->_linkID); - $this->lastInsID = $this->mssql_insert_id(); - return $this->numRows; - } - } - - /** - * 用于获取最后插入的ID - * @access public - * @return integer - */ - public function mssql_insert_id() { - $query = "SELECT @@IDENTITY as last_insert_id"; - $result = mssql_query($query, $this->_linkID); - list($last_insert_id) = mssql_fetch_row($result); - mssql_free_result($result); - return $last_insert_id; - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - mssql_query('BEGIN TRAN', $this->_linkID); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = mssql_query('COMMIT TRAN', $this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = mssql_query('ROLLBACK TRAN', $this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = array(); - if($this->numRows >0) { - while($row = mssql_fetch_assoc($this->queryID)) - $result[] = $row; - } - return $result; - } - - /** - * 取得数据表的字段信息 - * @access public - * @return array - */ - public function getFields($tableName) { - $result = $this->query("SELECT column_name, data_type, column_default, is_nullable - FROM information_schema.tables AS t - JOIN information_schema.columns AS c - ON t.table_catalog = c.table_catalog - AND t.table_schema = c.table_schema - AND t.table_name = c.table_name - WHERE t.table_name = '$tableName'"); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $info[$val['column_name']] = array( - 'name' => $val['column_name'], - 'type' => $val['data_type'], - 'notnull' => (bool) ($val['is_nullable'] === ''), // not null is empty, null is yes - 'default' => $val['column_default'], - 'primary' => false, - 'autoinc' => false, - ); - } - } - return $info; - } - - /** - * 取得数据表的字段信息 - * @access public - * @return array - */ - public function getTables($dbName='') { - $result = $this->query("SELECT TABLE_NAME - FROM INFORMATION_SCHEMA.TABLES - WHERE TABLE_TYPE = 'BASE TABLE' - "); - $info = array(); - foreach ($result as $key => $val) { - $info[$key] = current($val); - } - return $info; - } - - /** - * order分析 - * @access protected - * @param mixed $order - * @return string - */ - protected function parseOrder($order) { - return !empty($order)? ' ORDER BY '.$order:' ORDER BY rand()'; - } - - /** - * limit - * @access public - * @return string - */ - public function parseLimit($limit) { - if(empty($limit)) return ''; - $limit = explode(',',$limit); - if(count($limit)>1) - $limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')'; - else - $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"; - return 'WHERE '.$limitStr; - } - - /** - * 更新记录 - * @access public - * @param mixed $data 数据 - * @param array $options 表达式 - * @return false | integer - */ - public function update($data,$options) { - $this->model = $options['model']; - $sql = 'UPDATE ' - .$this->parseTable($options['table']) - .$this->parseSet($data) - .$this->parseWhere(!empty($options['where'])?$options['where']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false) - .$this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql); - } - - /** - * 删除记录 - * @access public - * @param array $options 表达式 - * @return false | integer - */ - public function delete($options=array()) { - $this->model = $options['model']; - $sql = 'DELETE FROM ' - .$this->parseTable($options['table']) - .$this->parseWhere(!empty($options['where'])?$options['where']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false) - .$this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql); - } - - /** - * 关闭数据库 - * @access public - */ - public function close() { - if ($this->_linkID){ - mssql_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error() { - $this->error = mssql_get_last_message(); - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - ThinkLog::record($this->error,'ERR'); - return $this->error; - } -} \ No newline at end of file diff --git a/Think/Db/Driver/Mysql.php b/Think/Db/Driver/Mysql.php index 147c3c57..6a70c0f4 100644 --- a/Think/Db/Driver/Mysql.php +++ b/Think/Db/Driver/Mysql.php @@ -8,210 +8,24 @@ // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - namespace Think\Db\Driver; -use Think\Db; - +use Think\Db\Driver; /** - * Mysql数据库驱动类 - * @category Think - * @package Think + * PDO数据库驱动 + * @category Extend + * @package Extend * @subpackage Driver.Db * @author liu21st */ -class Mysql extends Db{ - - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config=''){ - if ( !extension_loaded('mysql') ) { - throw_exception(L('_NOT_SUPPERT_').':mysql'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = ''; - } - } - } - - /** - * 连接数据库方法 - * @access public - * @throws ThinkExecption - */ - public function connect($config='',$linkNum=0,$force=false) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - // 处理不带端口号的socket连接情况 - $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); - // 是否长连接 - $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; - if($pconnect) { - $this->linkID[$linkNum] = mysql_pconnect( $host, $config['username'], $config['password'],131072); - }else{ - $this->linkID[$linkNum] = mysql_connect( $host, $config['username'], $config['password'],true,131072); - } - if ( !$this->linkID[$linkNum] || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID[$linkNum])) ) { - throw_exception(mysql_error()); - } - $dbVersion = mysql_get_server_info($this->linkID[$linkNum]); - //使用UTF8存取数据库 - mysql_query("SET NAMES '".$this->conf['db_charset']."'", $this->linkID[$linkNum]); - //设置 sql_model - if($dbVersion >'5.0.1'){ - mysql_query("SET sql_mode=''",$this->linkID[$linkNum]); - } - // 标记连接成功 - $this->connected = true; - // 注销数据库连接配置信息 - if(1 != $this->conf['db_deploy_type']) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - mysql_free_result($this->queryID); - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - if(0===stripos($str, 'call')){ // 存储过程查询支持 - $this->close(); - } - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) { $this->free(); } - N('db_query',1); - // 记录开始执行时间 - \Think\Debug::remark('queryStartTime','time'); - $this->queryID = mysql_query($str, $this->_linkID); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = mysql_num_rows($this->queryID); - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer|false - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) { $this->free(); } - N('db_write',1); - // 记录开始执行时间 - \Think\Debug::remark('queryStartTime','time'); - $result = mysql_query($str, $this->_linkID) ; - $this->debug(); - if ( false === $result) { - $this->error(); - return false; - } else { - $this->numRows = mysql_affected_rows($this->_linkID); - $this->lastInsID = mysql_insert_id($this->_linkID); - return $this->numRows; - } - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - mysql_query('START TRANSACTION', $this->_linkID); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = mysql_query('COMMIT', $this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = mysql_query('ROLLBACK', $this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = array(); - if($this->numRows >0) { - while($row = mysql_fetch_assoc($this->queryID)){ - $result[] = $row; - } - mysql_data_seek($this->queryID,0); - } - return $result; - } - +class Mysql extends Driver{ /** * 取得数据表的字段信息 * @access public - * @return array */ public function getFields($tableName) { - $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); + $this->initConnect(true); + $sql = 'SHOW COLUMNS FROM `'.$tableName.'`'; + $result = $this->query($sql); $info = array(); if($result) { foreach ($result as $key => $val) { @@ -231,15 +45,10 @@ class Mysql extends Db{ /** * 取得数据库的表信息 * @access public - * @return array */ public function getTables($dbName='') { - if(!empty($dbName)) { - $sql = 'SHOW TABLES FROM '.$dbName; - }else{ - $sql = 'SHOW TABLES '; - } - $result = $this->query($sql); + $sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES '; + $result = $this->query($sql); $info = array(); foreach ($result as $key => $val) { $info[$key] = current($val); @@ -248,94 +57,7 @@ class Mysql extends Db{ } /** - * 替换记录 - * @access public - * @param mixed $data 数据 - * @param array $options 参数表达式 - * @return false | integer - */ - public function replace($data,$options=array()) { - foreach ($data as $key=>$val){ - $value = $this->parseValue($val); - if(is_scalar($value)) { // 过滤非标量数据 - $values[] = $value; - $fields[] = $this->parseKey($key); - } - } - $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; - return $this->execute($sql); - } - - /** - * 插入记录 - * @access public - * @param mixed $datas 数据 - * @param array $options 参数表达式 - * @param boolean $replace 是否replace - * @return false | integer - */ - public function insertAll($datas,$options=array(),$replace=false) { - if(!is_array($datas[0])) return false; - $fields = array_keys($datas[0]); - array_walk($fields, array($this, 'parseKey')); - $values = array(); - foreach ($datas as $data){ - $value = array(); - foreach ($data as $key=>$val){ - $val = $this->parseValue($val); - if(is_scalar($val)) { // 过滤非标量数据 - $value[] = $val; - } - } - $values[] = '('.implode(',', $value).')'; - } - $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); - return $this->execute($sql); - } - - /** - * 关闭数据库 - * @access public - * @return void - */ - public function close() { - if ($this->_linkID){ - mysql_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error() { - $this->error = mysql_error($this->_linkID); - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - \Think\Log::record($this->error,'ERR'); - return $this->error; - } - - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL字符串 - * @return string - */ - public function escapeString($str) { - if($this->_linkID) { - return mysql_real_escape_string($str,$this->_linkID); - }else{ - return mysql_escape_string($str); - } - } - - /** - * 字段和表名处理添加` + * 字段和表名处理 * @access protected * @param string $key * @return string @@ -345,6 +67,7 @@ class Mysql extends Db{ if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { $key = '`'.$key.'`'; } - return $key; + return $key; } + } \ No newline at end of file diff --git a/Think/Db/Driver/Mysqli.php b/Think/Db/Driver/Mysqli.php deleted file mode 100644 index 407b2dff..00000000 --- a/Think/Db/Driver/Mysqli.php +++ /dev/null @@ -1,345 +0,0 @@ - -// +---------------------------------------------------------------------- -namespace Think\Db\Driver; -use Think\Db; -/** - * Mysqli数据库驱动类 - * @category Think - * @package Think - * @subpackage Driver.Db - * @author liu21st - */ -class Mysqli extends Db{ - - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config=''){ - if ( !extension_loaded('mysqli') ) { - throw_exception(L('_NOT_SUPPERT_').':mysqli'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = ''; - } - } - } - - /** - * 连接数据库方法 - * @access public - * @throws ThinkExecption - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $this->linkID[$linkNum] = new mysqli($config['hostname'],$config['username'],$config['password'],$config['database'],$config['hostport']?intval($config['hostport']):3306); - if (mysqli_connect_errno()) throw_exception(mysqli_connect_error()); - $dbVersion = $this->linkID[$linkNum]->server_version; - - // 设置数据库编码 - $this->linkID[$linkNum]->query("SET NAMES '".C('DB_CHARSET')."'"); - //设置 sql_model - if($dbVersion >'5.0.1'){ - $this->linkID[$linkNum]->query("SET sql_mode=''"); - } - // 标记连接成功 - $this->connected = true; - //注销数据库安全信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - $this->queryID->free_result(); - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = $this->_linkID->query($str); - // 对存储过程改进 - if( $this->_linkID->more_results() ){ - while (($res = $this->_linkID->next_result()) != NULL) { - $res->free_result(); - } - } - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = $this->queryID->num_rows; - $this->numCols = $this->queryID->field_count; - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_write',1); - // 记录开始执行时间 - G('queryStartTime'); - $result = $this->_linkID->query($str); - $this->debug(); - if ( false === $result ) { - $this->error(); - return false; - } else { - $this->numRows = $this->_linkID->affected_rows; - $this->lastInsID = $this->_linkID->insert_id; - return $this->numRows; - } - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - //数据rollback 支持 - if ($this->transTimes == 0) { - $this->_linkID->autocommit(false); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = $this->_linkID->commit(); - $this->_linkID->autocommit( true); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = $this->_linkID->rollback(); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @param string $sql sql语句 - * @return array - */ - private function getAll() { - //返回数据集 - $result = array(); - if($this->numRows>0) { - //返回数据集 - for($i=0;$i<$this->numRows ;$i++ ){ - $result[$i] = $this->queryID->fetch_assoc(); - } - $this->queryID->data_seek(0); - } - return $result; - } - - /** - * 取得数据表的字段信息 - * @access public - * @return array - */ - public function getFields($tableName) { - $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $info[$val['Field']] = array( - 'name' => $val['Field'], - 'type' => $val['Type'], - 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes - 'default' => $val['Default'], - 'primary' => (strtolower($val['Key']) == 'pri'), - 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), - ); - } - } - return $info; - } - - /** - * 取得数据表的字段信息 - * @access public - * @return array - */ - public function getTables($dbName='') { - $sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES '; - $result = $this->query($sql); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $info[$key] = current($val); - } - } - return $info; - } - - /** - * 替换记录 - * @access public - * @param mixed $data 数据 - * @param array $options 参数表达式 - * @return false | integer - */ - public function replace($data,$options=array()) { - foreach ($data as $key=>$val){ - $value = $this->parseValue($val); - if(is_scalar($value)) { // 过滤非标量数据 - $values[] = $value; - $fields[] = $this->parseKey($key); - } - } - $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; - return $this->execute($sql); - } - - /** - * 插入记录 - * @access public - * @param mixed $datas 数据 - * @param array $options 参数表达式 - * @param boolean $replace 是否replace - * @return false | integer - */ - public function insertAll($datas,$options=array(),$replace=false) { - if(!is_array($datas[0])) return false; - $fields = array_keys($datas[0]); - array_walk($fields, array($this, 'parseKey')); - $values = array(); - foreach ($datas as $data){ - $value = array(); - foreach ($data as $key=>$val){ - $val = $this->parseValue($val); - if(is_scalar($val)) { // 过滤非标量数据 - $value[] = $val; - } - } - $values[] = '('.implode(',', $value).')'; - } - $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); - return $this->execute($sql); - } - - /** - * 关闭数据库 - * @access public - * @return volid - */ - public function close() { - if ($this->_linkID){ - $this->_linkID->close(); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @static - * @access public - * @return string - */ - public function error() { - $this->error = $this->_linkID->error; - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - ThinkLog::record($this->error,'ERR'); - return $this->error; - } - - /** - * SQL指令安全过滤 - * @static - * @access public - * @param string $str SQL指令 - * @return string - */ - public function escapeString($str) { - if($this->_linkID) { - return $this->_linkID->real_escape_string($str); - }else{ - return addslashes($str); - } - } - - /** - * 字段和表名处理添加` - * @access protected - * @param string $key - * @return string - */ - protected function parseKey(&$key) { - $key = trim($key); - if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { - $key = '`'.$key.'`'; - } - return $key; - } -} \ No newline at end of file diff --git a/Think/Db/Driver/Oracle.php b/Think/Db/Driver/Oracle.php index 1aee5e93..7dbbcb92 100644 --- a/Think/Db/Driver/Oracle.php +++ b/Think/Db/Driver/Oracle.php @@ -9,7 +9,7 @@ // | Author: liu21st // +---------------------------------------------------------------------- namespace Think\Db\Driver; -use Think\Db; +use Think\Db\Driver; /** * Oracle数据库驱动 * @category Extend @@ -17,193 +17,49 @@ use Think\Db; * @subpackage Driver.Db * @author ZhangXuehun */ -class Oracle extends Db{ +class Oracle extends Driver{ - private $mode = OCI_COMMIT_ON_SUCCESS; private $table = ''; protected $selectSql = 'SELECT * FROM (SELECT thinkphp.*, rownum AS numrow FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%) thinkphp ) %LIMIT%%COMMENT%'; - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config=''){ - putenv("NLS_LANG=AMERICAN_AMERICA.UTF8"); - if ( !extension_loaded('oci8') ) { - throw_exception(L('_NOT_SUPPERT_').'oracle'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = array(); - } - } - } - - /** - * 连接数据库方法 - * @access public - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; - $conn = $pconnect ? 'oci_pconnect':'oci_new_connect'; - $this->linkID[$linkNum] = $conn($config['username'], $config['password'],$config['database']);//modify by wyfeng at 2008.12.19 - - if (!$this->linkID[$linkNum]){ - $this->error(false); - } - // 标记连接成功 - $this->connected = true; - //注销数据库安全信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - oci_free_statement($this->queryID); - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //更改事务模式 - $this->mode = OCI_COMMIT_ON_SUCCESS; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = oci_parse($this->_linkID,$str); - $this->debug(); - if (false === oci_execute($this->queryID, $this->mode)) { - $this->error(); - return false; - } else { - return $this->getAll(); - } - } - /** * 执行语句 * @access public * @param string $str sql指令 * @return integer */ - public function execute($str) { + public function execute($str,$bind=[]) { $this->initConnect(true); if ( !$this->_linkID ) return false; $this->queryStr = $str; - // 判断新增操作 $flag = false; if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $this->queryStr, $match)) { - $this->table = C("DB_SEQUENCE_PREFIX") .str_ireplace(C("DB_PREFIX"), "", $match[2]); + $this->table = C("DB_SEQUENCE_PREFIX").str_ireplace(C("DB_PREFIX"), "", $match[2]); $flag = (boolean)$this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'"); - }//modify by wyfeng at 2009.08.28 - - //更改事务模式 - $this->mode = OCI_COMMIT_ON_SUCCESS; + } //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_write',1); + if ( !empty($this->PDOStatement) ) $this->free(); + $this->executeTimes++; // 记录开始执行时间 - G('queryStartTime'); - $stmt = oci_parse($this->_linkID,$str); + Debug::remark('queryStartTime','time'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) { + throw_exception($this->error()); + } + $result = $this->PDOStatement->execute($bind); $this->debug(); - if (false === oci_execute($stmt)) { + if ( false === $result) { $this->error(); return false; } else { - $this->numRows = oci_num_rows($stmt); - $this->lastInsID = $flag?$this->insertLastId():0;//modify by wyfeng at 2009.08.28 + $this->numRows = $this->PDOStatement->rowCount(); + if($flag || preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) { + $this->lastInsID = $this->getLastInsertId(); + } return $this->numRows; } } - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - $this->mode = OCI_DEFAULT; - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit(){ - if ($this->transTimes > 0) { - $result = oci_commit($this->_linkID); - if(!$result){ - $this->error(); - return false; - } - $this->transTimes = 0; - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback(){ - if ($this->transTimes > 0) { - $result = oci_rollback($this->_linkID); - if(!$result){ - $this->error(); - return false; - } - $this->transTimes = 0; - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = array(); - $this->numRows = oci_fetch_all($this->queryID, $result, 0, -1, OCI_FETCHSTATEMENT_BY_ROW); - //add by wyfeng at 2008-12-23 强制将字段名转换为小写,以配合Model类函数如count等 - if(C("DB_CASE_LOWER")) { - foreach($result as $k=>$v) { - $result[$k] = array_change_key_case($result[$k], CASE_LOWER); - } - } - return $result; - } - - /** * 取得数据表的字段信息 * @access public @@ -242,39 +98,6 @@ class Oracle extends Db{ return $info; } - /** - * 关闭数据库 - * @access public - */ - public function close() { - if($this->_linkID){ - oci_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error($result = true) { - if($result){ - $error = oci_error($this->queryID); - }elseif(!$this->_linkID){ - $error = oci_error(); - }else{ - $error = oci_error($this->_linkID); - } - if('' != $this->queryStr){ - $error['message'] .= "\n [ SQL语句 ] : ".$this->queryStr; - } - $result? ThinkLog::record($error['message'],'ERR'):throw_exception($error['message'],'',$error['code']); - $this->error = $error['message']; - return $this->error; - } - /** * SQL指令安全过滤 * @access public @@ -309,7 +132,7 @@ class Oracle extends Db{ * @access public * @return integer */ - public function insertLastId() { + public function getLastInsertId() { if(empty($this->table)) { return 0; } diff --git a/Think/Db/Driver/Pdo.php b/Think/Db/Driver/Pdo.php deleted file mode 100644 index ddc8fea0..00000000 --- a/Think/Db/Driver/Pdo.php +++ /dev/null @@ -1,447 +0,0 @@ - -// +---------------------------------------------------------------------- -namespace Think\Db\Driver; -use Think\Db; -/** - * PDO数据库驱动 - * @category Extend - * @package Extend - * @subpackage Driver.Db - * @author liu21st - */ -class Pdo extends Db{ - - protected $PDOStatement = null; - private $table = ''; - - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config=''){ - if ( !class_exists('PDO') ) { - throw_exception(L('_NOT_SUPPERT_').':PDO'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = array(); - } - } - - } - - /** - * 连接数据库方法 - * @access public - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - if($this->pconnect) { - $config['params'][PDO::ATTR_PERSISTENT] = true; - } - //$config['params'][PDO::ATTR_CASE] = C("DB_CASE_LOWER")?PDO::CASE_LOWER:PDO::CASE_UPPER; - try{ - $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']); - }catch (PDOException $e) { - throw_exception($e->getMessage()); - } - // 因为PDO的连接切换可能导致数据库类型不同,因此重新获取下当前的数据库类型 - $this->dbType = $this->_getDsnType($config['dsn']); - if(in_array($this->dbType,array('MSSQL','ORACLE','IBASE','OCI'))) { - // 由于PDO对于以上的数据库支持不够完美,所以屏蔽了 如果仍然希望使用PDO 可以注释下面一行代码 - throw_exception('由于目前PDO暂时不能完美支持'.$this->dbType.' 请使用官方的'.$this->dbType.'驱动'); - } - $this->linkID[$linkNum]->exec('SET NAMES '.C('DB_CHARSET')); - // 标记连接成功 - $this->connected = true; - // 注销数据库连接配置信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - $this->PDOStatement = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( !empty($this->PDOStatement) ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->PDOStatement = $this->_linkID->prepare($str); - if(false === $this->PDOStatement) - throw_exception($this->error()); - $result = $this->PDOStatement->execute(); - $this->debug(); - if ( false === $result ) { - $this->error(); - return false; - } else { - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - $flag = false; - if($this->dbType == 'OCI') - { - if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $this->queryStr, $match)) { - $this->table = C("DB_SEQUENCE_PREFIX").str_ireplace(C("DB_PREFIX"), "", $match[2]); - $flag = (boolean)$this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'"); - } - }//modify by wyfeng at 2009.08.28 - //释放前次的查询结果 - if ( !empty($this->PDOStatement) ) $this->free(); - N('db_write',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->PDOStatement = $this->_linkID->prepare($str); - if(false === $this->PDOStatement) { - throw_exception($this->error()); - } - $result = $this->PDOStatement->execute(); - $this->debug(); - if ( false === $result) { - $this->error(); - return false; - } else { - $this->numRows = $this->PDOStatement->rowCount(); - if($flag || preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) { - $this->lastInsID = $this->getLastInsertId(); - } - return $this->numRows; - } - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - $this->_linkID->beginTransaction(); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = $this->_linkID->commit(); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = $this->_linkID->rollback(); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC); - $this->numRows = count( $result ); - return $result; - } - - /** - * 取得数据表的字段信息 - * @access public - */ - public function getFields($tableName) { - $this->initConnect(true); - if(C('DB_DESCRIBE_TABLE_SQL')) { - // 定义特殊的字段查询SQL - $sql = str_replace('%table%',$tableName,C('DB_DESCRIBE_TABLE_SQL')); - }else{ - switch($this->dbType) { - case 'MSSQL': - case 'SQLSRV': - $sql = "SELECT column_name as 'Name', data_type as 'Type', column_default as 'Default', is_nullable as 'Null' - FROM information_schema.tables AS t - JOIN information_schema.columns AS c - ON t.table_catalog = c.table_catalog - AND t.table_schema = c.table_schema - AND t.table_name = c.table_name - WHERE t.table_name = '$tableName'"; - break; - case 'SQLITE': - $sql = 'PRAGMA table_info ('.$tableName.') '; - break; - case 'ORACLE': - case 'OCI': - $sql = "SELECT a.column_name \"Name\",data_type \"Type\",decode(nullable,'Y',0,1) notnull,data_default \"Default\",decode(a.column_name,b.column_name,1,0) \"pk\" " - ."FROM user_tab_columns a,(SELECT column_name FROM user_constraints c,user_cons_columns col " - ."WHERE c.constraint_name=col.constraint_name AND c.constraint_type='P' and c.table_name='".strtoupper($tableName) - ."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)"; - break; - case 'PGSQL': - $sql = 'select fields_name as "Name",fields_type as "Type",fields_not_null as "Null",fields_key_name as "Key",fields_default as "Default",fields_default as "Extra" from table_msg('.$tableName.');'; - break; - case 'IBASE': - break; - case 'MYSQL': - default: - $sql = 'DESCRIBE '.$tableName;//备注: 驱动类不只针对mysql,不能加`` - } - } - $result = $this->query($sql); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $val = array_change_key_case($val); - $val['name'] = isset($val['name'])?$val['name']:""; - $val['type'] = isset($val['type'])?$val['type']:""; - $name = isset($val['field'])?$val['field']:$val['name']; - $info[$name] = array( - 'name' => $name , - 'type' => $val['type'], - 'notnull' => (bool)(((isset($val['null'])) && ($val['null'] === '')) || ((isset($val['notnull'])) && ($val['notnull'] === ''))), // not null is empty, null is yes - 'default' => isset($val['default'])? $val['default'] :(isset($val['dflt_value'])?$val['dflt_value']:""), - 'primary' => isset($val['dey'])?strtolower($val['dey']) == 'pri':(isset($val['pk'])?$val['pk']:false), - 'autoinc' => isset($val['extra'])?strtolower($val['extra']) == 'auto_increment':(isset($val['key'])?$val['key']:false), - ); - } - } - return $info; - } - - /** - * 取得数据库的表信息 - * @access public - */ - public function getTables($dbName='') { - if(C('DB_FETCH_TABLES_SQL')) { - // 定义特殊的表查询SQL - $sql = str_replace('%db%',$dnName,C('DB_FETCH_TABLES_SQL')); - }else{ - switch($this->dbType) { - case 'ORACLE': - case 'OCI': - $sql = 'SELECT table_name FROM user_tables'; - break; - case 'MSSQL': - case 'SQLSRV': - $sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'"; - break; - case 'PGSQL': - $sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'"; - break; - case 'IBASE': - // 暂时不支持 - throw_exception(L('_NOT_SUPPORT_DB_').':IBASE'); - break; - case 'SQLITE': - $sql = "SELECT name FROM sqlite_master WHERE type='table' " - . "UNION ALL SELECT name FROM sqlite_temp_master " - . "WHERE type='table' ORDER BY name"; - break; - case 'MYSQL': - default: - if(!empty($dbName)) { - $sql = 'SHOW TABLES FROM '.$dbName; - }else{ - $sql = 'SHOW TABLES '; - } - } - } - $result = $this->query($sql); - $info = array(); - foreach ($result as $key => $val) { - $info[$key] = current($val); - } - return $info; - } - - /** - * limit分析 - * @access protected - * @param mixed $lmit - * @return string - */ - protected function parseLimit($limit) { - $limitStr = ''; - if(!empty($limit)) { - switch($this->dbType){ - case 'PGSQL': - case 'SQLITE': - $limit = explode(',',$limit); - if(count($limit)>1) { - $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' '; - }else{ - $limitStr .= ' LIMIT '.$limit[0].' '; - } - break; - case 'MSSQL': - case 'SQLSRV': - break; - case 'IBASE': - // 暂时不支持 - break; - case 'ORACLE': - case 'OCI': - break; - case 'MYSQL': - default: - $limitStr .= ' LIMIT '.$limit.' '; - } - } - return $limitStr; - } - - /** - * 字段和表名处理 - * @access protected - * @param string $key - * @return string - */ - protected function parseKey(&$key) { - if($this->dbType=='MYSQL'){ - $key = trim($key); - if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { - $key = '`'.$key.'`'; - } - return $key; - }else{ - return parent::parseKey($key); - } - - } - - /** - * 关闭数据库 - * @access public - */ - public function close() { - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error() { - if($this->PDOStatement) { - $error = $this->PDOStatement->errorInfo(); - $this->error = $error[2]; - }else{ - $this->error = ''; - } - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - ThinkLog::record($this->error,'ERR'); - return $this->error; - } - - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL指令 - * @return string - */ - public function escapeString($str) { - switch($this->dbType) { - case 'PGSQL': - case 'MSSQL': - case 'SQLSRV': - case 'MYSQL': - return addslashes($str); - case 'IBASE': - case 'SQLITE': - case 'ORACLE': - case 'OCI': - return str_ireplace("'", "''", $str); - } - } - - /** - * 获取最后插入id - * @access public - * @return integer - */ - public function getLastInsertId() { - switch($this->dbType) { - case 'PGSQL': - case 'SQLITE': - case 'MSSQL': - case 'SQLSRV': - case 'IBASE': - case 'MYSQL': - return $this->_linkID->lastInsertId(); - case 'ORACLE': - case 'OCI': - $sequenceName = $this->table; - $vo = $this->query("SELECT {$sequenceName}.currval currval FROM dual"); - return $vo?$vo[0]["currval"]:0; - } - } -} \ No newline at end of file diff --git a/Think/Db/Driver/Pgsql.php b/Think/Db/Driver/Pgsql.php index 05ce7a4d..84fb5952 100644 --- a/Think/Db/Driver/Pgsql.php +++ b/Think/Db/Driver/Pgsql.php @@ -9,7 +9,7 @@ // | Author: liu21st // +---------------------------------------------------------------------- namespace Think\Db\Driver; -use Think\Db; +use Think\Db\Driver; /** * Pgsql数据库驱动 * @category Extend @@ -17,214 +17,25 @@ use Think\Db; * @subpackage Driver.Db * @author liu21st */ -class Pgsql extends Db{ - - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config='') { - if ( !extension_loaded('pgsql') ) { - throw_exception(L('_NOT_SUPPERT_').':pgsql'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = array(); - } - } - } - - /** - * 连接数据库方法 - * @access public - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; - $conn = $pconnect ? 'pg_pconnect':'pg_connect'; - $this->linkID[$linkNum] = $conn('host='.$config['hostname'].' port='.$config['hostport'].' dbname='.$config['database'].' user='.$config['username'].' password='.$config['password']); - if (0 !== pg_connection_status($this->linkID[$linkNum])){ - throw_exception($this->error(false)); - } - //设置编码 - pg_set_client_encoding($this->linkID[$linkNum], C('DB_CHARSET')); - //$pgInfo = pg_version($this->linkID[$linkNum]); - //$dbVersion = $pgInfo['server']; - // 标记连接成功 - $this->connected = true; - //注销数据库安全信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - pg_free_result($this->queryID); - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = pg_query($this->_linkID,$str); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = pg_num_rows($this->queryID); - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_write',1); - // 记录开始执行时间 - G('queryStartTime'); - $result = pg_query($this->_linkID,$str); - $this->debug(); - if ( false === $result ) { - $this->error(); - return false; - } else { - $this->numRows = pg_affected_rows($result); - $this->lastInsID = $this->last_insert_id(); - return $this->numRows; - } - } - - /** - * 用于获取最后插入的ID - * @access public - * @return integer - */ - public function last_insert_id() { - $query = "SELECT LASTVAL() AS insert_id"; - $result = pg_query($this->_linkID,$query); - list($last_insert_id) = pg_fetch_array($result,null,PGSQL_ASSOC); - pg_free_result($result); - return $last_insert_id; - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - pg_exec($this->_linkID,'begin;'); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = pg_exec($this->_linkID,'end;'); - if(!$result){ - $this->error(); - return false; - } - $this->transTimes = 0; - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = pg_exec($this->_linkID,'abort;'); - if(!$result){ - $this->error(); - return false; - } - $this->transTimes = 0; - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = pg_fetch_all($this->queryID); - pg_result_seek($this->queryID,0); - return $result; - } +class Pgsql extends Driver{ /** * 取得数据表的字段信息 * @access public + * @return array */ public function getFields($tableName) { - $result = $this->query("select a.attname as \"Field\", - t.typname as \"Type\", - a.attnotnull as \"Null\", - i.indisprimary as \"Key\", - d.adsrc as \"Default\" - from pg_class c - inner join pg_attribute a on a.attrelid = c.oid - inner join pg_type t on a.atttypid = t.oid - left join pg_attrdef d on a.attrelid=d.adrelid and d.adnum=a.attnum - left join pg_index i on a.attnum=ANY(i.indkey) and c.oid = i.indrelid - where (c.relname='{$tableName}' or c.relname = lower('{$tableName}')) AND a.attnum > 0 - order by a.attnum asc;"); + $result = $this->query('select fields_name as "Field",fields_type as "Type",fields_not_null as "Null",fields_key_name as "Key",fields_default as "Default",fields_default as "Extra" from table_msg('.$tableName.');'); $info = array(); - if($result) { + if($result){ foreach ($result as $key => $val) { $info[$val['Field']] = array( - 'name' => $val['Field'], - 'type' => $val['Type'], - 'notnull' => (bool) ($val['Null'] == 't'?1:0), // 't' is 'not null' - 'default' => $val['Default'], - 'primary' => (strtolower($val['Key']) == 't'), - 'autoinc' => (strtolower($val['Default']) == "nextval('{$tableName}_id_seq'::regclass)"), + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), ); } } @@ -234,9 +45,10 @@ class Pgsql extends Db{ /** * 取得数据库的表信息 * @access public + * @return array */ public function getTables($dbName='') { - $result = $this->query("select tablename as Tables_in_test from pg_tables where schemaname ='public'"); + $result = $this->query("select tablename as Tables_in_test from pg_tables where schemaname ='public'"); $info = array(); foreach ($result as $key => $val) { $info[$key] = current($val); @@ -245,44 +57,9 @@ class Pgsql extends Db{ } /** - * 关闭数据库 - * @access public - */ - public function close() { - if($this->_linkID){ - pg_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error($result = true) { - $this->error = $result?pg_result_error($this->queryID): pg_last_error($this->_linkID); - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - ThinkLog::record($this->error,'ERR'); - return $this->error; - } - - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL指令 - * @return string - */ - public function escapeString($str) { - return pg_escape_string($str); - } - - /** - * limit - * @access public + * limit分析 + * @access protected + * @param mixed $lmit * @return string */ public function parseLimit($limit) { @@ -297,4 +74,5 @@ class Pgsql extends Db{ } return $limitStr; } + } \ No newline at end of file diff --git a/Think/Db/Driver/Sqlite.php b/Think/Db/Driver/Sqlite.php index 839ec22b..3bebe8ec 100644 --- a/Think/Db/Driver/Sqlite.php +++ b/Think/Db/Driver/Sqlite.php @@ -9,7 +9,7 @@ // | Author: liu21st // +---------------------------------------------------------------------- namespace Think\Db\Driver; -use Think\Db; +use Think\Db\Driver; /** * Sqlite数据库驱动 * @category Extend @@ -17,177 +17,7 @@ use Think\Db; * @subpackage Driver.Db * @author liu21st */ -class Sqlite extends Db { - - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config='') { - if ( !extension_loaded('sqlite') ) { - throw_exception(L('_NOT_SUPPERT_').':sqlite'); - } - if(!empty($config)) { - if(!isset($config['mode'])) { - $config['mode'] = 0666; - } - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = array(); - } - } - } - - /** - * 连接数据库方法 - * @access public - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; - $conn = $pconnect ? 'sqlite_popen':'sqlite_open'; - $this->linkID[$linkNum] = $conn($config['database'],$config['mode']); - if ( !$this->linkID[$linkNum]) { - throw_exception(sqlite_error_string()); - } - // 标记连接成功 - $this->connected = true; - //注销数据库安全信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = sqlite_query($this->_linkID,$str); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = sqlite_num_rows($this->queryID); - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_write',1); - // 记录开始执行时间 - G('queryStartTime'); - $result = sqlite_exec($this->_linkID,$str); - $this->debug(); - if ( false === $result ) { - $this->error(); - return false; - } else { - $this->numRows = sqlite_changes($this->_linkID); - $this->lastInsID = sqlite_last_insert_rowid($this->_linkID); - return $this->numRows; - } - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - sqlite_query($this->_linkID,'BEGIN TRANSACTION'); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = sqlite_query($this->_linkID,'COMMIT TRANSACTION'); - if(!$result){ - $this->error(); - return false; - } - $this->transTimes = 0; - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = sqlite_query($this->_linkID,'ROLLBACK TRANSACTION'); - if(!$result){ - $this->error(); - return false; - } - $this->transTimes = 0; - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = array(); - if($this->numRows >0) { - for($i=0;$i<$this->numRows ;$i++ ){ - // 返回数组集 - $result[$i] = sqlite_fetch_array($this->queryID,SQLITE_ASSOC); - } - sqlite_seek($this->queryID,0); - } - return $result; - } +class Sqlite extends Driver { /** * 取得数据表的字段信息 @@ -228,32 +58,6 @@ class Sqlite extends Db { return $info; } - /** - * 关闭数据库 - * @access public - */ - public function close() { - if ($this->_linkID){ - sqlite_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error() { - $this->error = sqlite_error_string(sqlite_last_error($this->_linkID)); - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - ThinkLog::record($this->error,'ERR'); - return $this->error; - } - /** * SQL指令安全过滤 * @access public @@ -261,7 +65,7 @@ class Sqlite extends Db { * @return string */ public function escapeString($str) { - return sqlite_escape_string($str); + return str_ireplace("'", "''", $str); } /** diff --git a/Think/Db/Driver/Sqlsrv.php b/Think/Db/Driver/Sqlsrv.php index 296fd22f..8268cb1d 100644 --- a/Think/Db/Driver/Sqlsrv.php +++ b/Think/Db/Driver/Sqlsrv.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- namespace Think\Db\Driver; -use Think\Db; +use Think\Db\Driver; /** * Sqlsrv数据库驱动 * @category Extend @@ -18,180 +18,8 @@ use Think\Db; * @subpackage Driver.Db * @author liu21st */ -class Sqlsrv extends Db{ +class Sqlsrv extends Driver{ protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; - /** - * 架构函数 读取数据库配置信息 - * @access public - * @param array $config 数据库配置数组 - */ - public function __construct($config='') { - if ( !function_exists('sqlsrv_connect') ) { - throw_exception(L('_NOT_SUPPERT_').':sqlsrv'); - } - if(!empty($config)) { - $this->config = $config; - } - } - - /** - * 连接数据库方法 - * @access public - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $host = $config['hostname'].($config['hostport']?",{$config['hostport']}":''); - $connectInfo = array('Database'=>$config['database'],'UID'=>$config['username'],'PWD'=>$config['password'],'CharacterSet' => C('DEFAULT_CHARSET')); - $this->linkID[$linkNum] = sqlsrv_connect( $host, $connectInfo); - if ( !$this->linkID[$linkNum] ) $this->error(false); - // 标记连接成功 - $this->connected = true; - //注销数据库安全信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - * 释放查询结果 - * @access public - */ - public function free() { - sqlsrv_free_stmt($this->queryID); - $this->queryID = null; - } - - /** - * 执行查询 返回数据集 - * @access public - * @param string $str sql指令 - * @return mixed - */ - public function query($str) { - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = sqlsrv_query($this->_linkID,$str,array(), array( "Scrollable" => SQLSRV_CURSOR_KEYSET)); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = sqlsrv_num_rows($this->queryID); - return $this->getAll(); - } - } - - /** - * 执行语句 - * @access public - * @param string $str sql指令 - * @return integer - */ - public function execute($str) { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) $this->free(); - N('db_write',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID= sqlsrv_query($this->_linkID,$str); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = sqlsrv_rows_affected($this->queryID); - $this->lastInsID = $this->mssql_insert_id(); - return $this->numRows; - } - } - - /** - * 用于获取最后插入的ID - * @access public - * @return integer - */ - public function mssql_insert_id() { - $query = "SELECT @@IDENTITY as last_insert_id"; - $result = sqlsrv_query($this->_linkID,$query); - list($last_insert_id) = sqlsrv_fetch_array($result); - sqlsrv_free_stmt($result); - return $last_insert_id; - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - sqlsrv_begin_transaction($this->_linkID); - } - $this->transTimes++; - return ; - } - - /** - * 用于非自动提交状态下面的查询提交 - * @access public - * @return boolen - */ - public function commit() { - if ($this->transTimes > 0) { - $result = sqlsrv_commit($this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 事务回滚 - * @access public - * @return boolen - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = sqlsrv_rollback($this->_linkID); - $this->transTimes = 0; - if(!$result){ - $this->error(); - return false; - } - } - return true; - } - - /** - * 获得所有的查询数据 - * @access private - * @return array - */ - private function getAll() { - //返回数据集 - $result = array(); - if($this->numRows >0) { - while($row = sqlsrv_fetch_array($this->queryID,SQLSRV_FETCH_ASSOC)) - $result[] = $row; - } - return $result; - } /** * 取得数据表的字段信息 @@ -299,33 +127,4 @@ class Sqlsrv extends Db{ return $this->execute($sql); } - /** - * 关闭数据库 - * @access public - */ - public function close() { - if ($this->_linkID){ - sqlsrv_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - * 数据库错误信息 - * 并显示当前的SQL语句 - * @access public - * @return string - */ - public function error($result = true) { - $errors = sqlsrv_errors(); - $this->error = ''; - foreach( $errors as $error ) { - $this->error .= $error['message']; - } - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - $result? ThinkLog::record($error['message'],'ERR'):throw_exception($this->error); - return $this->error; - } } \ No newline at end of file diff --git a/Think/Db/Lite.php b/Think/Db/Lite.php new file mode 100644 index 00000000..7f82c53f --- /dev/null +++ b/Think/Db/Lite.php @@ -0,0 +1,387 @@ + +// +---------------------------------------------------------------------- +// $Id$ +namespace Think\Db; +use Think\Config; +use Think\Debug; +use Think\Log; +use PDO; +class Lite { + // PDO操作实例 + protected $PDOStatement = null; + // 当前操作所属的模型名 + protected $model = '_think_'; + // 当前SQL指令 + protected $queryStr = ''; + protected $modelSql = []; + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 数据库连接ID 支持多个连接 + protected $linkID = []; + // 当前连接ID + protected $_linkID = null; + // 当前查询ID + protected $queryID = null; + // 数据库连接参数配置 + protected $config = []; + + protected $queryTimes = 0; + protected $executeTimes = 0; + // PDO连接参数 + protected $options = [ + PDO::ATTR_CASE => PDO::CASE_LOWER, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, + PDO::ATTR_STRINGIFY_FETCHES => false, + ]; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = []; + } + $this->config['params'] = $this->options+$this->config['params']; + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + try{ + if(empty($config['dsn'])) { + $config['dsn'] = $config['dbms'].':dbname='.$config['database'].';host='.$config['hostname']; + if(!empty($config['hostport'])) { + $config['dsn'] .= ';port='.$config['hostport']; + }elseif(!empty($config['unix_socket'])){ + $config['dsn'] .= ';unix_socket='.$config['unix_socket']; + } + } + $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']); + }catch (\PDOException $e) { + throw_exception($e->getMessage()); + } + if(!empty($config['charset'])) { + $this->linkID[$linkNum]->exec('SET NAMES '.$config['charset']); + } + // 注销数据库连接配置信息 + if(1 != $config['deploy']) $this->config = []; + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->PDOStatement = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str,$bind=[]) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + $this->queryTimes++; + // 记录开始执行时间 + Debug::remark('queryStartTime','time'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) + throw_exception($this->error()); + $result = $this->PDOStatement->execute($bind); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + return $this->getResult(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str,$bind=[]) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + $this->executeTimes++; + // 记录开始执行时间 + Debug::remark('queryStartTime','time'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) { + throw_exception($this->error()); + } + $result = $this->PDOStatement->execute($bind); + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = $this->PDOStatement->rowCount(); + if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) { + $this->lastInsID = $this->getLastInsertId(); + } + return $this->numRows; + } + } + + /** + * 获取最后插入id + * @access public + * @return integer + */ + public function getLastInsertId() { + return $this->_linkID->lastInsertId(); + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->_linkID->beginTransaction(); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = $this->_linkID->commit(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = $this->_linkID->rollback(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getResult() { + //返回数据集 + $result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC); + $this->numRows = count( $result ); + return $result; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + if($this->PDOStatement) { + $error = $this->PDOStatement->errorInfo(); + $this->error = $error[2]; + }else{ + $this->error = ''; + } + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + Log::record($this->error,'ERR'); + return $this->error; + } + + /** + * 获取最近一次查询的sql语句 + * @param string $model 模型名 + * @access public + * @return string + */ + public function getLastSql($model='') { + return $model?$this->modelSql[$model]:$this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->lastInsID; + } + + /** + * 获取最近的错误信息 + * @access public + * @return string + */ + public function getError() { + return $this->error; + } + + /** + * 设置当前操作模型 + * @access public + * @param string $model 模型名 + * @return void + */ + public function setModel($model){ + $this->model = $model; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + $this->modelSql[$this->model] = $this->queryStr; + $this->model = '_think_'; + // 记录操作结束时间 + Debug::remark('queryEndTime','time'); + Log::record($this->queryStr.' [ RunTime:'.Debug::getUseTime('queryStartTime','queryEndTime').'s ]','SQL'); + } + + /** + * 初始化数据库连接 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function initConnect($master=true) { + if(1 == $this->config['deploy']) + // 采用分布式数据库 + $this->_linkID = $this->multiConnect($master); + else + // 默认单数据库 + if ( !$this->_linkID ) $this->_linkID = $this->connect(); + } + + /** + * 连接分布式服务器 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function multiConnect($master=false) { + static $_config = []; + if(empty($_config)) { + // 缓存分布式数据库配置解析 + foreach ($this->config as $key=>$val){ + $_config[$key] = explode(',',$val); + } + } + // 数据库读写是否分离 + if(Config::get('db_rw_separate')){ + // 主从式采用读写分离 + if($master) + // 主服务器写入 + $r = floor(mt_rand(0,Config::get('db_master_num')-1)); + else{ + if(is_numeric(Config::get('db_slave_no'))) {// 指定服务器读 + $r = Config::get('db_slave_no'); + }else{ + // 读操作连接从服务器 + $r = floor(mt_rand(Config::get('db_master_num'),count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + } + }else{ + // 读写操作不区分服务器 + $r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + $db_config = [ + 'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], + 'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], + 'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], + 'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], + 'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], + 'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], + 'params' => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0], + ]; + return $this->connect($db_config,$r); + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 释放查询 + if ($this->queryID){ + $this->free(); + } + // 关闭连接 + $this->close(); + } +} \ No newline at end of file