What is the correct way to execute this code in Yii2. I get oci_new_cursor() expects parameter 1 to be resource, object given.
// get DB instance
$connection = Yii::$app->db;
// set cursor
$refcur = oci_new_cursor($connection);
$q = "BEGIN :RC := REPORT_CARDS.GET_DATA(:I_YEAR); END;";
...
There are some important facts to keep in mind:
Yii uses PDO
PDO and OCI8 are completely different extensions and you cannot mix their use
the PDO driver for Oracle databases (PDO_OCI) has limitations; for instance it seems that cursors aren't really supported and its use is in general not really recommended
see also this example of attempted cursor use with PDO
You can get the PDO instance used by Yii with \Yii::$app->db->pdo, but as per point 2 above, this does not help you with the OCI8 functions you are trying to use in your example. As per point 3, it further does not seem a great idea to commit resources to learning to use PDO just to replace OCI8.
Still, if you want to give the 'Yii way' another shot for those problems that it can still solve, you can try and see how far you get with yii\db\Command. The PDO counterpart for oci_bind_by_name() you refer to in your comment is PDOStatement::bindParam which is basically proxied by yii\db\Command::bindParam. So, a very basic use example for a custom-built SQL query would be something like
// $var1 and $var2 somewhere
$command = \Yii::$app->db->createCommand('some query with :bound :values');
$command->bindParam(':bound', $var1, \PDO::PARAM_STR);
$command->bindParam(':values', $var2, \PDO::PARAM_STR || \PDO::PARAM_INPUT_OUTPUT);
$command->execute();
I can't really test with your specific example, and based on what I've read I can't guarantee success if you try for yourself, but I wish you luck with the exploration. If it falls short of success, then I don't see an easy way around it; you'll just have to use a separate connection of your own, manually initialized with oci_connect or whatever, and then operate as usual through OCI8.
Related
I have used mysql_query() throughout my project; but I've just learned that mysql_ was deprecated as of PHP 5.5, has been removed in PHP 7.
So, I would like to know if I can replace all mysql_ functions with mysqli_ in my project blindly? For example, just replacing mysql_query() with mysqli_query(). Is there any adverse effect?
The short answer is no, the functions are not equivalent.
The good news is there is a converter tool that will help you if you've got a lot of calls/projects to change. This will allow your scripts to work right away.
https://github.com/philip/MySQLConverterTool
It's a forked version of the Oracle original version, and it's kosher.
That said, it's not too difficult to update your code, and you might want to migrate to an object orientated methodology anyway ...
1) The Connection
For all intents and purposes, you need a new connection function that saves the connection as a PHP variable, for example;
$mysqli = new mysqli($host, $username, $password, $database);
Notice I've saved the connection to $mysqli. You can save to $db or whatever you like, but you should use this throughout your code to reference the connection.
Remember to enable error reporting for mysqli before opening the connection;
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
2) The Query
Note: You should protect against SQL injection with prepared statements, which are available in MySQLi. Take a look at How can I prevent SQL injection in PHP?, but I'm just going to cover the basics here.
You now have to include the connection as an argument in your query, and other mysqli_ functions. In procedural code it's the first argument, in OO you write it like a class method.
Procedural:
$result = mysqli_query($mysqli, $sql);
OO:
$result = $mysqli->query($sql);
3) Fetch Result
The fetching of the result is similar to the old mysql_ function in procedural;
while ($row = mysqli_fetch_assoc($result))
but as $result is now an object in mysqli, you can use the object function call;
while ($row = $result->fetch_assoc())
4) Close Connection
So as before, you need to include the connection in the close function; as an argument in procedural;
mysqli_close($mysqli);
and as the object that you run the function on in OO;
$mysqli->close();
I would be here forever if I went through them all, but you get the idea. Take a look at the documentation for more information. Don't forget to convert any connection close, result release, or error and row counting functions you have.
The basic rule of thumb is for functions that use the database connection, you need to include it in the function now (either as the first argument in procedural, or the object you use to call the function in OO), or for a result set you can just change the function to mysqli_ or use the result set as the object.
If you cannot convert all calls to the mysqli functions on a old project, you could install and include the library php7-mysql-shim.
It will try to create a transparent replacement for mysql on PHP 7 using mysqli.
Obviously the performance is slower, but it's a solution to get around the problem in a couple of minutes.
You may safely include the library in projects working with PHP 5.6 (it will be ignored).
if (defined('PHP_VERSION_ID') && (PHP_VERSION_ID >= 50600)) { require_once "mysql-shim.php"; }
You can't. some of the functions of mysql and mysqli require different parameters. So you should know which will use the same parameters.
The question is a fairly open one. I've been using Stored Procs with MS SQLServer for some time with classic ASP and ASP.net and love them, lots.
I have a small hobby project I'm working on and for various reasons have gone the LAMP route. Any hints/tricks/traps or good starting points to get into using stored procedures with MySQL and PHP5? My version of MySQL supports Stored Procedures.
#michal kralik - unfortunately there's a bug with the MySQL C API that PDO uses which means that running your code as above with some versions of MySQL results in the error:
"Syntax error or access violation: 1414 OUT or INOUT argument $parameter_number for routine $procedure_name is not a variable or NEW pseudo-variable".
You can see the bug report on bugs.mysql.com. It's been fixed for version 5.5.3+ & 6.0.8+.
To workaround the issue, you would need to separate in & out parameters, and use user variables to store the result like this:
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(:in_string, #out_string)");
$stmt->bindParam(':in_string', 'hello');
// call the stored procedure
$stmt->execute();
// fetch the output
$outputArray = $this->dbh->query("select #out_string")->fetch(PDO::FETCH_ASSOC);
print "procedure returned " . $outputArray['#out_string'] . "\n";
Forget about mysqli, it's much harder to use than PDO and should have been already removed. It is true that it introduced huge improvements over mysql, but to achieve the same effect in mysqli sometimes requires enormous effort over PDO i.e. associative fetchAll.
Instead, take a look at PDO, specifically
prepared statements and stored procedures.
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// call the stored procedure
$stmt->execute();
print "procedure returned $value\n";
It isn't actually mandatory to use mysqli or PDO to call stored procedures in MySQL 5. You can call them just fine with the old mysql_ functions. The only thing you can't do is return multiple result sets.
I've found that returning multiple result sets is somewhat error prone anyway; it does work in some cases but only if the application remembers to consume them all, otherwise the connection is left in a broken state.
You'll need to use MySQLI (MySQL Improved Extension) to call stored procedures. Here's how you would call an SP:
$mysqli = new MySQLI(user,pass,db);
$result = $mysqli->query("CALL sp_mysp()");
When using SPs you'll need close first resultset or you'll receive an error. Here's some more information :
http://blog.rvdavid.net/using-stored-procedures-mysqli-in-php-5/
(broken link)
Alternatively, you can use Prepared Statements, which I find very straight-forward:
$stmt = $mysqli->prepare("SELECT Phone FROM MyTable WHERE Name=?");
$stmt->bind_param("s", $myName);
$stmt->execute();
MySQLI Documentation: http://no.php.net/manual/en/book.mysqli.php
I have been using ADODB, which is a great thing for abstracting actual commands to make it portable between different SQL Servers (ie mysql to mssql). However, Stored procedures do not appear to be directly supported. What this means, is that I have run a SQL query as if it is a normal one, but to "call" the SP.
An example query:
$query = "Call HeatMatchInsert('$mMatch', '$mOpponent', '$mDate', $mPlayers, $mRound, '$mMap', '$mServer', '$mPassword', '$mGame', $mSeason, $mMatchType)";
This isn't accounting for returned data,which is important. I'm guessing that this would be done by setting a #Var , that you can select yourself as the return #Variable .
To be Abstract though, although making a first php stored procedure based web app was very difficult to work around (mssql is very well documented, this is not), It's great after its done - changes are very easy to make due to the seperation.
I'm using PHP 5.3.6 with PDO to access Postgres 9.0.4. I've been asked to reduce the memory footprint of a report. The current implementation is simple: execute the query, do a fetchAll() and then iterate with foreach() through the resulting array. This obviously doesn't scale with huge result sets: it can temporarily consume 100MB or more.
I have a new implementation which takes the PDO statement handle and then iterates directly on it using foreach(), i.e. no intermediate array via fetchAll(). (From what I've read, iterating a statement handle with foreach calls fetch() under the covers.) This is just as fast and consumes way less memory: about 28kB. Still, I'm not confident I'm doing it right because, although I've done a ton of Googling, it's tough to find answers to basic questions about this:
I've seen articles that suggest solving my original problem using cursors. Does the Postgress PDO driver already use cursors internally? If writing my own SQL to create a cursor is required, I'm willing to but I'd prefer to write the simplest code possible (but no simpler!).
If foreach calls fetch() each iteration, isn't that too network chatty? Or is it smart and fetches many rows at once, e.g. 500, to save bandwidth? (This may imply that it uses cursors internally.)
I've seen an article that wraps the statement handle in a class that implements Iterator interface. Isn't this redundant given that a PDO statement handle already does this? Or am I missing something?
My call to prepare the SQL statement looks like this:
$sth = $dbh->prepare($sql);
I found that it made no memory or speed difference if I did this:
$sth = $dbh->prepare($sql, array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );
Is this because this is the default anyway for the Postgres PDO driver? This would make sense if it is already using cursors internally.
General comments about the approach and other ways to solve this problem are welcome.
PDO for Postgres does use cursors internally.
Apparently PDO::CURSOR_FWDONLY does not use cursors. Black box tests:
(0) Preparations:
$con = new \PDO('dsn');
// you'll get "NO ACTIVE TRANSACTION" otherwise
$con->beginTransaction();
$sql = 'select * from largetable';
(1) Default - takes forever:
$stmt = $con->prepare($sql);
$stmt->execute();
print_r($stmt->fetch());
(2) FWDONLY - takes forever:
$stmt = $con->prepare($sql, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY));
$stmt->execute();
print_r($stmt->fetch());
(3) SCROLLABLE - runs in a flash:
$stmt = $con->prepare($sql, array(\PDO::ATTR_CURSOR => \PDO::CURSOR_SCROLL));
$stmt->execute();
print_r($stmt->fetch());
I turned on PG logging just to be sure and it is indeed so - only SCROLL uses cursors.
So, the only way to make use of cursors is to use SCROLL, at least in PHP 5.4.23.
This is a terrible question because I don't have a simple way to reproduce it. However, I'm using the Zend Framework to connect to my MySQL database on OS X. Sometimes a call to the prepare function on a mysqli object returns null. The stated return values for the prepare function are false or a statement object.
I can't figure out where else to look for info on why the prepare statement is failing. Is there any way to get visibility into the prepare process to see why it is failing? All of my problems are coming up while a transaction is open.
Sorry for the lack of specifics, but I really can't nail down why this is happening.
Just to correct ToughPal, you should be using:
mysqli_query($db, "INSERT INTO table (variable1, variable2) VALUES (hello, mynameis);
Remember that you need to have the db connection defined and stated in the query first, before your actual SQL.
Remember to enclose the table name, column names and value data in backtick escapes.
Example prepared statement
$result = $db->query( 'INSERT INTO server (key, value) VALUES (:key, :value)',
array('key' => $foo, 'value' => $bar)
Can you let us know your DB query?
Try and execute your DB query with test data and see if the query works fine to start with. If the query is ok then we can look why the code fails.
Well I managed to find the issue over the weekend but was really only able to fix the symptoms and not the cause.
I didn't include any SQL in the original issue because the problem was happening randomly, the same code would sometimes work and sometimes not. The issue looks like it was a memory pointer problem. Whenever I had a problem Zend Debugger told me that I had a mysqli object. I believe this because otherwise I would've gotten an error when trying to run the prepare function on it. I have a singleton object that acts as a container for my mysqli connection but whenever the prepare function failed, === showed that the mysqli being used was not the same as the mysqli connection in my singleton object.
In the end, Zend Framework's only issue is that it doesn't fail if the the prepare function returns null. If you are seeing this problem use === to verify that the connection is actually the same as the one that you've previously initiated.
if you're doing something like this
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$query = "...";
$mysqli->prepare($query);
then you can inspect mysqli::$error next to see useful errors about why prepare() failed
print_r($mysqli->error);
The question is a fairly open one. I've been using Stored Procs with MS SQLServer for some time with classic ASP and ASP.net and love them, lots.
I have a small hobby project I'm working on and for various reasons have gone the LAMP route. Any hints/tricks/traps or good starting points to get into using stored procedures with MySQL and PHP5? My version of MySQL supports Stored Procedures.
#michal kralik - unfortunately there's a bug with the MySQL C API that PDO uses which means that running your code as above with some versions of MySQL results in the error:
"Syntax error or access violation: 1414 OUT or INOUT argument $parameter_number for routine $procedure_name is not a variable or NEW pseudo-variable".
You can see the bug report on bugs.mysql.com. It's been fixed for version 5.5.3+ & 6.0.8+.
To workaround the issue, you would need to separate in & out parameters, and use user variables to store the result like this:
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(:in_string, #out_string)");
$stmt->bindParam(':in_string', 'hello');
// call the stored procedure
$stmt->execute();
// fetch the output
$outputArray = $this->dbh->query("select #out_string")->fetch(PDO::FETCH_ASSOC);
print "procedure returned " . $outputArray['#out_string'] . "\n";
Forget about mysqli, it's much harder to use than PDO and should have been already removed. It is true that it introduced huge improvements over mysql, but to achieve the same effect in mysqli sometimes requires enormous effort over PDO i.e. associative fetchAll.
Instead, take a look at PDO, specifically
prepared statements and stored procedures.
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// call the stored procedure
$stmt->execute();
print "procedure returned $value\n";
It isn't actually mandatory to use mysqli or PDO to call stored procedures in MySQL 5. You can call them just fine with the old mysql_ functions. The only thing you can't do is return multiple result sets.
I've found that returning multiple result sets is somewhat error prone anyway; it does work in some cases but only if the application remembers to consume them all, otherwise the connection is left in a broken state.
You'll need to use MySQLI (MySQL Improved Extension) to call stored procedures. Here's how you would call an SP:
$mysqli = new MySQLI(user,pass,db);
$result = $mysqli->query("CALL sp_mysp()");
When using SPs you'll need close first resultset or you'll receive an error. Here's some more information :
http://blog.rvdavid.net/using-stored-procedures-mysqli-in-php-5/
(broken link)
Alternatively, you can use Prepared Statements, which I find very straight-forward:
$stmt = $mysqli->prepare("SELECT Phone FROM MyTable WHERE Name=?");
$stmt->bind_param("s", $myName);
$stmt->execute();
MySQLI Documentation: http://no.php.net/manual/en/book.mysqli.php
I have been using ADODB, which is a great thing for abstracting actual commands to make it portable between different SQL Servers (ie mysql to mssql). However, Stored procedures do not appear to be directly supported. What this means, is that I have run a SQL query as if it is a normal one, but to "call" the SP.
An example query:
$query = "Call HeatMatchInsert('$mMatch', '$mOpponent', '$mDate', $mPlayers, $mRound, '$mMap', '$mServer', '$mPassword', '$mGame', $mSeason, $mMatchType)";
This isn't accounting for returned data,which is important. I'm guessing that this would be done by setting a #Var , that you can select yourself as the return #Variable .
To be Abstract though, although making a first php stored procedure based web app was very difficult to work around (mssql is very well documented, this is not), It's great after its done - changes are very easy to make due to the seperation.