cyb5201314 发表于 2012-8-11 02:03:56

深夜寂寞看CI,发现BUG一枚,请验收。。。

CI 版本:2.1.2
文件:system/database/DB_driver.php
类:CI_DB_driver
方法:compile_binds($sql, $binds)
大约578行左右。
方法的描述是:Compile Bindings
该方法应该是为了实现sql语句的占位符替换成目标数据的功能,如:

INSERT INTO `table` (`colA`, `colB`) VALUES (?,?);   替换成   
INSERT INTO `table` (`colA`, `colB`) VALUES (数值1,数值2);

在此方法里还做了数据转意。

/**
       * Compile Bindings
       *
       * @access        public
       * @param        string        the sql statement
       * @param        array        an array of bind data
       * @return        string
       */
        function compile_binds($sql, $binds)
        {
                if (strpos($sql, $this->bind_marker) === FALSE)
                {
                        return $sql;
                }

                if ( ! is_array($binds))
                {
                        $binds = array($binds);
                }

                // Get the sql segments around the bind markers
                $segments = explode($this->bind_marker, $sql);

                // The count of bind should be 1 less then the count of segments
                // If there are more bind arguments trim it down
                if (count($binds) >= count($segments)) {
                        $binds = array_slice($binds, 0, count($segments)-1);
                }

                // Construct the binded query
                $result = $segments;
                $i = 0;
                foreach ($binds as $bind)
                {
                        $result .= $this->escape($bind);
                        $result .= $segments[++$i];
                }

                return $result;
        }
看着一部分:
if ( ! is_array($binds))
                {
                        $binds = array($binds);
                }
看图:http://1.ssdt.sinaapp.com/%E6%9C%AA%E5%91%BD%E5%90%8D.jpg

http://1.ssdt.sinaapp.com/%E6%9C%AA%E5%91%BD%E5%90%8D1.jpg

cyb5201314 发表于 2012-8-11 02:05:40

{:1_1:}今天才下载CI看的,希望一起进步

Hex 发表于 2012-8-11 09:20:59

从注释来看,这个 $binds 应该传递数组或者一个字符串,而不能是 1,2,3,4 这样的字符串,也就是说这个方法不会去拆分逗号分割的字符串。

cyb5201314 发表于 2012-8-11 10:40:07

Hex 发表于 2012-8-11 09:20 static/image/common/back.gif
从注释来看,这个 $binds 应该传递数组或者一个字符串,而不能是 1,2,3,4 这样的字符串,也就是说这个方法 ...
假如就想您说的,不是类似的1,2,3,4字符串,那他为什么要将一个字符串整合成一个一维数组?还要进行foreach??假如sql语句里占位符只能写一个,那为什么不直接替换,而大费周章的去遍历?我没说他会去拆分1,2,3,4,而是相反的将其作为一个数组元素

Hex 发表于 2012-8-11 14:13:25

cyb5201314 发表于 2012-8-11 10:40 static/image/common/back.gif
假如就想您说的,不是类似的1,2,3,4字符串,那他为什么要将一个字符串整合成一个一维数组?还要进行foreac ...

先判断是不是数组,不是数组变成数组,这样的写法比较常见吧,就是为了后续可以统一按数组来处理。
占位符可以写多个,所以 $binds 可以传一个数组过来。

cyb5201314 发表于 2012-8-11 15:51:43

本帖最后由 cyb5201314 于 2012-8-11 15:54 编辑

Hex 发表于 2012-8-11 14:13 static/image/common/back.gif
先判断是不是数组,不是数组变成数组,这样的写法比较常见吧,就是为了后续可以统一按数组来处理。
占位 ...
我知道统一成数组很方便,但是请您看看这下面的代码好吗?$binds = array($binds);这句会把$binds变成一个一维数组,而他下面又对$binds进行了foreach,欲将$binds内的元素按顺序替换到占位符的位置,但是按您讲的,如果只是简单的获取一个数组,而且是一维数组,您觉得这是对的??就算是目标数值是一样的,那也只需要替换一下全部的占位符为目标数值就行了,何必弄成数组,再看下面,他将sql语句用占位符分割了,再遍历$binds的一维数组,将每一个元素连接在分割的sql里,出现的结果就是sql断开了,除非他的功能只能支持占位符为1个数量的,此时$binds可以是一个字符串,刚去英文网站找了已经改过的版本
/**
         * Compile Bindings
         *
         * @param      string      the sql statement
         * @param      array      an array of bind data
         * @return      string
         */
      public function compile_binds($sql, $binds)
      {
                if (empty($binds) OR empty($this->bind_marker) OR strpos($sql, $this->bind_marker) === FALSE)
                {
                        return $sql;
                }
                elseif ( ! is_array($binds))
                {
                        $binds = array($binds);
                        $bind_count = 1;
                }
                else
                {
                        // Make sure we're using numeric keys
                        $binds = array_values($binds);
                        $bind_count = count($binds);
                }

                // We'll need the marker length later
                $ml = strlen($this->bind_marker);

                // Make sure not to replace a chunk inside a string that happens to match the bind marker
                if ($c = preg_match_all("/'[^']*'/i", $sql, $matches))
                {
                        $c = preg_match_all('/'.preg_quote($this->bind_marker).'/i',
                              str_replace($matches,
                                        str_replace($this->bind_marker, str_repeat(' ', $ml), $matches),
                                        $sql, $c),
                              $matches, PREG_OFFSET_CAPTURE);

                        // Bind values' count must match the count of markers in the query
                        if ($bind_count !== $c)
                        {
                              return $sql;
                        }
                }
                elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker).'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
                {
                        return $sql;
                }

                do
                {
                        $c--;
                        $sql = substr_replace($sql, $this->escape($binds[$c]), $matches[$c], $ml);
                }
                while ($c !== 0);

                return $sql;
      }

Hex 发表于 2012-8-11 17:35:02

cyb5201314 发表于 2012-8-11 15:51 static/image/common/back.gif
我知道统一成数组很方便,但是请您看看这下面的代码好吗?$binds = array($binds);这句会把$binds变成一个 ...

这里的关键就是要看 $binds 是什么。
如果 $binds 是 1,2,3,4 就有问题,如果 $binds 是 array('1','2','3','4') 就没问题。
要看是谁调用的 compile_binds() 方法。调用的时候是如何传参的。

Hex 发表于 2012-8-11 17:43:40

cyb5201314 发表于 2012-8-11 15:51 static/image/common/back.gif
我知道统一成数组很方便,但是请您看看这下面的代码好吗?$binds = array($binds);这句会把$binds变成一个 ...

我刚才又仔细看了下传参,这个参数手册规定是要传递一个数组,类似 array('123', 'abc', 'def') 这样的。
我看了一下,你这个是最新代码库里的代码,不过,感觉 $binds 处理没变,只是改变了一下替换占位符的代码。

kissgxd 发表于 2012-8-13 11:05:45

看了半天,没懂BUG在哪

^淡如清风 发表于 2012-8-13 17:45:24

我看懂了。
页: [1] 2
查看完整版本: 深夜寂寞看CI,发现BUG一枚,请验收。。。