WordPress.org

Make WordPress Core

Ticket #2862: wpdb_BuildSql.diff

File wpdb_BuildSql.diff, 7.0 KB (added by DevaSatyam, 12 years ago)

patch file

  • wp-includes/wp-db.php

     
    8383                else
    8484                        return mysql_real_escape_string( $string, $this->dbh );
    8585        }
     86       
     87        /**
     88 *  Builds a properly formatted and escaped SQL statement using an SQL template and a list of arguments.
     89 *
     90 *  The function scans the template for query marks ? which are placeholders for the arguments
     91 *  Query marks are to be followed by format descriptors.
     92 *
     93 *  The first argument, the template, is mandatory.  If the template contains no query marks
     94 *  and no argument is given, the function does nothing.
     95 *
     96 *  Placeholders have the following format and are not case sensitive:
     97 *
     98 *  <b>?[nn][m]t</b>
     99 *
     100 *  Where:
     101 *
     102 *  <b>?</b> Begining of placeholder for argument
     103 *
     104 *  <b>nn - <i>position</i></b> number of the argument to be replaced.
     105 *      Argument 0 is the template itself and is not valid.
     106 *      The first argument after the SQL template is number 1
     107 *              If no number is given, arguments are taken sequentially.
     108 *              Numbered replacements do not move the sequential argument pointer.
     109 *              Arguments beyond the actual number present are considered null
     110 *
     111 *  <b>m - <i>modifier</i></b> [optional] indicates what to do if the argument is null
     112 *  - m: mandatory, if the argument contains null, it will give a fatal error.
     113 *  - z: null, if the argument is 0 or an empty string, it will be replaced by null
     114 *
     115 *  <b>t - <i>data type</i></b> the placeholder will be replaced by the argument as follows
     116 *  - s: string, if not null, it will be escaped and enclosed in quotes
     117 *  - i: integer, the integer value (intval() function) of the argument
     118 *  - f: float, the floating point value (floatval() function) of the argument
     119 *  - d: date, the argument will be assumed to represent a timestamp and it will be converted to yyyy-mm-dd and quoted
     120 *  - b: boolean, anything evaluated to false will be 0, otherwise 1
     121 *  - t: table prefix, the value of the global variable <i>$table_prefix</i>, escaped and unquoted
     122 *       It takes no argument from the argument list
     123 *
     124 *  Example:
     125 *  <code>
     126 *  echo BuildSql('Insert into ?ttable (?s,?ns,?mi,?d,?ni,?i)','Something','',5,time(),0,null);
     127 *  </code>
     128 *  will return:
     129 *  <pre>
     130 *  Insert into wp_table ('Something',null,5,'2006-05-15',null,0)
     131 *  </pre>
     132 *
     133 *  Note that placeholders do not need to be quoted, if quotes are required (strings or dates) they will be provided
     134 *
     135 *  @param string $query Template of SQL statement
     136 *
     137 *
     138 *  @param mixed $value,... Values to be replaced into placeholders, sequentially unless stated otherwise
     139 *
     140 *  @return string properly formated and escaped SQL statement
     141 *
     142 *  The function will call bail if an unknown formatting character is found.
     143 *  Unused arguments will produce warnings.
     144 *  Missing arguments will be assumed null and will trigger a fatal error
     145 *    if the placeholder has the mandatory modifier m.
     146 *  There is no provision to put a literal ? into the SQL statement since the ? is not a valid SQL operator,
     147 *    the only valid place for query marks are in literal string constants, which can be passed to this
     148 *    function in an argument
     149 */
    86150
     151        function BuildSql($query) {
     152                global $table_prefix;
     153
     154                $num_args = func_num_args();  // number of arguments available
     155                $args_used = (1 << $num_args) -2; // bit mask to check if arguments are used
     156            /*                      +---------Anything up to first query mark
     157                                    |      +------ query mark, start of placeholder
     158                                    |      |    +---- position of argument
     159                                    |      |    |     +----- modifier
     160                                    |      |    |     |       +--- data type
     161                                                                |      |    |     |       |                     */
     162                if (preg_match_all('|([^\?]*)(\?(\d?\d)?([mn]?)([sifdbt])?)*|i',$query,$matches,PREG_SET_ORDER)) {
     163                        $arg_pointer = 1; // sequential pointer to arguments
     164                        $s = '';  // output SQL statement
     165                        foreach($matches as $match) {
     166                                $NullIfEmpty = false;
     167                                $s .= $match[1];    //concatenate everything up to question mark
     168                                $type = strtolower($match[5]);  // read datatype
     169       
     170                                // read the value of the argument
     171                                if ($type =='t') {
     172                                        $value = $table_prefix;         // t is a special case, it takes no argument from the list
     173                                        $n = 0;
     174                                } elseif (intval($match[3])) {  // if there is a nn position modifier, read it
     175                                                                                                // (null evaluates to 0, which is an invalid position anyhow)
     176                                        $n = intval($match[3]);
     177                                } else {                                                // else, read the next sequential argument an increment the argument pointer
     178                                        $n = $arg_pointer++;
     179                                }
     180                                if ($n) {               // if there was an argument to be read (notice t does not ask for an argument)
     181                                        $args_used &= ~ (1 << $n);   // some bitwise magic to unset the bit position representing the argument
     182                                        if ($n >= $num_args) $value = null;   // if argument requeste beyond those available, assume it null
     183                                        else $value = func_get_arg($n);      // otherwise, read it
     184                                }
     185       
     186                                switch ($match[4]) {  // read modifier
     187                                        case 'm':                       // mandatory?
     188                                        case 'M':
     189                                                if (is_null($value)) $this->bail("<p>Missing value for argument $n near: ... ${match[0]} ...</p>");
     190                                                break;
     191                                        case 'n':               // null if empty?
     192                                        case 'N':
     193                                                $NullIfEmpty = true;  // set flag
     194                                                break;
     195                                }
     196                                switch($type) { // now we process $value according to datatype and $NullIfEmpty flag
     197                                case 's':
     198                                        case 'S':
     199                                                if ($NullIfEmpty and strlen($value) == 0) {
     200                                                        $s .='null';
     201                                                } else {
     202                                                $s .= "'" . $this->escape($value) . "'"; 
     203                                                }
     204                                        break;
     205                                case 'i':
     206                                        case 'I':
     207                                                if ($NullIfEmpty and $value == 0) {
     208                                                        $s .='null';
     209                                                } else {
     210                                                $s .= intval($value);
     211                                                }
     212                                        break;
     213                                case 'f':
     214                                        case 'F':
     215                                                if ($NullIfEmpty and $value == 0) {
     216                                                        $s .='null';
     217                                                } else {
     218                                                $s .= floatval($value);
     219                                                }
     220                                        break;
     221                                        case 'd':
     222                                        case 'D':
     223                                                if ($NullIfEmpty and empty($value)) {
     224                                                        $s .='null';
     225                                                } else {
     226                                                        $s .= "'" . date('Y-m-d', $value) . "'";
     227                                                }
     228                                                break;
     229                                        case 'b':
     230                                        case 'B':  // booleans cannot be null
     231                                                $s .= intval($value!=false);
     232                                                break;
     233                                        case 't':
     234                                        case 'T':
     235                                                $s .=  $this->escape($value);
     236                                                break;
     237                                        case null:
     238                                                break;
     239                                default:
     240                                                $this->bail('<p>Unknown formatting character in BuildSql: ' . $match[0] . " en SQL <br />[$query]</p>");
     241                                }
     242       
     243                        }
     244                }
     245                // if all arguments used, $args_used will be zero
     246                if ($args_used) {
     247                        for($i=1;$i<$num_args;$i++) {
     248                                $args_used >>=1; // bitmaks is shift right
     249                                // if right most bit still 1, it means it has not been used.
     250                                if ($args_used & 1) $this->bail("Argument $i not used");
     251                        }
     252                }
     253       
     254                return $s;
     255        }
     256
    87257        // ==================================================================
    88258        //      Print SQL/DB error.
    89259