PGAdmin succeeds but PDO query fails - php

I am wanting to get column information on a Postgres database table. I am using the following query:
select column_name as "Field", data_type as "Type", is_nullable as "Null", character_maximum_length as "max_length" from information_schema.columns where table_name='testempty'
(At some point, I will be removing the AS clauses. I had reasons for including them when I originally set up this query, but these reasons have since evaporated.)
When I run the query in PGAdmin, I get the results I expect: There are 2 columns, and I see their requested details. When I execute the same query using PDO in PHP, I get 0 rows back. No errors, the execute call returns true. Here is the PHP code:
try {
$remote_statement = $remote_con->prepare($column_query);
$remote_exec = $remote_statement->execute();
} catch(Exception $e) {
file_put_contents("logs/remote.log", '[' . date("Y-m-d H:i:s") . ' ' . $_SERVER["REMOTE_ADDR"] . "] Prepare failed: " . $e->getMessage() . "\n", FILE_APPEND);
}
if (!$remote_exec) {
file_put_contents("logs/remote.log", '[' . date("Y-m-d H:i:s") . ' ' . $_SERVER["REMOTE_ADDR"] . "] Execute failed\n", FILE_APPEND);
}
$remote_error = $remote_statement->errorInfo();
if (!empty($remote_error[2])) {
file_put_contents("logs/remote.log", '[' . date("Y-m-d H:i:s") . ' ' . $_SERVER["REMOTE_ADDR"] . "] Query failed: " . $remote_error[2] . "\n", FILE_APPEND);
die($remote_error);
}
$remote_rows = $remote_statement->fetchAll(PDO::FETCH_ASSOC);
$remote_con is a PDO connection object I created earlier in the code. $column_query is set to the query I listed above. There is another table I run this same code on prior to this and I get the expected results.
I appreciate any helpful hints here. I am sure I am missing something obvious, but it baffles me that the query works in PGAdmin and not via a PHP call.

This turned out to be a table-specific permissions issue. Granted SELECT permissions to PUBLIC for a problem table and the query via PHP worked. I found another pair of tables in a different database with this issue, and all was resolved by granting this permission.

Related

After rewind mysql query results, not working to re-use query

I'm relatively new to mysql/php rewind. I am execuring a query, and after I mark the current data set and re-wind it, I need to run the same set to run shell scripts that take a really long time. I'm going to run the same script as a cron in a few minutes, so I can mark another set and know I'm fetching a different data set to run the slow shell scripts on. For some reason, the rewind isn't working, so it's not using the data set twice:
if(!($stmt = $mysqli->prepare("SELECT node, model FROM Table WHERE vendor = 'Calix' AND model in ('C7','E7') AND ((update_status NOT in ('u') OR (update_time IS NULL) OR ((DATEDIFF(NOW(),SW_ver_update_time)>14)) )) LIMIT 100"))) //AND ping_reply IS NULL AND software_version IS NULL
{
echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
if(!$stmt->bind_result($ip, $model))
{
echo "Binding results failed: (" . $stmt->errno . ") " . $stmt->error;
}
if(!$stmt->execute())
{
$tempErr = "Error select node, model c7,e7 status: " . $stmt->error;
printf($tempErr . "\n"); //show mysql execute error if exists
$err->logThis($tempErr);
}
$stmt1 = $mysqli1->prepare("UPDATE Table SET update_status = 'u' , update_time = UTC_TIMESTAMP() WHERE node = ?");
while($stmt->fetch()) {
print "current ip: " . $ip . "\n";
$stmt1->bind_param("s", $ip);
$stmt1->execute(); //write time stamp and 'u' on ones 'in process of Updating'
}
//rewind db pointer
mysql_data_seek($stmt, 0);
//Circulate through 100 dslams fetched that we marked as in process.
//This takes a long time to execuate and will be running this script concurrently in 5 minutes
//so we need to know what we're working on so we don't fetch them again.
while($stmt->fetch()) {
print "hello current ip: " . $ip . "\n";
//will execute shell script here
//I never see hello print statement
}
I looked at mysql_data_seek but I don't see an example that uses fetch(). Can I not use fetch() after a rewind? What's the issue here? Thanks!
*Update:
I tried
$stmt->data_seek(0);
But it's still not letting me re-use that query. If anyone has a suggestion of how to get rewind to work, or a way to get around it, like storing the query results so I can re-use them without re-running the query later, that's ok too.
You can't use mysql_data_seek() with mysqli functions. Each PHP extension for MySQL is separate, and you can't use the functions from one extension with query results from another extension.
You'd want to use the equivalent function in the mysqli extension: mysqli_stmt::data_seek().
Re your comments:
You can use get_result() and then call fetch_all() on the result. This will return an array of rows, in which each row is an array of columns returned by the MySQL query.
if(!($stmt = $mysqli->prepare("SELECT node, model FROM Table WHERE vendor = 'Calix' AND model in ('C7','E7') AND ((update_status NOT in ('u') OR (update_time IS NULL) OR ((DATEDIFF(NOW(),SW_ver_update_time)>14)) )) LIMIT 100"))) //AND ping_reply IS NULL AND software_version IS NULL
{
error_log("Prepare failed: ({$mysqli->errno}) {$mysqli->error}");
die();
}
if(!$stmt->execute())
{
error_log("Error select node, model c7,e7 status: {$stmt->error}");
die();
}
if (!($result = $stmt->get_result()))
{
error_log("Error get result of select node, model c7,e7: {$stmt->error}");
die();
}
$rows = $result->fetch_all(MYSQLI_ASSOC);
I also show use of error_log() which automatically logs to your http error log. If there's an error, I call die() so the code doesn't attempt to go on to the next step. In your script, you might structure it differently, like use return instead, if there's other code to run.
Or else you can fully embrace exceptions.

php pdo query fails to return result despite prepared statement being correct

I have the following php/pdo which calls a a mysql procedure which returns a filename however despite the prepared statement being correct and returning the following from a cut and pasted db query:
db query/result
> call sp_CDRbyCustomer('Wind', 'R2X', DATE(DATE_SUB(NOW(), INTERVAL 10 WEEK)), DATE(NOW()));
> +------------------------------------------------------+
> | Exported filename |
> +------------------------------------------------------+
> | '/tmp/CDR_for_Wind_20140704-20140912_1410516460.csv' |
> +------------------------------------------------------+
> 1 row in set (0.02 sec)
the php/pdo
which should return our filename is:
include('db.ini');
define('DEBUG', true);
if (DEBUG ) {
openlog("$iam", LOG_PID | LOG_ODELAY,LOG_LOCAL4);
syslog(LOG_INFO, "START OF DEBUG LOG.");
}
/***** connect to database using db.ini for credentials *****/
try {
$dbConn = new PDO('mysql:host='.$host.';dbname='.$db, $dbUser, $dbPass, array (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION));
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
$structure_name = "'Wind'";
$cug_uid = "'R2X'";
$num_weeks = 10;
/**** Query - export file name ****/
$sqlQuery4filename = ("
call sp_CDRbyCustomer($structure_name, $cug_uid, DATE(DATE_SUB(NOW(), INTERVAL $num_weeks WEEK)), DATE(NOW()))
");
$sqlQuery4filename = preg_replace( "/\r|\n/", "", $sqlQuery4filename );
debug("01: sqlQueryfile string is '" . $sqlQuery4filename . "'");
$stmnt = $dbConn->prepare($sqlQuery4filename);
debug($stmnt);
$stmnt->execute();
$stmnt->closeCursor();
$filename = $stmnt->fetch(PDO::FETCH_ASSOC);
$filename = $filename['Exported filename'];
debug("01: filename string is '" . $filename . "'");
function debug($debug) {
if(!DEBUG) return;
print '
<div class="debug">
';
print_r($debug);
print '
</div><!-- end of debug -->
';
}
However I only ever get an empty string returned.
I have had this working, but after subversioning it I ended up with the wrong version and can no longer get it to work, anybody give me any clues to what I'm doing wrong.
You need to properly debug this:
See what the exact SQL command is you execute (I can't tell from your question).
Test the command against the database, for instance with PHPmyAdmin.
Show what the fetch() result is, before you access it as an array.
If you follow the PHP execution trial from the beginning to the end, you should be able to work out where it goes wrong.
You need to bind the output parameter. See Example #4 in the docs http://php.net/manual/en/pdo.prepared-statements.php
<?php
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// call the stored procedure
$stmt->execute();
print "procedure returned $return_value\n";
?>
So after much debugging and many different coding attempts I eventually retrieved teh required result.
I tried numerous attempts to use binParam but the returned result would always be a null string.
I had changed to mysql procedure to output the required filename so the mysql command SELECT #filename would provide the desired result.
I then retrieved this value with the following:
/**** Query - export file name ****/
$sql = 'call sp_CDRbyCustomer( \'' . $structure_name . '\', \'' . $cug_uid . '\', DATE(DATE_SUB(NOW(), INTERVAL ' . $num_weeks . ' WEEK)), DATE(NOW()), #filename )';
$stmnt = $dbConn->prepare($sql);
debug($stmnt);
$stmnt->execute();
$stmnt->closeCursor();
$filename_result = $dbConn->query("select #filename")->fetch();
$filename = $filename_result['#filename'];
I'm not sure if this is the best way to do this but it does produce the result I desire :-)

pg_send_query_params Returns TRUE But Fails

I have a PHP script which inserts a row into a Postgres DB. It works fine on my test server (Postgres 9.1) but fails on my new shared host (Postgres 8.4).
$query = "INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3))";
$result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));
The $result is always TRUE but no row is inserted.
I also tried:
$result = pg_get_result($dbconn);
But experienced the same behaviour.
Following #CraigRinger's transaction suggestion below I also tried both:
$query = "BEGIN;INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3));COMMIT;";
$result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));
and
pg_send_query($dbconn, "BEGIN;");
$query = "INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3));";
$result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));
pg_send_query($dbconn, "COMMIT;");
And still got the same behaviour.
If I run the INSERT query in phpPgAdmin a row is inserted. I am also able to get the results from this query in a PHP script:
"SELECT relid FROM pg_stat_user_tables"
What does this mean when the INSERT query result is true but no row is inserted? What could be the problem and how might I approach resolving this?
Edit
I can INSERT rows using phpPgAdmin and then SELECT these rows from a PHP script.
Here is a full PHP script that fails (it is stripped of POST gathering and validation that exists in my full script). The rest.php script simply holds connection vars and a response function. This rest.php script works with my SELECT script:
<?php
require "KLogger.php";
require "rest.php";
ini_set("error_reporting", E_ALL ^ E_NOTICE);
ini_set("display_errors", 0);
ini_set("log_errors", 1);
$log = KLogger::instance(dirname(__FILE__), KLogger::DEBUG);
$log_id = "AM".time();
$log->logInfo($log_id . " *** " . $_SERVER['REMOTE_ADDR']);
$lat = '51.510199';
$lon = '-0.129654';
$rate = '10';
$is_happy = 't';
$dbconn = pg_connect("host=" . $host . " dbname=" . $db . " user=" . $user . " password=" . $pw);
if(!$dbconn)
{
$log->logInfo($log_id . " No connection: " . pg_last_error());
sendResponse(500, "Internal Server Error");
}
else
{
$query = "INSERT INTO " . $table . " VALUES (DEFAULT, $1, $2, CURRENT_TIMESTAMP::TIMESTAMP(0), $3, $4, ST_Point($4, $3));";
$result = pg_send_query_params($dbconn, $query, array($is_happy, $rate, $lat, $lon));
if(!$result)
{
$log->logInfo($log_id . " No Result: " . pg_last_error());
sendResponse(500, "Internal Server Error");
}
else
{
$log->logInfo($log_id . " sendResponse(200)");
sendResponse(200, "OK");
}
}
pg_close($dbconn);
?>
The most common cause for this kind of issue is an open, uncomitted transaction.
If you BEGIN (or do so implicitly by turning autocommit off in your database driver) then do some work, only the transaction that did the work can see the changes until it COMMITs.
If that is the case then an immediate follow-up query from within the same script using the same connection will see the changed row, but nothing else will.
You can also check for this by enabling:
log_statement = 'all'
log_line_prefix = 'db=%d pid=%p vtxid=%v txid=%x'
and finding mismatched transactions by looking for virtual transaction IDs (vtxid) with a BEGIN and no matching COMMIT.
If you can't modify postgresql.conf because it's shared hosting you should be able to ALTER USER myuser SET log_statement = 'all'; or ALTER DATABASE mydatabase SET log_statement = 'all';. You can't set log_line_prefix outside postgresql.conf but your host might have a reasonable setting already.
Another possibility - and one that might be explained by the version difference - is that you're triggering an error later in the transaction by using a feature only available in 9.1, and you aren't detecting that error. Your earlier INSERT succeeds, but the whole transaction then gets rolled back when the later statement fails. Again, examine the server logs to see.
Another common cause is that you're connecting to a different database with the script than the one you connect to when you test to see if it's inserted. Try SELECTing the row you expect to have been inserted from the script after you insert it. It's also worth creating a dummy table via your admin tool (phpPgAdmin in your case, it seems) and then testing to see whether the script can see the dummy table.

How to monitor SQL (which uses prepared stataments)?

When first developing an PHP app (MySQl, but using ODBC interfaces to allow for future expansion), I was simply assigning my SQL to a variable and calling odbc_exec().
That made debugging simple, as I just had to examine my variable $sql.
Of course, I soon realized that I have to use prepared statements to sanitize user input.
My question is how to discover the exact SQL which is being executed in the databse, in order to debug my prepared statements.
I reazlise that I can't do it from PHP, but are their any external monitor tools which can interecpt the SQL? Or even a MySql command to echo, if I leave a console window open?
Use the MySQL query log.
You can start mysql server by --log[=file_name] to have a log file.
Here's some code I cam up with to aid debugging within PHP code.
However, to be absolutely certin of what is being executed by MySql, the other posters are correct. Look at the query log.
function OdbcPrepareAndExecute($sql, $parameter_array)
{
if (substr_count($sql, '?') != count($parameter_array))
{
ob_start();
var_dump($parameter_array);
$parameter_array_dump .= ob_get_clean();
ReportErrorAndDie('Invalid parameters',
'Request to prepare ODBC statement "' . $sql .'" with ' .
substr_count($sql, '?') . ' place-holders, but ' .
count($parameter_array) . ' parameters in array : ' .
$parameter_array_dump
);
}
LogDatabaseActivity('Prepare SQL "' . $sql . '"');
$prepared_statement = #odbc_prepare($_SESSION['connection'], $sql);
if($prepared_statement === False)
{
ReportErrorAndDie('Database problem',
'Could not prepare ODBC statement "' . $sql .'"');
}
LogDatabaseActivity('Execute prepared SQL statement with the following parameters:');
ob_start();
var_dump($parameter_array);
$parameter_array_dump = ob_get_clean();
LogDatabaseActivity($parameter_array_dump);
$expanded_sql = $sql;
for ($i = 0; $i < count($parameter_array); $i++)
$expanded_sql = substr_replace($expanded_sql,
$parameter_array[$i],
strpos($expanded_sql, '?'),
1);
LogDatabaseActivity('(preapred statement expands to "' . $expanded_sql . '")');
$result = #odbc_execute($prepared_statement, $parameter_array);

PDO : Insert query containing ' is not executing in SQLite3 with PHP 5.3.4 with

I am creating a blogging application using PHP5/SQLite3 . To insert a post in database I am executing query written below.
$db=connectToDatabase();
$tempcontent=$db->escapeString($tempcontent);
$query = "INSERT INTO posts VALUES (null,$temptitle, $tempcontent, $tempcategory, $tempauthor)";
$db->query($query);
$db=disconnectToDatabase();
I am having problem when the text input contain ' or " . when there is ', the query is not getting executed at all . If ' is not there then " is displayed with escape (\") in browser .
Sorry, I forgot to mention :
connectTodatabase() function is providing very general way to connect to database. as :
try {
$db1 = new PDO("sqlite:blog.db");
}catch( PDOException $exception ){
die($exception->getMessage());
}
return $db1;
Just post the whole class because we are not mind readers or psychics here.
The probably problem is you are not escaping data you include in your query.
Use either mysql_real_escape_string():
http://php.net/manual/en/function.mysql-real-escape-string.php
Or PDO prepared statements:
http://www.php.net/manual/en/pdo.prepare.php

Categories