From 49108300c90d9e3e75023c192ad457f2feb99869 Mon Sep 17 00:00:00 2001 From: thinkphp Date: Tue, 10 Jan 2017 10:31:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E5=AF=B9=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E8=BF=87=E7=A8=8B=E8=B0=83=E7=94=A8=E7=9A=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20=E6=94=B9=E8=BF=9BgetRealSql=E7=9A=84=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=20=E6=94=B9=E8=BF=9B=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E8=A1=A8=E5=AD=97=E6=AE=B5=E4=BD=BF=E7=94=A8=E4=B8=AD=E5=88=92?= =?UTF-8?q?=E7=BA=BF=E7=9A=84=E5=8F=82=E6=95=B0=E7=BB=91=E5=AE=9A=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- library/think/db/Builder.php | 2 +- library/think/db/Connection.php | 135 +++++++++++++++++++++----------- 2 files changed, 92 insertions(+), 45 deletions(-) diff --git a/library/think/db/Builder.php b/library/think/db/Builder.php index 2372152c..3e7a60e9 100644 --- a/library/think/db/Builder.php +++ b/library/think/db/Builder.php @@ -316,7 +316,7 @@ abstract class Builder throw new Exception('where express error:' . $exp); } } - $bindName = $bindName ?: 'where_' . str_replace('.', '_', $field); + $bindName = $bindName ?: 'where_' . str_replace(['.', '-'], '_', $field); if (preg_match('/\W/', $bindName)) { // 处理带非单词字符的字段名 $bindName = md5($bindName); diff --git a/library/think/db/Connection.php b/library/think/db/Connection.php index ef56c6fd..580dd10d 100644 --- a/library/think/db/Connection.php +++ b/library/think/db/Connection.php @@ -118,6 +118,9 @@ abstract class Connection PDO::ATTR_EMULATE_PREPARES => false, ]; + // 绑定参数 + protected $bind = []; + /** * 架构函数 读取数据库配置信息 * @access public @@ -319,22 +322,26 @@ abstract class Connection /** * 执行查询 返回数据集 * @access public - * @param string $sql sql指令 - * @param array $bind 参数绑定 - * @param boolean $master 是否在主服务器读操作 - * @param bool|string $class 指定返回的数据集对象 + * @param string $sql sql指令 + * @param array $bind 参数绑定 + * @param bool $master 是否在主服务器读操作 + * @param bool $class 是否返回PDO对象 * @return mixed * @throws BindParamException * @throws PDOException */ - public function query($sql, $bind = [], $master = false, $class = false) + public function query($sql, $bind = [], $master = false, $pdo = false) { $this->initConnect($master); if (!$this->linkID) { return false; } - // 根据参数绑定组装最终的SQL语句 - $this->queryStr = $this->getRealSql($sql, $bind); + + // 记录SQL语句 + $this->queryStr = $sql; + if ($bind) { + $this->bind = $bind; + } //释放前次的查询结果 if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) { @@ -349,16 +356,22 @@ abstract class Connection if (empty($this->PDOStatement)) { $this->PDOStatement = $this->linkID->prepare($sql); } + // 是否为存储过程调用 + $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); // 参数绑定 - $this->bindValue($bind); + if ($procedure) { + $this->bindParam($bind); + } else { + $this->bindValue($bind); + } // 执行查询 $this->PDOStatement->execute(); // 调试结束 $this->debug(false); - $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); + // 返回结果集 return $this->getResult($class, $procedure); } catch (\PDOException $e) { - throw new PDOException($e, $this->config, $this->queryStr); + throw new PDOException($e, $this->config, $this->getLastsql()); } } @@ -377,8 +390,12 @@ abstract class Connection if (!$this->linkID) { return false; } - // 根据参数绑定组装最终的SQL语句 - $this->queryStr = $this->getRealSql($sql, $bind); + + // 记录SQL语句 + $this->queryStr = $sql; + if ($bind) { + $this->bind = $bind; + } //释放前次的查询结果 if (!empty($this->PDOStatement) && $this->PDOStatement->queryString != $sql) { @@ -393,8 +410,14 @@ abstract class Connection if (empty($this->PDOStatement)) { $this->PDOStatement = $this->linkID->prepare($sql); } - // 参数绑定操作 - $this->bindValue($bind); + // 是否为存储过程调用 + $procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']); + // 参数绑定 + if ($procedure) { + $this->bindParam($bind); + } else { + $this->bindValue($bind); + } // 执行语句 $this->PDOStatement->execute(); // 调试结束 @@ -403,7 +426,7 @@ abstract class Connection $this->numRows = $this->PDOStatement->rowCount(); return $this->numRows; } catch (\PDOException $e) { - throw new PDOException($e, $this->config, $this->queryStr); + throw new PDOException($e, $this->config, $this->getLastsql()); } } @@ -416,23 +439,21 @@ abstract class Connection */ public function getRealSql($sql, array $bind = []) { - if ($bind) { - foreach ($bind as $key => $val) { - $value = is_array($val) ? $val[0] : $val; - $type = is_array($val) ? $val[1] : PDO::PARAM_STR; - if (PDO::PARAM_STR == $type) { - $value = $this->quote($value); - } elseif (PDO::PARAM_INT == $type) { - $value = (float) $value; - } - // 判断占位符 - $sql = is_numeric($key) ? - substr_replace($sql, $value, strpos($sql, '?'), 1) : - str_replace( - [':' . $key . ')', ':' . $key . ',', ':' . $key . ' '], - [$value . ')', $value . ',', $value . ' '], - $sql . ' '); + foreach ($bind as $key => $val) { + $value = is_array($val) ? $val[0] : $val; + $type = is_array($val) ? $val[1] : PDO::PARAM_STR; + if (PDO::PARAM_STR == $type) { + $value = $this->quote($value); + } elseif (PDO::PARAM_INT == $type) { + $value = (float) $value; } + // 判断占位符 + $sql = is_numeric($key) ? + substr_replace($sql, $value, strpos($sql, '?'), 1) : + str_replace( + [':' . $key . ')', ':' . $key . ',', ':' . $key . ' '], + [$value . ')', $value . ',', $value . ' '], + $sql . ' '); } return rtrim($sql); } @@ -444,7 +465,7 @@ abstract class Connection * @access public * @param array $bind 要绑定的参数列表 * @return void - * @throws \think\Exception + * @throws BindParamException */ protected function bindValue(array $bind = []) { @@ -463,7 +484,34 @@ abstract class Connection throw new BindParamException( "Error occurred when binding parameters '{$param}'", $this->config, - $this->queryStr, + $this->getLastsql(), + $bind + ); + } + } + } + + /** + * 存储过程的输入输出参数绑定 + * @access public + * @param array $bind 要绑定的参数列表 + * @return void + * @throws BindParamException + */ + protected function bindParam($bind) + { + foreach ($bind as $key => $val) { + if (is_numeric($key)) { + $key = $key + 1; + } + array_unshift($val, $key); + $result = call_user_func_array([$this->PDOStatement, 'bindParam'], $val); + if (!$result) { + $param = array_shift($val); + throw new BindParamException( + "Error occurred when binding parameters '{$param}'", + $this->config, + $this->getLastsql(), $bind ); } @@ -473,19 +521,19 @@ abstract class Connection /** * 获得数据集 * @access protected - * @param bool|string $class true 返回PDOStatement 字符串用于指定返回的类名 - * @param bool $procedure 是否存储过程 + * @param bool $pdo 是否返回PDOStatement + * @param bool $procedure 是否存储过程 * @return mixed */ - protected function getResult($class = '', $procedure = false) + protected function getResult($pdo = false, $procedure = false) { - if (true === $class) { + if ($pdo) { // 返回PDOStatement对象处理 return $this->PDOStatement; } if ($procedure) { // 存储过程返回结果 - return $this->procedure($class); + return $this->procedure(); } $result = $this->PDOStatement->fetchAll($this->fetchType); $this->numRows = count($result); @@ -500,14 +548,13 @@ abstract class Connection /** * 获得存储过程数据集 * @access protected - * @param bool|string $class true 返回PDOStatement 字符串用于指定返回的类名 * @return array */ - protected function procedure($class) + protected function procedure() { $item = []; do { - $result = $this->getResult($class); + $result = $this->getResult(); if ($result) { $item[] = $result; } @@ -698,7 +745,7 @@ abstract class Connection */ public function getLastSql() { - return $this->queryStr; + return $this->getRealSql($this->queryStr, $this->bind); } /** @@ -736,7 +783,7 @@ abstract class Connection $error = ''; } if ('' != $this->queryStr) { - $error .= "\n [ SQL语句 ] : " . $this->queryStr; + $error .= "\n [ SQL语句 ] : " . $this->getLastsql(); } return $error; } @@ -771,7 +818,7 @@ abstract class Connection // 记录操作结束时间 Debug::remark('queryEndTime', 'time'); $runtime = Debug::getRangeTime('queryStartTime', 'queryEndTime'); - $sql = $sql ?: $this->queryStr; + $sql = $sql ?: $this->getLastsql(); $log = $sql . ' [ RunTime:' . $runtime . 's ]'; $result = []; // SQL性能分析