I have a function in PostgreSQL / plpgsql with the following signature:
CREATE OR REPLACE FUNCTION user_login(TEXT, TEXT) RETURNS SETOF _get_session AS $$ ... $$
Where _get_session is a view. The function works fine when calling it from phpPgAdmin, however whan I call it from PHP I get the following error:
Warning: pg_query() [function.pg-query]: Query failed: ERROR: type
"session_ids" does not exist CONTEXT: compile of PL/pgSQL function
"user_login" near line 2 in /home/sites/blah.com/index.php on line 69
The DECLARE section of the function contains the following variables:
oldSessionId session_ids := $1;
newSessionId session_ids := $2;
The domain session_ids DOES exist, and other functions which use the same domain work when called from the same script. The PHP is as follows:
$query = "SELECT * FROM $dbschema.user_login('$session_old'::TEXT, '$session'::TEXT)";
$result = pg_query($login, $query);
I have also tried this using ::session_ids in place of ::TEXT when calling the function, however I recieve the same error.
Help :o(
Just make your code simple:
$query = "SELECT * FROM $dbschema.user_login($1, $2)";
$result = pg_query_params($login, $query, array($session_old, $session));
Now you're safe from SQL injection.
But, your function is still wrong, there is no datatype "session_ids". I think you want to use TEXT in the DECLARE part.
If your query covers multiple lines, then PHP is most likely not sending them as part of the same transaction. If this is the case you have two options.
The first option is to send all the queries in the same call
pg_query("query1; query2; query3;");
The second option (and the best in my opinion) is to use transactions. This will allow you to make the calls over several lines though the begin statement will most likely need to be sent with the initial query.
pg_query("begin; query1;");
pg_query("query2;");
pg_query("commit;");
If there is an error that occurs, then replace the commit with a rollback, and no changes will have been made to the db.
When working with Postgres, this is actually a good rule of thumb to follow anyway.
Related
I am trying to execute an stored procedures inside an Oracle database :
x_pkg.get_xID
It require one input & will output a single string
I already tried several different options that I found in internet :
$val = 'DATABASE';
$result = new ResultSetMapping ();
$query = $entityManager -> createNativeQuery ("BEGIN x_pkg.get_xID(${val}, :cursor); END;", $result);
In this case I get error : ORA-01008: not all variables bound (500 Internal Server Error)
$query = $entityManager -> createNativeQuery ("CALL x_pkg.get_xID(:data)", $result);
$query -> setParameters (['data' => $val]);
In this case I get error : ORA-06553: PLS-306: wrong number or types of arguments in call to 'GET_XID' (500 Internal Server Error)
$query = $entityManager -> createNativeQuery ("CALL x_pkg.get_xID(${val})", $result);
In this case I get error : ORA-06576: not a valid function or procedure name (500 Internal Server Error)
Thank you for your help.
I can help you explain why you get these errors and then it might help you to find the solution to solve the problem,
And just keep it in mind, the Oracle database is a bit tricky and different than other community used database such as MySQL, it has it's own power and strict rules,
**I will explain the first case at the end.*
So, in your second case, you get that error because Oracle expect the OUT variable to be a part of your Call which is not the case in your code and because it is inside the procedure
In your third case, using ${val} is not valid even if it's valid for PHP itself, the Oracle database see it in other way, so this is not an option for you,
Now about the first case, you should make sure that your procedure is returning a cursor and not a variable, I think you should check it in your Oracle database and also in your next line of code where you execute your query (it's not posted here so I can't be sure about it), this is a tricky part of Oracle database, you should make sure what your procedure is returning to avoid the error,
And good luck :)
This question already has answers here:
Getting raw SQL query string from PDO prepared statements
(16 answers)
Closed 6 years ago.
In PHP, when accessing MySQL database with PDO with parametrized query, how can you check the final query (after having replaced all tokens)?
Is there a way to check what gets really executed by the database?
So I think I'll finally answer my own question in order to have a full solution for the record. But have to thank Ben James and Kailash Badu which provided the clues for this.
Short Answer
As mentioned by Ben James: NO.
The full SQL query does not exist on the PHP side, because the query-with-tokens and the parameters are sent separately to the database.
Only on the database side the full query exists.
Even trying to create a function to replace tokens on the PHP side would not guarantee the replacement process is the same as the SQL one (tricky stuff like token-type, bindValue vs bindParam, ...)
Workaround
This is where I elaborate on Kailash Badu's answer.
By logging all SQL queries, we can see what is really run on the server.
With mySQL, this can be done by updating the my.cnf (or my.ini in my case with Wamp server), and adding a line like:
log=[REPLACE_BY_PATH]/[REPLACE_BY_FILE_NAME]
Just do not run this in production!!!
You might be able to use PDOStatement->debugDumpParams. See the PHP documentation .
Using prepared statements with parametrised values is not simply another way to dynamically create a string of SQL. You create a prepared statement at the database, and then send the parameter values alone.
So what is probably sent to the database will be a PREPARE ..., then SET ... and finally EXECUTE ....
You won't be able to get some SQL string like SELECT * FROM ..., even if it would produce equivalent results, because no such query was ever actually sent to the database.
I check Query Log to see the exact query that was executed as prepared statement.
I initially avoided turning on logging to monitor PDO because I thought that it would be a hassle but it is not hard at all. You don't need to reboot MySQL (after 5.1.9):
Execute this SQL in phpMyAdmin or any other environment where you may have high db privileges:
SET GLOBAL general_log = 'ON';
In a terminal, tail your log file. Mine was here:
>sudo tail -f /usr/local/mysql/data/myMacComputerName.log
You can search for your mysql files with this terminal command:
>ps auxww|grep [m]ysqld
I found that PDO escapes everything, so you can't write
$dynamicField = 'userName';
$sql = "SELECT * FROM `example` WHERE `:field` = :value";
$this->statement = $this->db->prepare($sql);
$this->statement->bindValue(':field', $dynamicField);
$this->statement->bindValue(':value', 'mick');
$this->statement->execute();
Because it creates:
SELECT * FROM `example` WHERE `'userName'` = 'mick' ;
Which did not create an error, just an empty result. Instead I needed to use
$sql = "SELECT * FROM `example` WHERE `$dynamicField` = :value";
to get
SELECT * FROM `example` WHERE `userName` = 'mick' ;
When you are done execute:
SET GLOBAL general_log = 'OFF';
or else your logs will get huge.
What I did to print that actual query is a bit complicated but it works :)
In method that assigns variables to my statement I have another variable that looks a bit like this:
$this->fullStmt = str_replace($column, '\'' . str_replace('\'', '\\\'', $param) . '\'', $this->fullStmt);
Where:
$column is my token
$param is the actual value being assigned to token
$this->fullStmt is my print only statement with replaced tokens
What it does is a simply replace tokens with values when the real PDO assignment happens.
I hope I did not confuse you and at least pointed you in right direction.
The easiest way it can be done is by reading mysql execution log file and you can do that in runtime.
There is a nice explanation here:
How to show the last queries executed on MySQL?
I don't believe you can, though I hope that someone will prove me wrong.
I know you can print the query and its toString method will show you the sql without the replacements. That can be handy if you're building complex query strings, but it doesn't give you the full query with values.
I think easiest way to see final query text when you use pdo is to make special error and look error message. I don't know how to do that, but when i make sql error in yii framework that use pdo i could see query text
I need to execute two SQL statements together because connection_id() in the first statement will be used in the Mysql view wp_statistics_benchmarks.
Without the connection_id(), the wp_statistics_benchmarks is an empty view. The following SQL works fine and get results:
replace into wp_params (`view_name` , `param1_val`, `connection_id`)
values ('benchmarks', 484 , connection_id())
;
select * from wp_statistic_benchmarks;
But, to work with wordpress, the following code doesn't work:
$mysqli = new mysqli(.....);
$results = $this->_wpdb->query("
replace into wp_params (`view_name`, `param1_val`, `connection_id`)
values ('benchmarks', $connected_from, $mysqli->thread_id);
select * FROM `wp_statistic_benchmarks`;"
);
How can I convert these two mysql codes into Wordpress wpdb queries?
Use the wpdb object twice.
$this->_wpdb->query('replace into ...');
$rows = $this->_wpdb->get_results('select ...')
Let me put it another way, select * from wp_stat ... and replace into wp_params ... from your original "mysql codes" are separate statements without any relation to each other.
You think that you need to run them in sequence, whereas in fact you can have a cup of coffee or even travel around the earth in between those replace into and select statements and they would still do the same thing. If that is not the case, then your question lacks information necessary to provide a good answer because wp_params is not a standard table in wordpress and neither is the view. I don't think you understand your problem.
Besides, running them as I suggest is equivalent with your "mysql codes". Moreover, $wpdb->query returns the number of affected rows or false, so you will never be able to run a select statement with $wpdb->query() to retrieve a set of tuples.
How can I convert these two mysql codes into Wordpress wpdb queries?
You can't. That's because you're using wpdb and it only supports one query per ->query() call. However, if you're using Mysqli with wpdb, you can use the multi_query() method of it with wpdb. Here is how:
To use multiple queries, you need to ensure that wpdb uses Mysqli (e.g. define the USE_EXT_MYSQL constant as FALSE in your Wordpress config).
Then you can obtain the mysqli instance from the wpdb object, either with reflection or a helper class/module:
abstract class wpdb_dbh extends wpdb
{
static function from(wpdb $wpdb) {
return $wpdb->dbh;
}
}
Mysqli is then available without creating a new instance:
$mysqli = wpdb_dbh::from($this->_wpdb);
As this is a valid Mysqli instance you can run multi query.
But just obtaining the same Mysqli instance as wpdb uses it probably the most important thing here as otherwise your open an additional connection with new mysqli(...) which you need to prevent.
Additionally take care that $mysqli->thread_id is a fitting replacement to connection_id() following the same formatting/encoding. You should be able to use connection_id() directly anyway, so I actually see not much reason to access the thread_id member, but it's perhaps only because you tried some alternatives and I'm just over-cautious.
The ';' query delimiter is purely an SQL shell convenience and is not a part of the MySQL dialect so you're correct that your code doesn't work.
Here's the actual replacement code:
$mysqli = new mysqli(.....);
$this->_wpdb->query(
"replace into wp_params
(`view_name`, `param1_val`, `connection_id`)
values ('benchmarks', $connected_from, $mysqli->thread_id)");
$results = $this->_wpdb->query("select * FROM `wp_statistic_benchmarks`");
This is the same as Ярослав's answer above.
Update:
If your code is still not working you might have to enable persistent connections in Wordpress.
Update 2:
There was a missing space between in the second query's select statement and the * shorthand all columns selector. Interestingly this may or may not cause an issue for you, it doesn't seem to bother my MySQL 5.5 command line shell.
If I understand your requirements (and I do not know wordpress), you are inserting a row to wp_params with a column called connection_id. I would assume that this value will be unique on the table. I would be tempted to add an integer autoincrement id field to the table and then get the value of that (last insert id). Then use this id in a WHERE clause when selecting from the view.
I'm using PHP ODBC library to connect to a MSSQL 2008 server (http://php.net/manual/en/ref.uodbc.php).
Some of my stored procedures do not return record sets (e.g. they just do an insert or update). I would like to be able to handle output gracefully in this situation. After the database call is made, the output is injected into an array which is returned to the application for processing. Here are the key parts of the code (excluding error handling etc):
$sql_result = odbc_exec($connection, $sql);
while ($row = odbc_fetch_array($sql_result)) {
$resultArray[$i] = $row;
$i++;
}
If $sql_result has executed successfully, but does not contain a record set (as it would following an insert or update) then odbc_fetch_array triggers this warning:
Warning: odbc_fetch_row(): No tuples available at this result index
Ideally, I'd like to test $sql_result first to see if it contains an empty record set, but every obvious attempt I've tried always leads to the same warning message.
Anyone got a neat way of checking to see if $sql_result is empty?
I don't think there is a simple way using the PHP odbc API. Usually you would use different functions to process statements that return values such as SELECT vs those like UPDATE that do not.
If this is a utility that runs arbitrary statements you could parse the statement.
This isn't an empty result set, it's no result set at all, you might be able to tell the difference by examining the result in a debugger or using var_dump.
This question already has answers here:
Getting raw SQL query string from PDO prepared statements
(16 answers)
Closed 6 years ago.
In PHP, when accessing MySQL database with PDO with parametrized query, how can you check the final query (after having replaced all tokens)?
Is there a way to check what gets really executed by the database?
So I think I'll finally answer my own question in order to have a full solution for the record. But have to thank Ben James and Kailash Badu which provided the clues for this.
Short Answer
As mentioned by Ben James: NO.
The full SQL query does not exist on the PHP side, because the query-with-tokens and the parameters are sent separately to the database.
Only on the database side the full query exists.
Even trying to create a function to replace tokens on the PHP side would not guarantee the replacement process is the same as the SQL one (tricky stuff like token-type, bindValue vs bindParam, ...)
Workaround
This is where I elaborate on Kailash Badu's answer.
By logging all SQL queries, we can see what is really run on the server.
With mySQL, this can be done by updating the my.cnf (or my.ini in my case with Wamp server), and adding a line like:
log=[REPLACE_BY_PATH]/[REPLACE_BY_FILE_NAME]
Just do not run this in production!!!
You might be able to use PDOStatement->debugDumpParams. See the PHP documentation .
Using prepared statements with parametrised values is not simply another way to dynamically create a string of SQL. You create a prepared statement at the database, and then send the parameter values alone.
So what is probably sent to the database will be a PREPARE ..., then SET ... and finally EXECUTE ....
You won't be able to get some SQL string like SELECT * FROM ..., even if it would produce equivalent results, because no such query was ever actually sent to the database.
I check Query Log to see the exact query that was executed as prepared statement.
I initially avoided turning on logging to monitor PDO because I thought that it would be a hassle but it is not hard at all. You don't need to reboot MySQL (after 5.1.9):
Execute this SQL in phpMyAdmin or any other environment where you may have high db privileges:
SET GLOBAL general_log = 'ON';
In a terminal, tail your log file. Mine was here:
>sudo tail -f /usr/local/mysql/data/myMacComputerName.log
You can search for your mysql files with this terminal command:
>ps auxww|grep [m]ysqld
I found that PDO escapes everything, so you can't write
$dynamicField = 'userName';
$sql = "SELECT * FROM `example` WHERE `:field` = :value";
$this->statement = $this->db->prepare($sql);
$this->statement->bindValue(':field', $dynamicField);
$this->statement->bindValue(':value', 'mick');
$this->statement->execute();
Because it creates:
SELECT * FROM `example` WHERE `'userName'` = 'mick' ;
Which did not create an error, just an empty result. Instead I needed to use
$sql = "SELECT * FROM `example` WHERE `$dynamicField` = :value";
to get
SELECT * FROM `example` WHERE `userName` = 'mick' ;
When you are done execute:
SET GLOBAL general_log = 'OFF';
or else your logs will get huge.
What I did to print that actual query is a bit complicated but it works :)
In method that assigns variables to my statement I have another variable that looks a bit like this:
$this->fullStmt = str_replace($column, '\'' . str_replace('\'', '\\\'', $param) . '\'', $this->fullStmt);
Where:
$column is my token
$param is the actual value being assigned to token
$this->fullStmt is my print only statement with replaced tokens
What it does is a simply replace tokens with values when the real PDO assignment happens.
I hope I did not confuse you and at least pointed you in right direction.
The easiest way it can be done is by reading mysql execution log file and you can do that in runtime.
There is a nice explanation here:
How to show the last queries executed on MySQL?
I don't believe you can, though I hope that someone will prove me wrong.
I know you can print the query and its toString method will show you the sql without the replacements. That can be handy if you're building complex query strings, but it doesn't give you the full query with values.
I think easiest way to see final query text when you use pdo is to make special error and look error message. I don't know how to do that, but when i make sql error in yii framework that use pdo i could see query text