[TYPO3-core] RFC #15457: Add support for prepared queries [summary and pending questions]
Xavier Perseguers
typo3 at perseguers.ch
Thu Aug 19 09:13:21 CEST 2010
Hi,
I summarize this message because a +1 by testing is still missing (from
anybody). In addition/in regard to that point, there are a few decisions
that should be agreed on.
Currently, we have:
+1 by reading from Helmut
+1 by reading, reviewing and testing from Ernesto
Before having the final +1 by testing, please answer those
questions/remarks, let me possibly make a new version and then I'd
kindly ask another +1 by testing by anybody and a new +1 by testing from
Ernesto (or either Masi or Steffen if Ernesto is unable to do it in the
very near future).
> Problem:
> Having support for prepared queries would allow to implement an
> efficient caching mechanism when using DBAL which would result in a huge
> speed improvement.
>
> It will provide a PDO-like syntax which could, in a second phase, allow
> TYPO3 to issue real prepared statements to the underlying DBMS. In
> addition, this RFC provides a DB abstraction that is object oriented,
> meaning, it is not necessary anymore to deal with MySQL pointers
>
> How prepared queries could then be used:
> Idea is to rewrite Core queries using prepared queries once this support
> has been made available.
sample #1 (named parameter)
====================================
$statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('*', 'pages',
'pid = :pid');
$statement->execute(array(':uid' => 2));
while (($row = $statement->fetch()) !== FALSE) {
// ...
}
$statement->free();
sample #2 (question mark parameter)
====================================
$statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('uid, title',
'pages', 'pid = ?');
$pid = 1;
$statement->bindParam(1, $pid);
$statement->execute();
$pagesWithPid1 = $statement->fetchAll();
$statement->free();
// New execution of the prepared query and explicitly setting the type
of parameter
$pid = 4;
$statement->bindParam(1, $pid, t3lib_db_PreparedStatement::PARAM_INT);
$statement->execute();
$pagesWithPid4 = $statement->fetchAll();
$statement->free();
Questions / Remarks from Jigal:
> PARAM_AUTOTYPE is not present in PDO, so this will require extra
> code when using PDO itself
After a few tests, Using type PARAM_STR instead seems fine and works (by
testing) with numerical columns such as pid or uid. And it behaves like PDO.
Same problem happens with PARAM_FLOAT which does not exist in PDO and
could be handled as PARAM_STR. PARAM_INT should stay as it is (now with
latest patch), that is, an integer!
> Do not default PARAM_STR
I do not agree. Either we keep PARAM_AUTOTYPE and as such do not default
to PARAM_STR or behave like PDO but forcing the user to provide a
datatype means:
1) bindValues() and execute($params) will be completely unusable as user
should then provide an array within an array for parameters
2) Would not behave like PDO and then is not in line with your wish to
have an API as close as possible to PDO ;-)
> Remove method bindValues()
I do not see the downside of having it if we default to PARAM_STR
instead of the would-not-exist-anymore PARAM_AUTOTYPE. This way, it
would behave as when providing parameters in method execute(). But I
find it a bit cleaner than forcing user to pass multiple parameters to
execute() (which s/he could still do).
> Named markers are only replaced once in PDO.
The remarks is to allow or not such query:
$statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery('uid, title',
'pages', 'uid = :id OR pid = :id');
$statement->bindValue(':id', 43);
where :id is replaced twice. In PDO this is not the case. Still, I find
it handy and as such would like to keep it.
> fetch* functions in PDO default to FETCH_BOTH; is there a reason to
do something else?
Have you real use-cases where you rely on having both indexed- and
named-based keys in your resultset? How is your code using
$GLOBALS['TYPO3_DB'] currently written to work like that?
> In PDO this is not possible to support both named and positionned
markers as it results in exception SQLSTATE[HY093] being thrown.
=> We have no way in native MySQL to detect that both types are used in
query. What we could do is see which type is used with first call to
bindValue() and stick to that type for all subsequent calls...
Remarks from me:
Regarding your ancient "PDO" class. Did not test but we could use
something like you did:
if (!is_numeric($key)) {
// replace the marker (not preceeded by a word character or a ':' but
followed
// by a word boundary)
$this->sql = preg_replace('/(?<![\w:])'.$key.'\b/', PDO::quote($val,
$data_type), $this->sql);
}
instead of str_replace() when using native MySQL (when using DBAL we
have a proper way of replacing both question marks and named markers).
Regarding constant values. It does not cost anything to use the real
internal value of PDO instead of sequential value. As such I'd like to
have it as in PDO (PARAM_INT, PARAM_BOOL, PARAM_STR).
Possible support for INSERT, UPDATE, ... may be added in future but will
definitively not with this RFC.
Thanks for reading so far, thanks in advance for your remarks ;-)
Xavier
More information about the TYPO3-team-core
mailing list