Insert query doesn't work on server - php

Below code runs without any problems on my local server. However, when I try to run it on the intended server, two of my queries don't work - they do not INSERT as they are supposed to. I've marked two queries that don't work with comments, the rest works. Intended server runs on PHP 5.6.30-0+deb8u1.
UPDATE: thanks to aynber, I've tracked the error. This is the error for the first query: prepared statement \"editRecord\" does not exist" I don't understand why this works on local server but not on intended one.
UPDATE 2: error between prepared statement and execution: syntax error at or near \"ON\"\nLINE 3:
case "editRecord":
$id = openPandoraBox(post("id"));
$tutorAbsence = post("tutorAbsence");
$clientAbsence = post("clientAbsence");
if($tutorAbsence == "1") {
if(post("tutor") != "0") {
// ------------this query does not work.-----------
$absUpsSql = "INSERT INTO tutorabsence(id, tutorid, reason)
VALUES ($1, $2, $3)
ON CONFLICT (id)
DO UPDATE SET tutorid=$2, reason=$3";
$absUpsPrep = pg_prepare($conn, 'editRecord', $absUpsSql);
$absUpsQry = pg_execute($conn, 'editRecord',
array($id, post("tutor"), post("tutorreason"))
);
} else {
$tutorAbsence = "0";
};
} else {
$absDelSql = "DELETE FROM tutorabsence WHERE id=$1";
$absDelPrep = pg_prepare($conn, 'absDel', $absDelSql);
$absDelQry = pg_execute($conn, 'absDel', array($id));
};
if($clientAbsence == "1"){
if(post("client") != "0") {
// ------------this query does not work.-----------
$absUpsSql = "INSERT INTO clientabsence(id, clientid, reason)
VALUES ($1, $2, $3)
ON CONFLICT (id)
DO UPDATE SET clientid=$2, reason=$3";
$absUpsPrep = pg_prepare($conn, 'absUps', $absUpsSql);
$absUpsQry = pg_execute($conn, 'absUps',
array($id, post("client"), post("clientreason"))
);
} else {
$clientAbsence = "0";
};
} else {
$absDelSql = "DELETE FROM clientabsence WHERE id=$1";
$absDelPrep = pg_prepare($conn, 'absDelOne', $absDelSql);
$absDelQry = pg_execute($conn, 'absDelOne', array($id));
};
$resultSql = "UPDATE appointments
SET hour=$1, tutorid=$2,
clientid=$3, purpose=$4,
tutornotshown=$5, clientnotshown=$6
WHERE appid=$7";
$resultPrep = pg_prepare($conn, 'resultSql', $resultSql);
$result = pg_execute($conn, 'resultSql',
array(post('hour'), post("tutor"), post("client"),
post("purpose"), $tutorAbsence, $clientAbsence, $id
)
);
echo json_encode(array("success" => 1));
break;

UPDATE 2: error between prepared statement and execution: syntax error at or near \"ON\"\nLINE 3:
If it works on your local server but not on production server, it is likely that they don't run the same version of PostgreSQL. ON CONFLICT is a feature that was released with PostgreSQL 9.5 (https://www.postgresql.org/docs/9.5/static/sql-insert.html) which is still fairly recent.
You should run this query on the production server to check out which version of PostgreSQL it uses:
SELECT version();
Your server probably runs PostgreSQL 9.5 or 9.6 while the production server is probably on an older release.

Upsert for PostgreSQL below 9.5 is too complicated. I am very short of time, so I'll just use SELECT COUNT(*) and if's.

Related

PHP sqlsrv_fetch_array problem && sqlsrv_num_rows -1

a new webserver has been stood up for me. It is Ubuntu 20.04 and has PHP 7.4.3 on it. I am working with MS SQL Server 2012. I can send my SQL query to the DB server and see it in SQL Server Profiler. I can copy it from the profiler and it runs fine in SQL Management Studio but, I am having a problem when I try to echo the results to my page. When I use sqlsrv_num_rows I get -1. Could I get a hand please?
<?php
if(isset($_POST['getPassBtn'])){
#DATABASE LOGIN
include './php/inc/dbLogin/mydb.php';
#FORM POST VARIABLES
$badge = $_POST['empId'];
//$badge = (int)$badge;
#check badge entry for paramiters
if($badge == '' || $badge < 10000 || $badge > 30000){
echo '<br/> ERROR : Invalid Badge Number <br/>';
die();
}
$sql = "USE mydb SET NOCOUNT ON SELECT badgeNumber, userPassword FROM dbo.users WHERE badgeNumber = '$badge' ORDER BY badgeNumber ASC --getTestData.php";
//$sql = "USE toolsMeskwaki SELECT * FROM bingoProgressive.users ORDER BY badgeNumber ASC --getTestData.php";
$params = array();
$options = array( 'Scrollable' => 'buffered');
$stmt = sqlsrv_query( $conn, $sql, $params, $options);
#check if query returns false
if( $stmt === false ) {
die( print_r( sqlsrv_errors(), true));
}else{
echo '<br/> Query sent to SQL Server <br/>';
}
/*
$row_count = sqlsrv_num_rows( $stmt );
if ($row_count === false){
echo "Error in retrieveing row count.";
}else{
echo $row_count;
}
*/
#Fetching Data by array
while($row = sqlsrv_fetch_array($stmt)){
echo 'badgeNumber '.$row['badgeNumber'];
echo 'userPassword '.$row['userPassword'];
}
#release query
sqlsrv_free_stmt($stmt);
#CLOSE DATA BASE CONNECTION
sqlsrv_close($conn);
echo "<br/> SQL Server Connection closed.<br />";
}else{
echo '<br/> click GET btn to connect SQL Server <br/>';
}
?>
You're submitting three different statements:
USE mydb
SET NOCOUNT ON
SELECT badgeNumber, userPassword FROM dbo.users WHERE badgeNumber = '$badge' ORDER BY badgeNumber ASC
It works in SQL Management Studio for two reasons:
Auto-magic statement detection, although deprecated for several years (you're now expected to use ; as delimiter), is still supported.
The query tool is specifically designed to run several statements at once.
We know that sqlsrv_query() supports it because it isn't returning false. But, given that you're running three statements, you need you use sqlsrv_next_result() twice to move to the third result set.
On a side note:
You can use sqlsrv_connect() to provide the initial database. You only need to switch DBs if you use several of them and you don't want to add the name as mydb.dbo.users.
SQLSRV supports prepared statements (see sqlsrv_prepare() and sqlsrv_execute()).

PHP sqlsrv BULK INSERT incomplete

I am trying to insert a big file (few millions row) via SQL server BULK INSERT functionality. My SQL query will look like:
BULK INSERT MY_TABLE
FROM '\\myserver\open\myfile.csv'
WITH (
firstrow=2,
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n',
BATCHSIZE = 50000,
ERRORFILE = '\\myserver\open\myfileerror.log'
);
When I trigger it from MSSQL Server Management Studio, it always import it completely.
When I do it from my PHP code, sometimes it stop in the middle, without any error messages.
I tried with both sqlsrv_query or sqlsrv_prepare/sqlsrv_execute, same result.
sql; //like the query above
$statement = sqlsrv_query($connection, $sql);
if($statement === false) {
$error = sqlsrv_errors();
$error['sql'] = $sql;
throw new Exception(json_encode($error));
}
Would it be possible to get the logs of MSSQL from the $statement, the same I get from the MSSQL Studio? e.g. (50000 row(s) affected).
As a workaround, I have increased the BATCHSIZE to 1000000, but that is not a real solution.
Background information:
- PHP 7.1.9
- sqlsrv version: 4.3.0+9904
- sqlsrv.ClientBufferMaxKBSize: 10240
- Windows 2012 R2 Server
The issue was about the statement buffer. When I read it with sqlsrv_next_result, processing continue.
$statement = sqlsrv_query($connection, $sql);
if($statement === false) {
$error = sqlsrv_errors();
$error['sql'] = $sql;
throw new Exception(json_encode($error));
} else if($statement) {
while($next_result = sqlsrv_next_result($statement)){
#echo date("Y-m-d H:i:s",time()). " Reading buffer...\n";
}
}

Mistake in SQL syntax.. (bindValue?)

I am trying to create an update query and I am looping in some set stuff to a var called $str and I cant seem to get it to work.
if (is_numeric($id)) {
if (!empty($values) && !empty($table_name)) {
$str = '';
$sql = "UPDATE `$table_name` SET :update_values WHERE `$column_name` = :id";
// Its one because we dont use ID like that
$i = 1;
foreach ($values as $key => $value) {
if ($key != $column_name) {
// Exclude the last one from having a comma at the end
if ($i == count($values) - 1) {
$str .= "$key='" . $value . "'";
} else {
$str .= "$key='" . $value . "', ";
$i++;
}
}
}
$query = $this->dbh->prepare($sql);
$query->bindValue('update_values', $str, PDO::PARAM_STR);
$query->bindValue(':id', $id, PDO::PARAM_INT);
$query->execute();
return true;
} else {
return false;
}
} else{
return false;
}
}
Output:
Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or
access violation: 1064 You have an error in your SQL syntax; check the
manual that corresponds to your MariaDB server version for the right
syntax to use near ''note_name=\'yeet\', note_date=\'2020-02-20\',
note_desc=\'asdasdasdasdadsasdads' at line 1
Am I making any obvious mistakes?
Also for the life of me I don't know what the backslashes in front of the values mean.
In MySQL, identifiers cannot be provided as values.
References to columns must appear in the text of the SQL statement, they cannot be provided through bind parameters. This holds true for table names, column names, function names.
There is no workaround; this is a by-design restriction. There's several reasons for this. One of the most straightforward reasons is understanding how a SQL statement gets prepared, the information that is needed to come up with an execution plan, the tables and columns have to be known at prepare time (for the semantic check and privilege check. The actual values can be deferred to execution time.
Bind placeholders are for providing values, not identifiers.
With the code given, what MySQL is seeing something along the lines of
UPDATE `mytable` SET 'a string value' WHERE `id_col` = 42
And MySQL is balking at the 'a string value'.
We can (and should) use bind parameters for values.
We could dynamically generate SQL text that looks like this:
UPDATE `mytable`
SET `col_one` = :val1
, `col_two` = :val2
WHERE `id_col` = :id
and after the SQL text is prepared into statement, we can bind values:
$sth->bindValue(':val1', $value_one , PDO::PARAM_STR );
$sth->bindValue(':val2', $value_two , PDO::PARAM_STR );
$sth->bindValue(':id' , $id , PDO::PARAM_INT );
and then execute

Why do I get a MySQL syntax error even though the cell updates correctly?

The error thrown:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
The relevant code:
$update = mysqli_real_escape_string($connection, $update);
// $update = '10'; $id = '4'
$sql = "UPDATE tasks SET `shortDesc` = '".$update."' WHERE `id`=".$id;
if (mysqli_query($connection, $sql) === TRUE) {
echo 1;
} else {
echo mysqli_error($connection);
}
I was not able to locate any similar error on the forum that would be of help.
Why is it working but throws an error?
The code you posted should not cause an error, given, that the parameter $id is never empty. Actually looking at your error message and your query, this could be the only error produced, because if both variables are empty, you will have:
UPDATE tasks SET `shortDesc` = '' WHERE `id`=
This will fail, because there is no value for id. Since MySQL has not problem with numbers in quotes, this should eliminate the error message:
$sql = "UPDATE tasks SET `shortDesc` = '".$update."' WHERE `id`='".$id."'";
You can optimize this for better reading:
$sql = "UPDATE tasks SET `shortDesc` = '$update' WHERE `id`='$id'";
Now if the variables are empty the query still does not become invalid.
Since this is or was the only source of error in your code, i reckon something is missing in your listing, or your code was called twice with missing parameters?
For quality assurance you should check $update and $id for validity before using them anyhow. at least make sure they are not empty, since then you can spare the call.

How to echo a MySQLi prepared statement?

I'm playing around with MySQLi at the moment, trying to figure out how it all works. In my current projects I always like to echo out a query string while coding, just to make sure that everything is correct, and to quickly debug my code. But... how can I do this with a prepared MySQLi statement?
Example:
$id = 1;
$baz = 'something';
if ($stmt = $mysqli->prepare("SELECT foo FROM bar WHERE id=? AND baz=?")) {
$stmt->bind_param('is',$id,$baz);
// how to preview this prepared query before acutally executing it?
// $stmt->execute();
}
I've been going through this list (http://www.php.net/mysqli) but without any luck.
EDIT
Well, if it's not possible from within MySQLi, maybe I'll stick with something like this:
function preparedQuery($sql,$params) {
for ($i=0; $i<count($params); $i++) {
$sql = preg_replace('/\?/',$params[$i],$sql,1);
}
return $sql;
}
$id = 1;
$baz = 'something';
$sql = "SELECT foo FROM bar WHERE id=? AND baz=?";
echo preparedQuery($sql,array($id,$baz));
// outputs: SELECT foo FROM bar WHERE id=1 AND baz=something
Far from perfect obviously, since it's still pretty redundant — something I wanted to prevent — and it also doesn't give me an idea as to what's being done with the data by MySQLi. But I guess this way I can quickly see if all the data is present and in the right place, and it'll save me some time compared to fitting in the variables manually into the query — that can be a pain with many vars.
I don't think you can - at least not in the way that you were hoping for. You would either have to build the query string yourself and execute it (ie without using a statement), or seek out or create a wrapper that supports that functionality. The one I use is Zend_Db, and this is how I would do it:
$id = 5;
$baz = 'shazam';
$select = $db->select()->from('bar','foo')
->where('id = ?', $id)
->where('baz = ?', $baz); // Zend_Db_Select will properly quote stuff for you
print_r($select->__toString()); // prints SELECT `bar`.`foo` FROM `bar` WHERE (id = 5) AND (baz = 'shazam')
I have struggled with this one in the past. So to get round it I wrote a little function to build the SQL for me based on the SQL, flags and variables.
//////////// Test Data //////////////
$_GET['filmID'] = 232;
$_GET['filmName'] = "Titanic";
$_GET['filmPrice'] = 10.99;
//////////// Helper Function //////////////
function debug_bind_param(){
$numargs = func_num_args();
$numVars = $numargs - 2;
$arg2 = func_get_arg(1);
$flagsAr = str_split($arg2);
$showAr = array();
for($i=0;$i<$numargs;$i++){
switch($flagsAr[$i]){
case 's' : $showAr[] = "'".func_get_arg($i+2)."'";
break;
case 'i' : $showAr[] = func_get_arg($i+2);
break;
case 'd' : $showAr[] = func_get_arg($i+2);
break;
case 'b' : $showAr[] = "'".func_get_arg($i+2)."'";
break;
}
}
$query = func_get_arg(0);
$querysAr = str_split($query);
$lengthQuery = count($querysAr);
$j = 0;
$display = "";
for($i=0;$i<$lengthQuery;$i++){
if($querysAr[$i] === '?'){
$display .= $showAr[$j];
$j++;
}else{
$display .= $querysAr[$i];
}
}
if($j != $numVars){
$display = "Mismatch on Variables to Placeholders (?)";
}
return $display;
}
//////////// Test and echo return //////////////
echo debug_bind_param("SELECT filmName FROM movies WHERE filmID = ? AND filmName = ? AND price = ?", "isd", $_GET['filmID'], $_GET['filmName'], $_GET['filmPrice']);
I have also build a little online tool to help.
Mysqli Prepare Statement Checker
I recently updated this project to include composer integration, unit testing and to better handle accepting arguments by reference (this requires updating to php 5.6).
In response to a request I received on a project I created to address this same issue using PDO, I created an extension to mysqli on github that seems like it addresses your issue:
https://github.com/noahheck/E_mysqli
This is a set of classes that extend the native mysqli and mysqli_stmt classes to allow you to view an example of the query to be executed on the db server by interpolating the bound parameters into the prepared query then giving you access to resultant query string as a new property on the stmt object:
$mysqli = new E_mysqli($dbHost, $dbUser, $dbPass, $dbName);
$query = "UPDATE registration SET name = ?, email = ? WHERE entryId = ?";
$stmt = $mysqli->prepare($query);
$stmt->bindParam("ssi", $_POST['name'], $_POST['email'], $_POST['entryId']);
$stmt->execute();
echo $stmt->fullQuery;
Will result in:
UPDATE registration SET name = 'Sue O\'reilly', email = 'sue.o#example.com' WHERE entryId = 5569
Note that the values in the fullQuery are escaped appropriately taking into account the character set on the db server, which should make this functionality suitable for e.g. log files, backups, etc.
There are a few caveats to using this, outlined in the ReadMe on the github project, but, especially for development, learning and testing, this should provide some helpful functionality.
As I've outlined in the github project, I don't have any practical experience using the mysqli extension, and this project was created at the request of users of it's sister project, so any feedback that can be provided from devs using this in production would be greatly appreciated.
Disclaimer - As I said, I made this extension.
Just set it to die and output the last executed query. The Error handling should give you meaningful information which you can use to fix up your query.
You can turn on log queries on mysql server.
Just execute command:
sql> SHOW VARIABLES LIKE "general_log%";
sql> SET GLOBAL general_log = 'ON';
And watch queries in the log file.
After testing turn log off:
sql> SET GLOBAL general_log = 'OFF';
I was able to use var_dump() to at least get a little more info on the mysqli_stmt:
$postmeta_sql = "INSERT INTO $db_new.wp_postmeta (post_id, meta_key, meta_value) VALUES (?, ?, ?)";
$stmt = $new_conn->prepare($postmeta_sql);
$stmt->bind_param("sss", $post_id, $meta_key, $meta_value);
echo var_dump($stmt);
$stmt->execute();
$stmt->close();

Categories