CodeIgniter - cannot execute procedure with couple UPDATE statements - php

Have an issue with executing routines in CodeIgniter.
I have a routine that just updates couple mysql tables with the data specified in parameters.
Originally I received:
Error Number: 2014
Commands out of sync; you can’t run this command now
Tried the solution specified at http://codeigniter.com/forums/viewthread/96583/
$this->mydb->Query($sql);
with changed driver to mysqli
It works fine with the select statements for me but if the routine has only couple updates - it does not work.
The problem is that there is no error message is returned. It behaves like it is successfully run, but tables are not updated.
NOTE: there should not be an issue with routine itself since if I print the query in question and try to execute this in MySQL Workbench - tables are updated correctly.
Any advises are appreciated.

Try changing the dbdriver in the config file to mysqli:
$db['default']['dbdriver'] = "mysqli";

$this->mydb->Query used in the whole project for each query has solved the issue

function call( $procedure )
{
$result = #$this->db->conn_id->query( $procedure );
while ( $this->db->conn_id->next_result() )
{
//free each result.
$not_used_result = $this->db->conn_id->use_result();
if ( $not_used_result instanceof mysqli_result )
{
$not_used_result->free();
}
}
return $result;
}

Related

mysqli_commit fails when select statement is added

Problem:
Unable to store data with mySQL stored procedure with mysqli_begin_transaction.
Details:
The below code will do simple insert and select using mysql stored procedure. Code runs fine without select statement. However once the select statement is added, it won't commit any data even the query returns success at PHP side.
Snippets (PHP):
$DB_DRRM_SQLI = mysqli_connect("localhost","root","", "sandbox_db");
mysqli_begin_transaction($DB_DRRM_SQLI);
$SQL_QUERY_CODE = "CALL SANDBOX_TEST()";
$DB_QUERY = mysqli_query($DB_DRRM_SQLI, $SQL_QUERY_CODE);
// ERROR REPORTING
if($DB_QUERY === false)
{
echo mysqli_error($DB_DRRM_SQLI);
mysqli_rollback($DB_DRRM_SQLI);
}
else
{
echo 'success';
mysqli_commit($DB_DRRM_SQLI);
}
exit;
Snippets (mySQL Stored procedure):
BEGIN
INSERT INTO
`sandbox_table`
(
`SOME_STRING`
)
VALUES
(
'ABCDEFGHIJKL...'
);
SELECT
LAST_INSERT_ID() AS INSERTED_ID,
'ABCDE...' AS OTHER_PARAMS;
END
Database (Table sandbox_table):
RECORD_PRIMARY_ID (Int - Auto increment)
SOME_STRING (Varchar - 500 length)
Spec:
PHP version: 5.6.14
10.1.8-MariaDB
Storage Engine: InnoDB
Notes:
If transaction is made at stored procedure works fine, but I need a PHP managed transaction to handle multiple query requests and response depending on the result of query.
(It can be a possible last resort if there's no other solution, where I need to convert whole PHP code to stored procedure and need pass tons of parameter)
Methods Tested:
Tried with other PHP version 7.0.9 with same result (10.1.16-MariaDB)
Tested with new database with no other data except sandbox_tableand above stored procedure.
Tested without additional include libraries (tested with purely on above snippets).
Solution:
It was caused by Commands out of sync error at mysqli_commit. Seems the mysqli won't allow committing transaction while the query is open, which happens if you add select statement to above stored procedure.
So to handle this, it must close the query first or put the query to buffer.
Snippets (PHP):
// SQL Database
$DB_DRRM_SQLI = mysqli_connect("localhost","root","", "sandbox_db");
mysqli_begin_transaction($DB_DRRM_SQLI);
$SQL_QUERY_CODE = "CALL SANDBOX_TEST()";
$DB_QUERY = mysqli_query($DB_DRRM_SQLI, $SQL_QUERY_CODE);
// ERROR REPORTING
if($DB_QUERY === false)
{
echo mysqli_error($DB_DRRM_SQLI);
mysqli_rollback($DB_DRRM_SQLI);
}
else
{
// Must free current query result before committing transaction
#mysqli_free_result($DB_QUERY);
#mysqli_next_result($DB_DRRM_SQLI);
if(mysqli_commit($DB_DRRM_SQLI) === false)
{
echo mysqli_error($DB_DRRM_SQLI);
}
else
{
echo 'success';
}
}
exit;

PHP PDO SQL - update inner join query freezes during execution

I need to run a daily PHP script that downloads a data file and executes a bunch of SQL Queries in sequence to import and optimize the data.
I'm having a problem executing one of my queries within PHP which appears to freeze the mysqld process on my server. Oddly, running the same query does not case a similar problem when run from the Sequel Pro Database client program (Mac).
The query is running an update on a large table with over a million rows. Here is the stored procedure I'm using:
DELIMITER ;;
CREATE PROCEDURE spSetTripIdInStopTimes()
BEGIN
-- SET META_TRIP_ID IN IMPORT_STOP_TIMES
UPDATE import_stop_times
INNER JOIN ref_trips ON
(
import_stop_times.trip_id = ref_trips.trip_id
AND import_stop_times.meta_agency_id =ref_trips.meta_agency_id
)
SET import_stop_times.meta_trip_id = ref_trips.meta_trip_id;
END;;
DELIMITER ;
When the procedure is called with
CALL spSetTripIdInStopTimes;
inside Sequel Pro, the result is 1241483 rows affected and the time taken is around 90 seconds.
With PHP PDO I run the same command with
$result = $database->runExecQuery("CALL spSetTripIdInStopTimes");
However, it gets stuck on this query for over 24 hrs and still has not completed. When I cancel the PHP script I can see that the mysqld process is still taking %99.5 CPU. At this point I restart SQL with 'sudo service mysql restart'.
I also tried using PHP's mysqli, but the freezing also occurs with this method.
$mysqli->query("CALL spSetTripIdInStopTimes")
Would anyone be able to reason why this is happening or suggest another method?
Thank you in advance.
Note: I also tried using the older mysql on PHP, but the version I'm using (5.5.9-1ubuntu4.14) tells me the command is deprecated and stops the script.
[UPDATE]
I've also tried running the stored procedure directly on the command line:
mysql --user=[username] --password=[password] --execute="call spSetTripIdInStopTimes()" [tablename]
which worked.
So I tried running the same command with PHP's exec() function:
exec("mysql --user=[username] --password=[password] --execute=\"call spSetTripIdInStopTimes()\" [table name]");
Unfortunately, it stills hangs. I'm starting to wonder if this is due to the limitation or overhead of PHP.
[UPDATE 2]
Here is the array of PHP PDO connection options I use:
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// Allow file reading, need following settings to import data from txt files
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
PDO::ATTR_EMULATE_PREPARES => true)
[UPDATE 3]
I'm using a custom database object, so I'll show the function for $database->runExecQuery() for clarification:
function runExecQuery($queryString)
{
$db = $this-> getConnection(); // Connect to database
try{
return array(
"success"=> true,
"data"=>$db->exec($queryString)
);
}
catch (PDOException $ex)
{
return array(
"success"=> false,
"errMessage"=> "ERROR[{$ex->getCode()}]".($this-> Debug ? "{$ex}" : "")
);
}
}
The variable $db is the connection variable that is initialized as follows:
// Create address string
$db_address =
"mysql:host={$settings['db_hostname']};".
"dbname={$settings['db_name']};".
"charset={$settings['db_charset']}";
// Create connection to database
$db = new PDO($db_address, $settings['db_user'], $settings['db_pw'], $options);
where $options is the array from [Update 2].
[Update 4]
Mihai's suggestion of changing PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false had some promising results as query appeared to finish. However, after more testing I found that the PHP script will sometimes still hang on the Query about 50% of the time it is run. This is true even with the same set of data in the SQL tables.

PHP/MSSQL/SQL Profiler: not executing incoming SQL

I have a very simple INSERT statement that I can run using SSMS. When I run the same INSERT statement using PHP mssql_execute or mssql_query SQL profiler shows me that the 'TextData' is identical when sent in by PHP as it is when sent in by SSMS. The problem is when executed via the PHP code, the INSERT never actually happens, whereas when run from within SSMS, it inserts just fine. Any ideas?
MS SQL: 2008 R2
PHP: 5.4, freetds 8.0
PHP error:
PHP Warning: mssql_execute(): message: Internal Query Processor Error: The query processor could not produce a query plan. For more information, contact Customer Support Services. (severity 16) in /home/...
Edit: PHP relevant PHP added
<?php
putenv('FREETDS=/home/###/freetds.conf');
putenv('FREETDSCONF=/home/###/freetds.conf');
$link = mssql_connect('mssqlserver', '###','###'); // connect
if ( !$link ) {
if ( function_exists('error_get_last') ) {
var_dump(error_get_last());
}
die('connection failed');
}
// Create a new statement
$stmt = mssql_init('Db.dbo.SprocName');
// Some values
$a = 1;
$b = 'test';
$c = 'myname';
// Bind values
mssql_bind($stmt,'#a',$a,SQLINT2,false,false);
mssql_bind($stmt,'#b',$b,SQLVARCHAR,false,false,8000);
mssql_bind($stmt,'#c',$c,SQLVARCHAR,false,false,50);
// Execute the statement
mssql_execute($stmt);
// And we can free it like so:
mssql_free_statement($stmt);
?>
The stored procedure (Db.dbo.SprocName) did a simple insert on a table, lets call it (Db.dbo.TableName). When I removed the foreign key from Db.dbo.TableName then the PHP mssql INSERT calls started working.
I realize this technically resolves the issue, but in practice its not acceptable. Those FK's are there for a reason :). Any thoughts?

Executing SQL directly; no cursor in PHP when calling a stored procedure

I'm getting the following error when trying to execute a stored procedure from PHP using sqlsrv driver:
Executing SQL directly; no cursor
Add a cursor option to your connection:
$connection = odbc_connect('host','username','password', 1)
or die('Connection failed!');
After password insert cursor_option 1 <-- this option was missing.
I got the same error when I used code that basically did this:
$options = array( "Scrollable"=>SQLSRV_CURSOR_STATIC);
$sql = "exec dbs_webgetnextcount 'expense'";
sqlsrv_query($db,$sql,null,$options);
I fixed it by not setting the cursor.
$sql = "exec dbs_webgetnextcount 'expense'";
sqlsrv_query($db,$sql);
PS. I was doing the CURSOR_STATIC option on my select statements so that sqlsrv_num_rows() would give a correct number.
I had the same problem as Jon but I figured since it is just a warning generated by the sql data access component and the query still completes successfully you can disable it in sqlsrv.exe using sqlsrv_configure("WarningsReturnAsErrors", 0);
Could be a permissions issue:
http://griffo.info/tellme/2009/05/executing-sql-directly-no-cursor/

PDO Unbuffered queries

I'm trying to get into PDO details. So I coded this:
$cn = getConnection();
// get table sequence
$comando = "call p_generate_seq('bitacora')";
$id = getValue($cn, $comando);
//$comando = 'INSERT INTO dsa_bitacora (id, estado, fch_creacion) VALUES (?, ?, ?)';
$comando = 'INSERT INTO dsa_bitacora (id, estado, fch_creacion) VALUES (:id, :estado, :fch_creacion)';
$parametros = array (
':id'=> (int)$id,
':estado'=>1,
':fch_creacion'=>date('Y-m-d H:i:s')
);
execWithParameters($cn, $comando, $parametros);
my getValue function works fine, and I get the next sequence for the table. But when I get into execWithParameters, i get this exception:
PDOException: SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in D:\Servidor\xampp_1_7_1\htdocs\bitacora\func_db.php on line 77
I tried to modify the connection attributes but it doesn't work.
These are my core db functions:
function getConnection() {
try {
$cn = new PDO("mysql:host=$host;dbname=$bd", $usuario, $clave, array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
));
$cn->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
return $cn;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
}
function getValue($cn, $comando) {
$resul = $cn->query($comando);
if (!$resul) return null;
while($res = $resul->fetch()) {
$retorno = $res[0][0];
break;
}
return $retorno;
}
function execWithParameters($cn, $comando, $parametros) {
$q = $cn->prepare($comando);
$q->execute($parametros);
if ($q->errorInfo() != null) {
$e = $q->errorInfo();
echo $e[0].':'.$e[1].':'.$e[2];
}
}
Somebody who can shed a light for this? PD. Please do not suggest doing autonumeric id, cause i am porting from another system.
The issue is that mysql only allows for one outstanding cursor at a given time. By using the fetch() method and not consuming all the pending data, you are leaving a cursor open.
The recommended approach is to consume all the data using the fetchAll() method.
An alternative is to use the closeCursor() method.
If you change this function, I think you will be happier:
<?php
function getValue($cn, $comando) {
$resul = $cn->query($comando);
if (!$resul) return null;
foreach ($resul->fetchAll() as $res) {
$retorno = $res[0];
break;
}
return $retorno;
}
?>
I don't think PDOStatement::closeCursor() would work if you're not doing a query that returns data (i.e. an UPDATE, INSERT, etc).
A better solution is to simply unset() your PDOStatement object after calling PDOStatement::execute():
$stmt = $pdo->prepare('UPDATE users SET active = 1');
$stmt->execute();
unset($stmt);
The problem seems to be---I'm not too familiar with PDO--- that after your getValue call returns, the query is still bound to the connection (You only ever ask for the first value, yet the connection returns several, or expects to do so).
Perhaps getValue can be fixed by adding
$resul->closeCursor();
before the return.
Otherwise, if queries to getValue will always return a single (or few enough) value, it seems that using fetchAll will be preferred.
I just spend 15 minutes googling all around the internet, and viewed at least 5 different Stackoverflow questions, some who claimed my bug apparently arose from the wrong version of PHP, wrong version of MySQL library or any other magical black-box stuff...
I changed all my code into using "fetchAll" and I even called closeCursor() and unset() on the query object after each and every query. I was honestly getting desperate! I also tried the MYSQL_ATTR_USE_BUFFERED_QUERY flag, but it did not work.
FINALLY I threw everything out the window and looked at the PHP error, and tracked the line of code where it happened.
SELECT AVG((original_bytes-new_bytes)/original_bytes) as saving
FROM (SELECT original_bytes, new_bytes FROM jobs ORDER BY id DESC LIMIT 100) AS t1
Anyway, the problem happened because my original_bytes and new_bytes both where unsigned bigints, and that meant that if I ever had a job where the new_bytes where actually LARGER than the original_bytes, then I would have a nasty MySQL "out of range" error. And that just happened randomly after running my minification service for a little while.
Why the hell I got this weird MySQL error instead of just giving me the plain error, is beyond me! It actually showed up in SQLBuddy (lightweight PHPMyAdmin) when I ran the raw query.
I had PDO exceptions on, so it should have just given me the MySQL error.
Never mind, the bottom line is:
If you ever get this error, be sure to check that your raw MySQL is actually correct and STILL working!!!
A friend of mine had very much the same problem with the xampp 1.7.1 build. After replacing xampp/php/* by the 5.2.9-2 php.net build and copying all necessary files to xampp/apache/bin it worked fine.
If you're using XAMPP 1.7.1, you just need to upgrade to 1.7.2.

Categories