From d64e40ca2cb9eea7bdb3fd2ff389f4b29b823c24 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Tue, 14 Mar 2017 15:19:31 +0900 Subject: [PATCH] Second fix for returning with multiple entries in DB IO - all data stored in array (size contrain needs to be checked) - allows any returning data - only named rows are returned (no numbers for column access) - if multiple rows then insert_id is an array with the return data - if single row the insert_id holds the PK, and insert_id_ext holds extended data if exists --- www/admin/class_test.php | 8 +++--- www/libs/Class.DB.IO.inc | 55 ++++++++++++++++++++++++++++++++-------- www/libs/db_pgsql.inc | 10 +++++--- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/www/admin/class_test.php b/www/admin/class_test.php index fa1859f0..7a6b3b55 100644 --- a/www/admin/class_test.php +++ b/www/admin/class_test.php @@ -74,16 +74,16 @@ } $status = $basic->db_exec("INSERT INTO foo (test) VALUES ('FOO TEST ".time()."') RETURNING test"); - print "DIRECT INSERT STATUS: $status | PRIMARY KEY: ".$basic->insert_id."
"; + print "DIRECT INSERT STATUS: $status | PRIMARY KEY: ".$basic->insert_id." | PRIMARY KEY EXT: ".print_r($basic->insert_id_ext, 1)."
"; print "DIRECT INSERT PREVIOUS INSERTED: ".print_r($basic->db_return_row("SELECT foo_id, test FROM foo WHERE foo_id = ".$basic->insert_id), 1)."
"; $basic->db_prepare("ins_foo", "INSERT INTO foo (test) VALUES ($1)"); $status = $basic->db_execute("ins_foo", array('BAR TEST '.time())); - print "PREPARE INSERT STATUS: $status | PRIMARY KEY: ".$basic->insert_id."
"; + print "PREPARE INSERT STATUS: $status | PRIMARY KEY: ".$basic->insert_id." | PRIMARY KEY EXT: ".print_r($basic->insert_id_ext, 1)."
"; print "PREPARE INSERT PREVIOUS INSERTED: ".print_r($basic->db_return_row("SELECT foo_id, test FROM foo WHERE foo_id = ".$basic->insert_id), 1)."
"; // returning test with multiple entries // $status = $basic->db_exec("INSERT INTO foo (test) values ('BAR 1 ".time()."'), ('BAR 2 ".time()."'), ('BAR 3 ".time()."') RETURNING foo_id"); - $status = $basic->db_exec("INSERT INTO foo (test) values ('BAR 1 ".time()."'), ('BAR 2 ".time()."'), ('BAR 3 ".time()."')"); - print "DIRECT MULTIPLE INSERT STATUS: $status | PRIMARY KEYS: ".print_r($basic->insert_id, 1)."
"; + $status = $basic->db_exec("INSERT INTO foo (test) values ('BAR 1 ".time()."'), ('BAR 2 ".time()."'), ('BAR 3 ".time()."') RETURNING foo_id, test"); + print "DIRECT MULTIPLE INSERT STATUS: $status | PRIMARY KEYS: ".print_r($basic->insert_id, 1)." | PRIMARY KEY EXT: ".print_r($basic->insert_id_ext, 1)."
"; # async test queries diff --git a/www/libs/Class.DB.IO.inc b/www/libs/Class.DB.IO.inc index 2e7f0a93..0216272f 100644 --- a/www/libs/Class.DB.IO.inc +++ b/www/libs/Class.DB.IO.inc @@ -272,6 +272,7 @@ public $num_fields; // how many fields has the query public $field_names; // array with the field names of the current query public $insert_id; // last inserted ID + public $insert_id_ext; // extended insert ID (for data outside only primary key) // other vars private $nbsp = ''; // used by print_array recursion function // error & warning id @@ -668,11 +669,12 @@ } elseif (preg_match("/ returning (.*)/i", $this->query, $matches) && $this->pk_name) { - if (preg_match("/$this->pk_name/", $matches[1])) + // add the primary key if it is not in the returning set + if (!preg_match("/$this->pk_name/", $matches[1])) { $this->query .= " , ".$this->pk_name; - $this->returning_id = true; } + $this->returning_id = true; } } } @@ -750,15 +752,33 @@ else { $this->insert_id = array (); + $this->insert_id_ext = array (); +// echo "** PREPARE RETURNING FOR CURSOR: ".$this->cursor."
"; // we have returning, now we need to check if we get one or many returned // we'll need to loop this, if we have multiple insert_id returns - while ($_insert_id = $this->db_functions->_db_fetch_array($this->cursor)) + while ($_insert_id = $this->db_functions->_db_fetch_array($this->cursor, PGSQL_ASSOC)) { - $this->insert_id[] = $_insert_id[$this->pk_name]; +// echo "*** RETURNING: ".print_r($_insert_id, 1)."
"; + $this->insert_id[] = $_insert_id; } - // if we have only one, revert from arry to single + // if we have only one, revert from array to single if (count($this->insert_id) == 1) - $this->insert_id = $this->insert_id[0]; + { +// echo "* SINGLE DATA CONVERT: ".count($this->insert_id[0])." => ".array_key_exists($this->pk_name, $this->insert_id[0])."
"; +// echo "* PK DIRECT: ".$this->insert_id[0][$this->pk_name]."
"; + // if this has only the pk_name, then only return this, else array of all data (but without the position) + // example if insert_id[0]['foo'] && insert_id[0]['bar'] it will become insert_id['foo'] & insert_id['bar'] + // if only ['foo_id'] and it is the PK then the PK is directly written to the insert_id + if (count($this->insert_id[0]) > 1 || !array_key_exists($this->pk_name, $this->insert_id[0])) + { + $this->insert_id_ext = $this->insert_id[0]; + $this->insert_id = $this->insert_id[0][$this->pk_name]; + } + elseif ($this->insert_id[0][$this->pk_name]) + { + $this->insert_id = $this->insert_id[0][$this->pk_name]; + } + } } // this warning handling is only for pgsql // we returned an array of PKs instread of a single one @@ -1389,8 +1409,8 @@ if (!preg_match("/{$this->prepare_cursor[$stm_name]['pk_name']}/", $matches[1])) { $query .= " , ".$this->prepare_cursor[$stm_name]['pk_name']; - $this->prepare_cursor[$stm_name]['returning_id'] = true; } + $this->prepare_cursor[$stm_name]['returning_id'] = true; } } // search for $1, $2, in the query and push it into the control array @@ -1467,13 +1487,28 @@ $this->debug('ExecuteData', 'ERROR in STM['.$stm_name.'|'.$this->prepare_cursor[ $this->insert_id = array (); // we have returning, now we need to check if we get one or many returned // we'll need to loop this, if we have multiple insert_id returns - while ($_insert_id = $this->db_functions->_db_fetch_array($this->cursor)) + while ($_insert_id = $this->db_functions->_db_fetch_array($code, PGSQL_ASSOC)) { - $this->insert_id[] = $_insert_id[$this->prepare_cursor[$stm_name]['pk_name']]; + $this->insert_id[] = $_insert_id; } // if we have only one, revert from arry to single if (count($this->insert_id) == 1) - $this->insert_id = $this->insert_id[0]; + { +// echo "+ SINGLE DATA CONVERT: ".count($this->insert_id[0])." => ".array_key_exists($this->prepare_cursor[$stm_name]['pk_name'], $this->insert_id[0])."
"; +// echo "+ PK DIRECT: ".$this->insert_id[0][$this->prepare_cursor[$stm_name]['pk_name']]."
"; + // if this has only the pk_name, then only return this, else array of all data (but without the position) + // example if insert_id[0]['foo'] && insert_id[0]['bar'] it will become insert_id['foo'] & insert_id['bar'] + // if only ['foo_id'] and it is the PK then the PK is directly written to the insert_id + if (count($this->insert_id[0]) > 1 || !array_key_exists($this->prepare_cursor[$stm_name]['pk_name'], $this->insert_id[0])) + { + $this->insert_id_ext = $this->insert_id[0]; + $this->insert_id = $this->insert_id[0][$this->prepare_cursor[$stm_name]['pk_name']]; + } + elseif ($this->insert_id[0][$this->pk_name]) + { + $this->insert_id = $this->insert_id[0][$this->prepare_cursor[$stm_name]['pk_name']]; + } + } } // this error handling is only for pgsql if (is_array($this->insert_id)) diff --git a/www/libs/db_pgsql.inc b/www/libs/db_pgsql.inc index 253e941d..e3845f03 100644 --- a/www/libs/db_pgsql.inc +++ b/www/libs/db_pgsql.inc @@ -152,12 +152,16 @@ } // METHOD: _db_fetch_array - // PARAMS: cursor + // PARAMS: cursor, opt result type // RETURN: row // DESC : wrapper for pg_fetch_array - public function _db_fetch_array($cursor) + public function _db_fetch_array($cursor, $result_type = '') { - return pg_fetch_array($cursor); + // result type is passed on as is [should be checked] + if ($result_type) + return pg_fetch_array($cursor, NULL, $result_type); + else + return pg_fetch_array($cursor); } // METHOD: _db_fetch_all