====== PDO SQLite named parameters bug workaround ======
The PDO SQLite back-end driver of php has a nasty bug with named parameters which has not been corrected **since 2006**, and nobody seems to care (bug mentioned [[http://www.trirand.net/forum/default.aspx?g=posts&m=3313#post3313|here]], detailed [[http://pecl.php.net/bugs/bug.php?id=7560|here]]). It can make certain requests to fail with the following error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 25 bind or column index out of range' in ...
There are only two workaround this bug: Use positional parameters (''?'') instead of named parameters ('':param'') or use the following workaround I wrote. This is neither brilliant nor perfect, but it does the job. It simply replaces the named parameters with their value.
function sqlite_computequery($query,$params)
{
$matches = array();
preg_match_all ('/\:\w+/',$query,$matches,PREG_OFFSET_CAPTURE); // Return the offsets of patterns found.
$newquery='';
$from=0; // Current offset
foreach($matches[0] as $item)
{
$param=substr($item[0],1); // Name of parameter
$offset=$item[1]; // Offset in query
if (isset($params[$param]))
{ $value = str_replace('"','""',$params[$param]); } // Value to replace with.
else
{ $value=''; }
$value='"'.$value.'"';
$newquery=$newquery.substr($query,$from,$offset-$from).$value;
$from = $offset+strlen($param)+1;
}
$newquery=$newquery.substr($query,$from);
return $newquery;
}
Example:
$myquery = 'insert into mytable (name,phone) values (:name,:phone)';
$myparams = array( 'name'=>'John', 'phone'=>'12345');
print sqlite_computequery($myquery,$myparams);
which displays:
insert into mytable (name,phone) values ("John","12345")
So instead of doing:
$myquery = 'insert into mytable (name,phone) values (:name,:phone)';
$myparams = array( 'name'=>'John', 'phone'=>'12345');
$q = $db->prepare($myquery);
$q->execute($myparams);
Do:
$myquery = 'insert into mytable (name,phone) values (:name,:phone)';
$myparams = array( 'name'=>'John', 'phone'=>'12345');
$q = $db->prepare(sqlite_computequery($myquery,$myparams));
$q->execute();
This function will probably have to be tweaked to handle numerical values and such, but it works.
~~DISCUSSION:closed~~