I'm having some troubles with a function I developed in CodeIgniter 3. I'm trying to call a Store Procedure made in Oracle (a SELECT with some conditions and joins) with a ref cursor but when a I execute it, I get an empty array from the cursor.
I leave you below the code in PHP:
public function getReport($nummonth,$numyear){
$sqlqry = "BEGIN FRGSV006_SCP60_COMPACT(:cur,:nummonth,:numyear); END;";
$smt = oci_parse($this->connbi, $sqlqry);
oci_bind_by_name($smt, ":nummonth", $nummonth,32);
oci_bind_by_name($smt, ":numyear", $numyear,32);
$refcur = oci_new_cursor($this->connbi);
oci_bind_by_name($smt, ":cur",$refcur,-1,OCI_B_CURSOR);
oci_execute($smt);
oci_execute($refcur);
oci_fetch_all($refcur, $result,null,null,OCI_FETCHSTATEMENT_BY_ROW);
oci_free_statement($smt);
oci_free_statement($refcur);
return $result;
}
I already test the procedure working on the database and it's ok. I've been searching all over Google for a solution and none of them worked.
Do you know what may be happening/why is not returning data?
Your code looks okay to me. I'm assuming connbi is already defined from an #oci_pconnect call that succeeded? You should also check for errors at each step:
$connbi = #oci_pconnect( . . . );
if (!$connbi) {
$e = oci_error();
trigger_error('Could not connect to database: ' . $e['message'],E_USER_ERROR);
}
$smt = oci_parse($this->connbi, $sqlqry);
if (!$smt) {
$e = oci_error($connbi);
trigger_error('Could not parse statement: ' . $e['message'] . $sql,E_USER_ERROR);
}
$refcur = oci_new_cursor($this->connbi);
oci_bind_by_name($smt, ":cur",$refcur,-1,OCI_B_CURSOR);
$r = oci_execute($smt);
if (!$r) {
$e = oci_error($smt);
trigger_error(htmlentities('Could not execute: ' . $e['message']),E_USER_ERROR);
}
$r = oci_execute($refcur);
if (!$r) {
$e = oci_error($refcur);
trigger_error(htmlentities('Could not execute: ' . $e['message']),E_USER_ERROR);
}
Also capture the rows returned $nrows = oci_fetch_all($refcur, $result,null,null, OCI_FETCHSTATEMENT_BY_ROW); and emit debugging output to see if it returned anything. You may also want to set some PHP settings like:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
Related
I have a function that is not acting as I expect it to. Its purpose is to return an array of rows for select queries, or the insert id for Insert queries. For some reason if there is an insert query followed by a select query, the part of the function where it tests whether or not the query was an insert or not fails because inesrt_id still returns the id of the inserted row. I could program around this but I'd really like to understand why it's happening.
My understanding was that if the most recent query is a select, then there should be no insert id. I'm new to mysqli, so maybe the query doesn't really 'end' when I think it does so the new select counts as part of the same query? I can get it to work fine if I recreate the connection on each query but that's not practical. Here's the code for the query function.
public function __construct(){
parent::__construct();
// #mysql_select_db ('public') OR die('Could not select the database: ' . mysql_error() );
$this->connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_TABLE, DB_PORT)OR die ('Could not connect to MySQL: ' . mysql_error());
$this->db = $this;
}
public function query_return($querystring){
$response = array();
$this->result_object = $this->connection->query($querystring);
if($this->result_object != FALSE) {
$last_id = $this->connection->insert_id;
if (!empty($last_id)) {
$response = $last_id;
}
else {
while ($row = mysqli_fetch_assoc($this->result_object)) {
array_push($response, $row);
}
}
}
else{
$response = PEAR::raiseError('There was a problem with the query: '. mysql_error());
}
return $response;
}
EDIT: Ok so thanks to the guys below I added an is_object test to the function. I couldn't directly replace the true/false test as I actually use this function for deletions too and I want to know when it fails. I wrapped the insert_id test with the is_object test and things seem to be working now. I guess that an insert_id will be returned for a deletion query if there was a previous insert on the connection but I don't think that will cause problems as those functions only fail if they receive FALSE from the query_return.
I still don't really fathom why mysqli_insert_id would return a value after a select query when the documentation leads me to believe that it shouldn't but at least my code is working. This query_return function is tweaked from 'mysql_' (no 'i') procedural versions of these methods and it worked with those versions so there's something I'm still not understanding. Anyways here's the tweaked function.
private function query_return($querystring){
$response = array();
$this->result_object = $this->connection->query($querystring);
if($this->result_object != FALSE) {
if (!is_object($this->result_object)) {
$last_id = $this->connection->insert_id;
if (!empty($last_id)) {
$response = $last_id;
}
}
else {
while ($row = mysqli_fetch_assoc($this->result_object)) {
array_push($response, $row);
}
}
}
else{
$response = PEAR::raiseError('There was a problem with the query: '. mysql_error());
}
return $response;
}
Looking though the source of PHP its a wrapper to https://dev.mysql.com/doc/refman/5.0/en/mysql-stmt-insert-id.html
This documentation says the followng
LAST_INSERT_ID() (with no argument) returns a BIGINT (64-bit) value representing the first automatically generated value that was
set for an AUTO_INCREMENT column by the most recently executed INSERT
statement to affect such a column
https://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id
I would suggest changing your if statement to
if (!is_object($this->result_object)) {
this will check if there are any results to retrieve
The PHP documentation should probably be updated to reflect this though, As it stands its obvious behaviour
That's how it works, mysqli_insert_id Still returns a value because it's the same connection. You will need to close and open a new one for it to be set to 0.
I believe the variable is retaining its value from the last call. Try adding a unset($last_id); like below. Let me know if it doesn't work that way. Cheers.
public function __construct(){
parent::__construct();
// #mysql_select_db ('public') OR die('Could not select the database: ' . mysql_error() );
$this->connection = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_TABLE, DB_PORT)OR die ('Could not connect to MySQL: ' . mysql_error());
$this->db = $this;
}
public function query_return($querystring){
$response = array();
$this->result_object = $this->connection->query($querystring);
if($this->result_object != FALSE) {
$last_id = $this->connection->insert_id;
if (!empty($last_id)) {
$response = $last_id;
}
else {
while ($row = mysqli_fetch_assoc($this->result_object)) {
array_push($response, $row);
}
}
unset($last_id); //<--------here
}
else{
$response = PEAR::raiseError('There was a problem with the query: '. mysql_error());
}
return $response;
}
This is probably very simple (I'm a novice), but I haven't been able to find an answer.
I'm using Linux, DB2 and PHP.
My simple DB2 query from PHP only returns rows with integer values, but fails with "Fetch Failure" for anything else (varchar ...).
The query works with db2cli for all values:
echo "select COLUMN from TEST.TABLE"" | ./db2cli execsql -dsn SCHEMA
But fails in PHP:
$conn_string = "DRIVER={IBM DB2 ODBC DRIVER};DATABASE=$database;" .
"HOSTNAME=$hostname;PORT=$port;PROTOCOL=TCPIP;UID=$user;PWD=$passwd;";
$conn = db2_pconnect($conn_string, '', '');
if ($conn) {
$sql = 'select COLUMN from TEST.TABLE';
$options = array('cursor' => DB2_SCROLLABLE, 'binmode' => DB2_BINARY);
$stmt = db2_prepare($conn, $sql, $options);
if ($stmt) {
$result = db2_execute($stmt);
if (!$result) {
echo "exec errormsg: " .db2_stmt_errormsg($stmt);
}
$total_rows = db2_num_rows($stmt);
print "<br>Total rows: $total_rows";
for ($i = 0; $i < $total_rows; $i++) {
$row = db2_fetch_array($stmt);
print "<br>$row[0]";
}
} else {
echo "exec erromsg: " . db2_stmt_erromsg($stmt);
}
db2_close($conn);
} else {
echo "failed #2 ".db2_conn_errormsg();
}
}
It will display any rows with integer values, but empty strings for everything else with the error "Fetch Failure" in the log. I tried db2_fetch_array, db2_fetch_assoc and db2_fetch_both.
Note: I've added the superfluous stuff like db2_scrollable and db2_num_rows later on in attempts to solve the problem. Unsuccessfully.
EDIT: I can even FILTER by the values that won't display ( SELECT column WHERE column = 'value') and it'll return the correct number of rows.
Overview: I have a function that is supposed to pull a row of the db based on its id number
Problem: It seems my function is returning, but it isn't returning anything.
Details:
-I have 2 different files used here: db_class.php and character_pull.php
-Also I have a database that contains 1 table (characters) that does contain column "id"
-there are echo lines for debugging. I will give what the output is.
character_pull.php:
<?php
include "db_class.php";
echo "made it out here1";
$classobject = new db_class();
echo "made it out here2";
$results = $classobject->getPlayerStats("1");
print_r($results);
echo "made it out here3";
$id = "id: " . $results['id'];
$name = "name: " . $results['charname'];
$strength = "strength: " . $results['strength'];
$defense = "defense: " . $results['defense'];
$health = "health: " . $results['health'];
$level = "level: " . $results['level'];
$type = "type: " . $results['type'];
$experience = "experience: " . $results['experience'];
echo"<br/>";
echo "made it out here4";
?>
db_class.php:
<?php
include "database_connect.php";
class db_class{
public function getPlayerStats($id){
echo "<br/>" . "making it in class1";
$query = "SELECT * FROM characters WHERE id = $id";
$result = mysqli_query($query);
return $char = mysqli_fetch_array($result);
$result ->close();
}
}
?>
the output I receive when I run the page is this:
made it out here1made it out here2 making it in class1made it out
here3 made it out here4
I have tried several things to fix this, but am having trouble figuring out what is wrong.
I know that this is probably extremely sloppy and primitive, but try not to laugh too hard and maybe you can help me out :P. Thanks in advance.
You have a number of issues here.
It seems your DB class is quite incomplete. To me, if I am creating a class to represent a DB connection and various operations I am going to make that connection in that class, not via some include (where I assume the connection is happening). The here is that the include will only occur conditionally if your code hits that line. In this case, since you have that include outside any actual function in the class (like a constructor) it will never be called.
I would suggest something like this to resolve this:
class db_class {
protected $mysqli;
private $db_host = 'your_db_host';
private $db_user = 'your_db_user';
private $db_password = 'your_db_password';
protected $db_name = 'default_db_name';
public __construct($db_host = NULL, $db_user = NULL, $db_password = NULL, $db_name = NULL) {
if (!empty($db_host)) {
$this->db_host= $db_host;
}
// validate other parameters similarly
$mysqli = new mysqli($this->db_host, $this->db_use, $this->db_password, $this->db_name);
if($mysqli->connect_error) {
throw new Exception('Connect Error: ' . $mysqli->connect_errno . ', ' . $mysqli->connect_error);
} else {
$this->mysqli = $mysqli;
}
}
// other class methods
}
You now have an object representing a mysqli connection store in $this->mysqli.
Your getPlayerStats() method might now look like
public function getPlayerStats($id) {
if(empty($id)) {
throw new Exception ('An empty value was passed for id');
}
// verify this is integer-like value
$id = (string)$id;
$pattern = '/^\d+$/';
if (!preg_match($pattern, $id) !== 1) {
throw new Exception ('A non-integer value was passed for id');
}
$id = (int)$id;
$query = "SELECT id, name, strength, defense, level, health, type, experience FROM characters WHERE id = :id";
$stmt = $this->mysqli->prepare($query);
$stmt->bind_param('i', $id);
$result = $stmt->execute();
if (false === $result) {
throw new Exception('Query error: ' . $stmt->error);
} else {
$obj = new stdClass();
$stmt->bind_result($obj->id, $obj->name, $obj->strength, $obj->defense, $obj->level, $obj, health, $obj->type, $obj->experience);
$stmt->fetch();
$stmt->close();
return $obj;
}
}
Note I used prepared statements here, which, you should get used to using as it is really best practice for querying databases. Note also I have added in handling of error cases all throughout the code. You should get in the habit of doing this, as it will making debugging much easier.
Just a guess but I would move this above the class name:
<?php
include "database_connect.php";
class db_class{
I have the following code:
$link = new PDO("mysql:dbname=$databasename;host=127.0.0.1",$username,$password);
$query = $link->prepare("SELECT * FROM index WHERE sbeid=:idvar");
for($j = 1; $j < count($array); $j++)
{
if($array[$j][16] == "TRUE" || $array[$j][16] == "FALSE")
{
$paramforquery = $array[$j][25];
$query->bindParam(":idvar",$paramforquery);
$query->execute();
$result = $query->fetchAll();
//do things with the $result
$query->closeCursor();
}
//else if, do stuff
}
$link = null;
$array is a large array composed of input from a CSV file that successfully loads via fopen().
My problem is this: the query just doesn't work. I know for a fact (ran the query directly on the server with some sample values from the file) that the data is in the database, but when i var_dump the $results each time the for loop runs, I just get an empty array.
What am I doing wrong?
TIA.
Increase the error reporting - the standard advice.
Set the error mode of the pdo object to ERRMODE_EXCEPTION - you hardly can miss an error that way.
Use a debugger or add some debug output to your script - a real debugger is way better.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$array = foo();
echo '<pre>Debug: |array|=', count($array), '</pre>';
$link = new PDO("mysql:dbname=$databasename;host=127.0.0.1",$username,$password);
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = $link->prepare("SELECT * FROM index WHERE sbeid=:idvar");
$query->bindParam(":idvar", $paramforquery);
foreach($array as $row) {
echo '<pre>Debug: row[16]='; var_dump($row[16]); echo '</pre>';
if($row[16] == "TRUE" || $row[16] == "FALSE") {
$paramforquery = $row[25];
echo '<pre>Debug: paramforquery='; var_dump($paramforquery); echo '</pre>';
$query->execute();
echo '<pre>Debug: rowcount='; var_dump($query->rowCount()); echo '</pre>';
$result = $query->fetchAll();
//do things with the $result
$query->closeCursor();
}
//else if, do stuff
}
$link = null;
Are you sure you are getting a connection ?
try {
$link = new PDO("mysql:dbname=$databasename;host=127.0.0.1",$username,$password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
}
This will catch any exceptions from trying to connect. If this works ok, try putting the query under the $link line and see what's returned.
If your query runs manually, i'd say its something to do with your DB connection. Make sure you've got error reporting turned on.
Additional:
In your query you have this :idvar ? Shouldnt you be using a PHP variable like this $idvar.
so
$query = $link->prepare("SELECT * FROM index WHERE sbeid=" . $idvar);
function get_total_adults()
{
$sql = "SELECT SUM(number_adults_attending) as number_of_adults FROM is_nfo_rsvp";
$result = mysql_query($sql) or die(mysql_error());
$array = mysql_fetch_assoc($result);
return $array['number_of_adults'];
}
I know there is a way to write this with less code. I'm just looking for the best way (without using something like ezSQL).
function get_total_adults() {
$sql = 'SELECT SUM(number_adults_attending) FROM is_nfo_rsvp';
$result = mysql_query($sql) or die(mysql_error());
// I'd throw a catchable exception (see below) rather than die with a MySQl error
return mysql_result($result, 0);
}
As to how I'd rather handle errors:
function get_total_adults() {
$sql = 'SELECT SUM(number_adults_attending) FROM is_nfo_rsvp';
$result = mysql_query($sql);
if (!$result) {
throw new Exception('Failed to get total number of adults attending');
}
return mysql_result($result, 0);
}
try {
$total_adults = get_total_adults();
} catch(Exception $ex) {
die('Whoops! An error occurred: ' . $ex->getMessage());
// or even better, add to your template and dump the template at this point
}
// continue code
You can drop the "as number_of_adults" part of the query and use mysql_result.
You could also try refactormycode.com