Chinaunix首页 | 论坛 | 博客
  • 博客访问: 532489
  • 博文数量: 119
  • 博客积分: 3167
  • 博客等级: 中校
  • 技术积分: 1215
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-20 21:21
文章分类

全部博文(119)

文章存档

2015年(21)

2012年(4)

2011年(1)

2007年(11)

2006年(50)

2005年(32)

分类: PHP

2015-09-06 12:15:33

SQL 错误消息: "???????????????? "@tid"??" SQL 语句: "INSERT INTO members ([tid], [name], [age]) VALUES (@tid,@name,@age)" SQL 错误代码: "7335941".


下面是TableDataGateway里面的部分代码


        list($holders, $values) = $this->dbo->getPlaceholder($row, $this->fields);
        $holders = implode(',', $holders);
        $fields = $this->dbo->qfields(array_keys($values));
        $sql = "INSERT INTO {$this->qtableName} ({$fields}) VALUES ({$holders})";
 


        // 插入数据
        if (!$this->dbo->Execute($sql, $values, true)) 






getPlaceholder 就是对SQL语句进行组装,函数定义在Abstract.php里面, 如下




/**
     * 根据驱动的参数占位符样式,返回包含参数占位符及有效数据的数组
     *
     * @param array $inputarr
     * @param array $fields
     *
     * @return array
     */
00803     function getPlaceholder(& $inputarr, $fields = null)
00804     {
00805         $holders = array();
00806         $values = array();
00807         if (is_array($fields)) {
00808             $fields = array_change_key_case(array_flip($fields), CASE_LOWER);
00809             foreach (array_keys($inputarr) as $key) {
00810                 if (!isset($fields[strtolower($key)])) { continue; }
00811                 if ($this->PARAM_STYLE == DBO_PARAM_QM) {
00812                     $holders[] = $this->PARAM_STYLE;
00813                 } else {
00814                     $holders[] = $this->PARAM_STYLE . $key;
00815                 }
00816                 $values[$key] =& $inputarr[$key];
00817             }
00818         } else {
00819             foreach (array_keys($inputarr) as $key) {
00820                 if ($this->PARAM_STYLE == DBO_PARAM_QM) {
00821                     $holders[] = $this->PARAM_STYLE;
00822                 } else {
00823                     $holders[] = $this->PARAM_STYLE . $key;
00824                 }
00825                 $values[$key] =& $inputarr[$key];
00826             }
00827         }
00828         return array($holders, $values);
00829     }












比如我们需要插入一行数据, 这个函数辅助组装SQL语句, 


原始数据是个KEY数组,getPlaceholder 传递参数 $inputarr 就是我们需要插入的值,参数$fields 就是字段名
函数返回的holders是判断PARAM_STYLE的定义 ,比如DBO_PARAM_QM ,
返回值一个是占位符数组 holders, 还有就是一个key型数组, 也就是需要插入的数据数组。


这个只是准备工作, 有了这两个数组后在TableDataGateway文件里面组装临时SQL语句, 


$sql = "INSERT INTO {$this->qtableName} ({$fields}) VALUES ({$holders})";


然后用数据库访问对象来调用自身类下的执行语句,
$this->dbo->Execute($sql, $values, true)


当然dbo所属的类里面还需要对这个临时sql语句进行最终解析, 比如这里是这个dbo对象是mssql类


于是找到mssql.php里面的execute函数


function execute($sql, $inputarr = null, $throw = true)


函数头里面的inputarr可以看到是上面的values, 也就是已经整理过的需要插入的数据数组
而传递过来的$sql就是上面的临时的包含占位符的临时SQL语句,


函数里面,这个地方语句      
if (is_array($inputarr)) {

            $sql = $this->bind($sql, $inputarr);
        }




$this->bind($sql, $inputarr);  就是把占位符替换成具体的值
比如
INSERT INTO [members] ([tid], [name], [age]) VALUES (@tid,@name,@age)
替换成 INSERT INTO [members] ([tid], [name], [age]) VALUES (123,abc,12)




结果发现这个bind函数只有父类中有定义, 在Abstract.php文件中:


    function bind($sql, & $inputarr)
    {
        $arr = explode('?', $sql);
        $sql = array_shift($arr);
        foreach ($inputarr as $value) {
            if (isset($arr[0])) {
                $sql .= $this->qstr($value) . array_shift($arr);
            }
        }
        return $sql;
    }


可见这个函数里面只对占位符'?'进行处理,而在实际调用的时候,mssql类下面占位符定义的是DBO_PARAM_AT_NAMED(at名称的形式)
比如上面的传参的我们打印出临时SQL语句查看占位符是VALUES (@tid,@name,@age)这样的形式,
于是bind函数没有起到应有的作用, SQL语句解析没有完成


引起这个问题的原因就是占位符


var $PARAM_STYLE = DBO_PARAM_AT_NAMED;
var $PARAM_STYLE = DBO_PARAM_QM;


尝试在mssql.php文件中把占位符直接改成问号形式, 而不要at名称的形式




这个改完发现生成的SQL成了这种形式
INSERT INTO [members] ([tid], [name], [age]) VALUES (32,weiwei,97)


还是报错, 因为数据类型问题 ,缺引号, 如果全加引号,或给weiwei加上引号就能正确执行,


可以看到上面的bind函数里面的$this->qstr 就是起这个加引号的作用, 


而mssql类下面的qstr实际运行的效果是没有加上引号,对比下看看吧, 




mssql.php文件里面的:


    function qstr($value)
    {
        if (is_int($value)) { return $value; }
        if (is_bool($value)) { return $value ? $this->TRUE_VALUE : $this->FALSE_VALUE; }
        if (is_null($value)) { return $this->NULL_VALUE; }
        return str_replace("'", "''", $value);
    }




mysql.php文件里面的


    function qstr($value)
    {
        if (is_int($value) || is_float($value)) { return $value; }
        if (is_bool($value)) { return $value ? $this->TRUE_VALUE : $this->FALSE_VALUE; }
        if (is_null($value)) { return $this->NULL_VALUE; }
        return "'" . mysql_real_escape_string($value, $this->conn) . "'";
    }






最后的一句返回


return "'" . mysql_real_escape_string($value, $this->conn) . "'";


就是加上引号,而且需要实现一个类似mysql_real_escape_string的功能来保证数据安全, 
简单测试下的话  就直接这样返回吧
return "'" . $value . "'";
这种形式倒是能正常运转了
后来发现原文件中已经有实现一个escap string的函数, 于是 return "'" . mssql_real_escape_string($value) . "'";
阅读(481) | 评论(0) | 转发(0) |
0

上一篇:fleaphp mssql

下一篇:fleaphp TRY CATCH

给主人留下些什么吧!~~