BlackM BlackM - 1 month ago 9
SQL Question

PHP - MySQLi - Insert with SELECT at the end not working

I have this function in PHP. I am trying to insert (if it's necessary) and then get the app_id from the table.

private function addApp($bundle_identifier,$os_id) {

$driver = new mysqli_driver();
$driver->report_mode = MYSQLI_REPORT_ALL;

//Insert or update app details
if ($stmt = $this->db->prepare("INSERT IGNORE INTO app (app_identifier,os_id) VALUES (?,?); SELECT app_id FROM app WHERE app_identifier = ? AND os_id = ?")){
$stmt->bind_param("ssss", $bundle_identifier,$os_id,$bundle_identifier,$os_id);
$stmt->execute();
$stmt->bind_result($app_id);

if (!isset($app_id)) {
echo "is set";
$app_id=$stmt->insert_id;
}
}

if($this->db->commit()){
return $app_id;
}

return 0;
}


The issue here is that stmt is always false with the error:


Uncaught exception 'mysqli_sql_exception' with message 'You have an
error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near 'SELECT app_id
FROM app WHERE app_identifier = ? AND os_id = ?' at line 1'


The weird thing is that this query works fine in my SQL.
Is that a limitation of mysqli?

Answer

According to http://php.net/manual/en/mysqli.prepare.php :

The query must consist of a single SQL statement.

Which basically answers your question. You have to use two db calls for two queries. Or use something like http://php.net/manual/en/mysqli.multi-query.php

The below is kept for information only as it refers PDO, while the question is about mysqli. It's generally useful though.

I think the reason for this working in mysql, but not in mysqli is that the latter supports prepared statements natively, while the former uses emulation. As your expression contains two queries, all bound parameters are given by driver to the first query (out of which is uses two and discards the other two). The second query then gets no parameters and therefore question marks are syntax errors. With prepared statements emulation PHP actually substitutes question marks with the properly escaped values and so forms two valid queries.

You can enable emulation using $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true), however, this may slightly affect performance.

See also http://www.php.net/manual/en/pdo.setattribute.php