145 votes

Obtention d'une chaîne de requête SQL brute à partir d'instructions préparées par PDO

Existe-t-il un moyen d’exécuter la chaîne SQL brute lors de l’appel de PDOStatement :: execute () sur une instruction préparée? Cela serait extrêmement utile pour le débogage.

117voto

Bill Karwin Points 204877

Je suppose que vous voulez dire que vous voulez la dernière requête SQL, avec les valeurs de paramètre d'interpolation. Je comprends que ce serait utile pour le débogage, mais ce n'est pas la façon dont les requêtes préparées de travail. Les paramètres ne sont pas combinées avec une déclaration préparée sur le côté client, donc, PDO ne devrait jamais avoir accès à la chaîne de requête combinée avec ses paramètres.

La requête est envoyée au serveur de base de données lorsque vous effectuez la préparation de(), et les paramètres sont envoyés séparément lorsque vous ne execute(). MySQL général journal de la requête indique que la finale de SQL avec des valeurs interpolées après avoir execute(). Ci-dessous un extrait de mon journal de la requête. J'ai couru les requêtes de la base de données mysql CLI, pas de PDO, mais le principe est le même.

081016 16:51:28 2 Query       prepare s1 from 'select * from foo where i = ?'
    	        2 Prepare     [2] select * from foo where i = ?
081016 16:51:39 2 Query       set @a =1
081016 16:51:47 2 Query       execute s1 using @a
    	        2 Execute     [2] select * from foo where i = 1

Vous pouvez également obtenir ce que vous voulez si vous définissez l'attribut PDO PDO::ATTR_EMULATE_PREPARES. Dans ce mode, PDO interpoler les paramètres dans la requête SQL et envoie la totalité de la requête lorsque vous execute(). Ce n'est pas un vrai requête préparée. Vous permettra de contourner les avantages de requêtes préparées par interpolation des valeurs des variables dans la chaîne SQL avant execute().

110voto

bigwebguy Points 636
/**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public static function interpolateQuery($query, $params) {
    $keys = array();

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }
    }

    $query = preg_replace($keys, $params, $query, 1, $count);

    #trigger_error('replaced '.$count.' keys');

    return $query;
}

34voto

Mike Points 81

J'ai modifié la méthode pour inclure la sortie de traitement des tableaux pour des instructions telles que WHERE IN (?).

UPDATE: Nous venons d'ajouter un contrôle pour la valeur NULL et des paramètres $ dupliqués afin que les valeurs réelles des paramètres ne soient pas modifiées.

Grand travail bigwebguy et merci!

 /**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_string($value))
            $values[$key] = "'" . $value . "'";

        if (is_array($value))
            $values[$key] = implode(',', $value);

        if (is_null($value))
            $values[$key] = 'NULL';
    }

    $query = preg_replace($keys, $values, $query, 1, $count);

    return $query;
}
 

9voto

Chris Go Points 70

Mike a ajouté un peu plus au code de Mike - faites défiler les valeurs pour ajouter des guillemets simples

 /**
 * Replaces any parameter placeholders in a query with the value of that
 * parameter. Useful for debugging. Assumes anonymous parameters from 
 * $params are are in the same order as specified in $query
 *
 * @param string $query The sql query with parameter placeholders
 * @param array $params The array of substitution parameters
 * @return string The interpolated query
 */
public function interpolateQuery($query, $params) {
    $keys = array();
    $values = $params;

    # build a regular expression for each parameter
    foreach ($params as $key => $value) {
        if (is_string($key)) {
            $keys[] = '/:'.$key.'/';
        } else {
            $keys[] = '/[?]/';
        }

        if (is_array($value))
            $values[$key] = implode(',', $value);

        if (is_null($value))
            $values[$key] = 'NULL';
    }
    // Walk the array to see if we can add single-quotes to strings
    array_walk($values, create_function('&$v, $k', 'if (!is_numeric($v) && $v!="NULL") $v = "\'".$v."\'";'));

    $query = preg_replace($keys, $values, $query, 1, $count);

    return $query;
}
 

6voto

Glass Robot Points 1922

PDOStatement a une propriété publique $ queryString. Ça devrait être ce que tu veux.

Je viens de remarquer que PDOStatement a une méthode non documentée debugDumpParams () que vous pouvez également consulter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X