I spent few hours trying to insert a query using PDO, and finally I realized that I can`t do it (dont know how).
The problem is in fact that column name have "?" in it. One of columns is named "If HSM Visa to what year?". Because of that, Every time I do insert I get either:
- wrong number of parameters passed or
- cant mix name and ? in query.
I gave up from this, and I'm going to alter mysql table I got to work with (who is naming columns with question marks anyway ?), but I'm still curious.
INSERT INTO `tbl_maindetails` (`Id`,`Title`,`If HSM Visa to what year?`) VALUES (?, ?, ?)
Thanks,
Goran
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
will solve the issue, I believe.
I have the same problem! I tried to get around the confusion between the character "?" in the column (field) names and the same character "?" as a positional (un-named) placeholder in PDO, by switching to NAMED parameter binding... but the problem STILL persists :(
Now, PDO sees the "?" in the column names and thinks I'm mixing up named and positional parameters!
For example:
UPDATE myTable SET `title` = :title, `Underwater?` = :Underwater
WHERE ID='123'
together with the following binding:
Array ( [:title] => test [:Underwater] => 0)
produces thee following ERROR MESSAGE:
"SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters"
Notice that I avoided placing any "?" inside the placeholder itself (it's ":Underwater" rather than ":Underwater?", but it was no help...)
Clearly, this is a bug! PDO is seeing the "?" in the column names, and jumping to the conclusion that it's a positional placeholder, even if we are strictly using NAME parameter binding!
I'll see if I can report this bug...
Since MySQL allows question marks in the column names, I see no compelling reason why we must avoid them! (Though, in the short term, I'll do that, sigh...)
Here is the only (ugly) solution that I could come up with:
$db->query("SET #column_name = 'question?'");
$db->query("SET #sql_text = CONCAT('INSERT INTO table1 SET `', #column_name, '` = ?')");
$db->query("PREPARE stmt FROM #sql_text;");
$db->query("SET #v = ?", 'something');
$db->query("EXECUTE stmt USING #v");
echo $db->insert_id();
This will insert a new row into table1 with question? = 'something'
This code is using a PDO wrapper so you'll need to adjust for that.
In the long run I think you made the right choice by renaming the column.
Related
I'm trying to create a query using PDO, where the query includes a subquery. The code isn't working. Using the workbench, I can do the query and it does perform.
I feel like there is nuance here when it comes to deriving a table while using PDO.
$turn = 1;
$phase = -1;
$status = "waiting";
$gameid = 1;
$stmt = $this->connection->prepare("
UPDATE playerstatus
SET
turn = :turn,
phase = :phase,
status = :status,
value = value + (SELECT reinforce FROM games where id = :gameid)
WHERE
gameid = :gameid
");
$stmt->bindParam(":turn", $turn);
$stmt->bindParam(":phase", $phase);
$stmt->bindParam(":status", $status);
$stmt->bindParam(":gameid", $gameid);
$stmt->execute();
I tried a multitude of adjustments, it simply fails upon executing.
EDIT error:
Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number
A known (but not well documented) limitation with PDO named placholders: the same bind placeholder can't be used more than one time in a statement. Workaround is to use distinct bind placeholder names.
(This limitation in PDO may have been addressed in a later versions(?). I think the root cause is that "behind the scenes", PDO is replacing the named placeholders with positional notation question marks. This problem is not restricted to just UPDATE statements, this same problem plagues all PDO SQL statements using named placeholders.)
Also, not related to the problem, I recommend using bindValue in place of bindParam.
Change the bind placeholder name to be distinct/unique. Shown here, changing one of the occurrences of :gameid to :gameid2
value = value + (SELECT reinforce FROM games where id = :gameid)
WHERE
gameid = :gameid2
^
And we need to supply a value for each bind placeholder. Which means we need to add another line. With bindValue, we can reference the same variable without needing make a copy of it.
$stmt->bindValue(":gameid", $gameid);
$stmt->bindValue(":gameid2", $gameid);
^
(Side-note: Blocking ! in question titles doesn't stop smart-arses like me putting U+203C Double Exclamation Mark instead :p)
After a quick round of debugging, I found this:
$query = <<<END
SELECT
`column1`, `column2`,
SOME_FUNCTION(`column3`) -- process in PHP instead?
FROM `tablename`
WHERE `condition` BETWEEN ? AND ?
END;
$stmt = $pdo->prepare($query);
$stmt->execute(array(1,10));
And got this:
Uncaught Exception » RuntimeException » PDOException:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
Do you see the problem?
The question mark in the comment -- process in PHP instead? is interpreted as a token to bind a parameter to! PDO then expects three parameters instead of the two that were passed.
Now, obviously the simple solution was to just rewrite the comment, but this feels like I'm avoiding what may be a bigger issue.
Is there perhaps something wrong with PDO, or is there an option I can set to have it understand MySQL comments?
You can have comments, but not those with ? in them or other things like :x that would be interpreted as placeholders.
PDO does not understand SQL syntax. It's treating all that text as something that needs to be examined for placeholders. When emulating prepared statements this is what will happen.
I have a query that looks like this:
SELECT CONCAT('path/to/page/?id=', id) AS link FROM users WHERE name = ?
I am using PDO to prepare this statement and I am getting the error
Invalid parameter number: number of bound variables does not match number of tokens
because it thinks the question mark in the CONCAT string is a placeholder.
Is there any way to escape the question mark so PDO knows that it is not a placeholder?
Please no comments about other ways to get the link. I am changing old code that goes into an old templating engine so it would be A LOT less work to find a way to escape the question mark than to not put a question mark in the query.
PDO is not confused by the question mark inside the quotes. I just test this with PHP 5.5.15.
$sql = "SELECT CONCAT('path/to/page/?id=', id) AS link FROM foo WHERE name = ?;";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(1, 'name');
$stmt->execute();
print_r($stmt->fetchAll());
It works fine, with no error about a wrong number of parameters. Your error is caused by the way you're binding parameters, not by the SQL syntax.
I suspect you haven't shown us the whole SQL query, because WHERE without FROM is a syntax error anyway. So you must have additional parameter placeholders that you haven't shown us. It would also be helpful if you show us the way you're binding parameters (or passing parameters to execute()).
This is a very old question, but the escaping of question marks have landed into PHP 7.4.
A question mark is escaped by adding a second... question mark.
In your query, you could add this:
$sql = "SELECT CONCAT('path/to/page/??id=', id) AS link FROM users WHERE name = ?";
For usage with json or jsonb operator in postgresql:
$sql = "SELECT '["a", "b", "c"]'::jsonb ?? 'a'";
I am currently working on a php project and used the word 'value' as a column name. The problem being that when I run the query, it overwrites all entries in the database, even though I have a delimiter (primary key = *). I have tried everything I can think of to get this to work, and it hasn't yet. here is the complete line of code:
$SqlStatement = "UPDATE rev_exp SET Date_Entered = '".date('Y-m-d')."', Description = '".$_POST['txtUtilityType']." ".$_POST['txtAccountNumber']." ".$_POST['txtDateAdded']."', `Value` = ".$_POST['txtValueBalance'].", Notes = '".$_POST['txtNotes']."' WHERE PK_Rev_Exp = ".$row['FK_Rev_Exp'];
Note here, that $row['FK_Rev_Exp'] is the delimiter I was talking about. It is being pulled accurately from a previous query. Also, please ignore any sql injection problems, I'm just working on getting the project functional, I can optimize later.
EDIT 1: I have also tried enclosing the "value" in everything I can think of that may get rid of this problem, but no luck.
EDIT 2: I also don't think it is a problem with the statement itself, as I directly entered the statement into the mysql command line and it only affected 1 row, possibly a php problem?
EDIT 3: Full block, including the execution of the sql. Here, ExecuteSQL runs all necessary mysqli statements to execute the sql command. it takes in a sql statement and a true/false if there is a result set:
$SqlStatement = "UPDATE rev_exp SET Date_Entered = '".date('Y-m-d')."', Description = '".$_POST['txtUtilityType']." ".$_POST['txtAccountNumber']." ".$_POST['txtDateAdded']."', `Value` = '".$_POST['txtValueBalance']."', Notes = '".$_POST['txtNotes']."' WHERE PK_Rev_Exp = ".$row['FK_Rev_Exp'];
ExecuteSQL($SqlStatement, false);
I can't figure it out, and any help would be appreciated.
I think your problem is not about mysql reserver keywords because your correctly surrounded Value with backtick and that makes database understand this is a field. I'm more concerned about treating not integers as integers so i would suggest to surround with quotes '' your value since it is a decimal
`Value` = '".$_POST['txtValueBalance']."',
I have a database. I had created a a table containing only one row in DB if it wasn't constructed before.
Why it has only 1 row is that I just use it to keep some info.
There is a field of TYPE NVARCHAR(100) which I want to use it to store session id,
and here comes the headache for me:
It seems that I can't even properly INSERT(I use phpmyadmin to check and it's blank) and UPDATE(syntax error...) it with a session id obtained from session_id(), which is returned as a string.
Here is the portion of my code relating to my action:
//uamip,uamport is in URL;I use $_GET[]
$_SESSION[uamport] = $_GET['uamport'];
$_SESSION[uamip] = $_GET['uamip'];
**$_SESSION[sid] = session_id();**
//construct
$sql="CREATE TABLE trans_vector(
`index` INT NOT NULL AUTO_INCREMENT,
`sid` NVARCHAR(100),
`uamip` CHAR(15),
`uamport` INT,
PRIMARY KEY (`index`)
)" ;
mysql_query($sql);
//insert(first time, so not constructed)
$sql="INSERT INTO trans_vector (sid,uamip,uamport) VALUES(
'$_SESSION[sid]',
'$_SESSION[myuamip]',
'$_SESSION[myuamport]'
)";
mysql_query($sql);
//update(from 2nd time and later, table exists, so I want to update the sid part)
$sql="UPDATE trans_vector SET sid="**.**$_SESSION[sid];
mysql_query($sql)
Now, when I use phpmyadmin to check the sid field after INSERT or UPDATE, It is blank;
But if I do this:
$vector=mysql_fetch_array(mysql_query("SELECT TABLES LIKE 'trans_vector'"));
and echo $vector[sid] ,then it's printed on webpage.
Another question is:
With the UPDATE statement above, I always get such error:
"Unknown column xxxxxx....(some session id returned, it seems it always translate it first and put it in the SQL statement, ** treating it as a column NAME** that's not what I want!)"
I tried some TYPE in CREATE statement, and also lots of syntax of the UPDATE statement(everything!!!) but it always give this error.
I am dealing trouble with ' and string representation containing a variable where the latter's value is actually what I want... and maybe the problem arise from type in CREATE and string representation in UPDATE statement?
Should CAST() statement helpful for me?
Wish you can help me deal with this...and probably list some real reference of such issue in PHP?
Thanks so much!!
$insert = "INSERT INTO trans_vector (`sid`, `uamip`, `uamport`) VALUES(
'".$_SESSION["sid"]."',
'".$_SESSION["myuamip"]."',
'".$_SESSION["myuamport"]."'
)";
this should solve at least some warnings, if not errors.
and for update...
$update = "UPDATE trans_vector SET `sid`='".$_SESSION["sid"]."';";
Notes about your code:
Array values have to be put into the string with operator '.' and cannot be inserted directly. Array indexes must be strings (note the ") or integers.
Column names should have `` around them. To insert a string with SQL, you have to put string into ''s, so the parser knows what is string and what column name. Without ''s parser is assuming you are stating a column.
and for mysql_escape_string, I assumed you handle that before storing data to sessions. Without those, you might can get unwanted SQL injections. And in case you did not do that, you can either do that (before you create queries):
foreach($_SESSION as $key => $value)
$_SESSION[$key] = mysql_escape_string($value);
or manually escape strings when you create a query.
As for the update statement, it’s clear that there are apostrophes missing. You always need apostrophes, when you want to insert a string value into the database. Moreover, you should use mysql_real_escape_string.
However, I think standard mysql is deprecated and has been removed in newer versions of PHP in favor of MySQLi and PDO. Thus you should switch to MySQLi or PDO soon.
You should also use apostrophes when referencing values within $_SESSION. Otherwise PHP will try to find a constanst with the name sid and later fallback to the string 'sid'. You will get into trouble if there once really is a constant called sid defined.
Here, the corrected update statement in mysql library:
$sql = "UPDATE trans_vector SET sid='" . mysql_real_escape_string($_SESSION['sid']) . "'";
Even better:
$sql = "UPDATE `trans_vector` SET `sid`='" . mysql_real_escape_string($_SESSION['sid']) . "'";
Using backticks makes clear for MySQL that this is a column name. Sometimes you will have column names that are called like reserved keywords in SQL. Then you will need apostrophes. A common example is a column called order for the sequence of entries.