Home > Mobile >  PDO MYSQL HY093 (wrong number of parameters) issued incorrectly
PDO MYSQL HY093 (wrong number of parameters) issued incorrectly

Time:05-14

I am receiving an HY093 (Parameter count mismatch) SQLSTATE on a query where I don't believe a mismatch exists.

Below I have a complete PHP script to reproduce the error. (Need to change the database credentials, of course.) In that script, nine question-marks are present in the SELECT statement, and there are 9 values in the search array, all hard coded for this test. And yet, the SELECT returns false (does not throw exception as desired) and SQLSTATE value is HY093, which my research tells me indicates an incorrect number of parameters.

My secondary disappointment is that this does not throw an error, but primarily I'm at a loss as to how I can query this table.

Any suggestions what might be causing this? Or what other information is needed in order to determine the problem?

Linux velmicro 5.13.0-40-generic #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC 2022 x86_64

PHP version 7.4.3

mysql version is 8.0.24

UBUNTU VERSION="20.04.3 LTS (Focal Fossa)"

#! /usr/bin/php
<?php

$pdoOptions = [ PDO::ATTR_EMULATE_PREPARES   => false // no emulation mode for "real" prepared stmts
            ,  PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION // Errors cause exception
            ,  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC // Default fetch mode
            ,  PDO::MYSQL_ATTR_FOUND_ROWS   => true
            ,  PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
            ] ;

$pdo = new PDO('mysql:host=hostname.org.com;dbname=mainDb', 'username', 'password', $pdoOptions) ;


$pdo->exec("DROP TABLE IF EXISTS emotes") ;

$pdo->exec(<<<EOS
                CREATE TABLE emotes (
                    id int NOT NULL AUTO_INCREMENT
                   , emoteChar varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
                   , epoch int NOT NULL
                   , name varchar(64) NOT NULL
                   , image1 varchar(128) DEFAULT NULL
                   , image2 varchar(128) DEFAULT NULL
                   , shortcut1 varchar(64) DEFAULT NULL
                   , shortcut2 varchar(64) DEFAULT NULL
                   , shortcut3 varchar(64) DEFAULT NULL
                   , shortcut4 varchar(64) DEFAULT NULL
                   , shortcut5 varchar(64) DEFAULT NULL
                   , PRIMARY KEY (id)
                   , KEY charEffective (emoteChar,epoch)
                    )
                EOS ) ;


$sql = <<<EOS
            SELECT id
            FROM   emotes em
            WHERE  emoteChar = ?
               AND name = ?
               AND IFNULL(image1, '') = IFNULL(?, '')
               AND IFNULL(image2, '') = IFNULL(?, '')
               AND IFNULL(shortcut1, '') = IFNULL(?, '')
               AND IFNULL(shortcut2, '') = IFNULL(?, '')
               AND IFNULL(shortcut3, '') = IFNULL(?, '')
               AND IFNULL(shortcut4, '') = IFNULL(?, '')
               AND IFNULL(shortcut5, '') = IFNULL(?, '')
               AND NOT EXISTS (SELECT 1
                               FROM   emotes sub
                               WHERE  sub.emoteChar = em.emoteChar
                                  AND sub.epoch > em.epoch
                               )
            EOS ;
$findEmoteStmt = $pdo->prepare($sql) ;
$findValues = [   'emoteChar' => 'x'
                , 'name' => 'name'
                , 'image1' => 'image1'
                , 'image2' => 'image2'
                , 'shortcut1' => 'shortcut1'
                , 'shortcut2' => 'shortcut2'
                , 'shortcut3' => 'shortcut3'
                , 'shortcut4' => 'shortcut4'
                , 'shortcut5' => 'shortcut5'
                         ] ;
$searchOk = $findEmoteStmt->execute( $findValues ) ;
if (! $searchOK) {
    printf("Could not search emoticon.  %d elements in the values.\nSQL='%s'\n  values=(%s)\n   error=(%s)\n"
               , count($findValues)
               , $findEmoteStmt->queryString
               , implode(',', $findValues)
               , implode(',', $findEmoteStmt->errorInfo())
                    ) ;
    }

Execution:

> php test.php
Could not search emoticon.  9 elements in the values.
SQL='SELECT id
FROM   emotes em
WHERE  emoteChar = ?
   AND name = ?
   AND IFNULL(image1, '') = IFNULL(?, '')
   AND IFNULL(image2, '') = IFNULL(?, '')
   AND IFNULL(shortcut1, '') = IFNULL(?, '')
   AND IFNULL(shortcut2, '') = IFNULL(?, '')
   AND IFNULL(shortcut3, '') = IFNULL(?, '')
   AND IFNULL(shortcut4, '') = IFNULL(?, '')
   AND IFNULL(shortcut5, '') = IFNULL(?, '')
   AND NOT EXISTS (SELECT 1
                   FROM   emotes sub
                   WHERE  sub.emoteChar = em.emoteChar
                      AND sub.epoch > em.epoch
                   )'
  values=(x,name,image1,image2,shortcut1,shortcut2,shortcut3,shortcut4,shortcut5)
   error=(HY093,,)

CodePudding user response:

fYou have positional parameter placeholders (?) but your values are in an associative array, which PDO would use for named parameter placeholders. You can't mix these different styles.

There are two ways you can fix this. Use one fix or the other (not both :-).

One fix would be to pass a simple array to execute(), not an associative array:

$searchOk = $findEmoteStmt->execute( array_values($findValues) ) ;

The other fix would be to use named parameter placeholders corresponding to the keys of your $findValues array, like this:

...    
WHERE  emoteChar = :emoteChar
   AND name = :name
...

And similarly for the other parameters.

The point is that if you use positional parameters, then pass a simple array of values. If you use named parameters, then pass an associative array of key/value pairs.

  • Related