diff --git a/CHANGELOG b/CHANGELOG
index f6b71b4..4a73e10 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,13 @@
+Thu Sep 01 2022
+ rubo77 - fix CVE-2020-13565: sanitize URL
+Thu Aug 25 2022
+ rubo77 - Adapt to PHP 8.2
+ rubo77 - Update ADODB to v5.20.20
+ rubo77 - work around missing get- and set_magic_quotes_runtime()
+ rubo77 - Lite.php 376 2004-11-08
+ rubo77 - update adodb to SVN Revision 425
+ rubo77 - Merge remote-tracking branch 'origin/master' from github @IPSO
+ mikeb - Switch from CVS to SVN on sourceforge.net
Tue Sep 05 2006
mikeb - Release version 3.3.7
Mon Sep 04 2006
@@ -26,7 +36,7 @@ Thu Sep 22 2005
Wed Sep 21 2005
mikeb - Addslashes to JS creation code in assign_group.php.
Thu Sep 08 2005
- mikeb - Added support for MS-SQL in setup.php, thanks to François Tissandier
+ mikeb - Added support for MS-SQL in setup.php, thanks to François Tissandier
Sat Sep 03 2005
mikeb - Fixed typo in manual
mikeb - Fixed comments in gacl.class.php
@@ -36,7 +46,7 @@ Mon Aug 22 2005
Thu Aug 04 2005
mikeb - Fixed bug with config ini file path in setup.php
Thu Jul 28 2005
- mikeb - Fixed bug with double/single quotes on line 3526. Jérémy Cohen Solal
+ mikeb - Fixed bug with double/single quotes on line 3526. Jérémy Cohen Solal
Sun Jul 24 2005
mikeb - Removed table prefix comment regarding not using "_". Apparently it works now
mikeb - Fixed comments in gacl.class.php regarding group IDs, it now correctly says group values.
diff --git a/Cache_Lite/Hashed_Cache_Lite.php b/Cache_Lite/Hashed_Cache_Lite.php
index 894952f..a0ca635 100644
--- a/Cache_Lite/Hashed_Cache_Lite.php
+++ b/Cache_Lite/Hashed_Cache_Lite.php
@@ -69,7 +69,7 @@ function _create_dir_structure($dir)
{
if (!@file_exists($dir)) {
$dir_parts = preg_split('![\/]+!', $dir, -1, PREG_SPLIT_NO_EMPTY);
- $new_dir = ($dir{0} == DIR_SEP) ? DIR_SEP : '';
+ $new_dir = ($dir[0] == DIR_SEP) ? DIR_SEP : '';
foreach ($dir_parts as $dir_part) {
$new_dir .= $dir_part;
if (!file_exists($new_dir) && !mkdir($new_dir, 0771)) {
@@ -145,7 +145,7 @@ function clean($group = false)
unset($this->_memoryCachingArray[$key]);
}
}
- $this->_memoryCachingCounter = count($this->_memoryCachingArray);
+ $this->_memoryCachingCounter = phpgacl_legacy_count($this->_memoryCachingArray);
if ($this->_onlyMemoryCaching) {
return true;
}
diff --git a/Cache_Lite/Lite.php b/Cache_Lite/Lite.php
index 17e2fa5..8f44a28 100644
--- a/Cache_Lite/Lite.php
+++ b/Cache_Lite/Lite.php
@@ -22,7 +22,7 @@
*
* @package Cache_Lite
* @category Caching
-* @version $Id$
+* @version $Id: Lite.php 376 2004-11-08 00:47:05Z ipso $
* @author Fabien MARTY
*/
@@ -366,7 +366,7 @@ function clean($group = false)
$motif = ($group) ? 'cache_'.$group.'_' : 'cache_';
}
if ($this->_memoryCaching) {
- while (list($key, $value) = each($this->_memoryCachingArray)) {
+ foreach($this->_memoryCachingArray as $key=>$value) {
if (strpos($key, $motif, 0)) {
unset($this->_memoryCachingArray[$key]);
$this->_memoryCachingCounter = $this->_memoryCachingCounter - 1;
@@ -526,14 +526,14 @@ function _read()
if ($fp) {
clearstatcache(); // because the filesize can be cached by PHP itself...
$length = @filesize($this->_file);
- $mqr = get_magic_quotes_runtime();
- set_magic_quotes_runtime(0);
+ $mqr = (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime());
+ if(function_exists('set_magic_quotes_runtime')) @set_magic_quotes_runtime(0);
if ($this->_readControl) {
$hashControl = @fread($fp, 32);
$length = $length - 32;
}
$data = @fread($fp, $length);
- set_magic_quotes_runtime($mqr);
+ if(function_exists('set_magic_quotes_runtime')) @set_magic_quotes_runtime($mqr);
if ($this->_fileLocking) @flock($fp, LOCK_UN);
@fclose($fp);
if ($this->_readControl) {
diff --git a/admin/acl_test2.php b/admin/acl_test2.php
index 893bd9f..912ae0f 100644
--- a/admin/acl_test2.php
+++ b/admin/acl_test2.php
@@ -32,9 +32,9 @@
echo("");
*/
-$total_rows = count($rows);
+$total_rows = phpgacl_legacy_count($rows);
-while (list(,$row) = @each(&$rows)) {
+foreach($rows as $row) {
list( $aco_section_value,
$aco_section_name,
$aco_value,
diff --git a/admin/acl_test3.php b/admin/acl_test3.php
index 86c2fde..efdeac9 100644
--- a/admin/acl_test3.php
+++ b/admin/acl_test3.php
@@ -52,9 +52,9 @@
echo("");
*/
-$total_rows = count($rows);
+$total_rows = phpgacl_legacy_count($rows);
-while (list(,$row) = @each(&$rows)) {
+foreach($rows as $row) {
list( $aco_section_value,
$aco_section_name,
$aco_value,
diff --git a/admin/assign_group.php b/admin/assign_group.php
index 8d02afc..a07f2de 100644
--- a/admin/assign_group.php
+++ b/admin/assign_group.php
@@ -33,13 +33,13 @@
//Parse the form values
//foreach ($_POST['delete_assigned_aro'] as $aro_value) {
- while (list(,$object_value) = @each($_POST['delete_assigned_object'])) {
+ foreach($_POST['delete_assigned_object'] as $object_value) {
$split_object_value = explode('^', $object_value);
$selected_object_array[$split_object_value[0]][] = $split_object_value[1];
}
//Insert Object -> GROUP mappings
- while (list($object_section_value,$object_array) = @each($selected_object_array)) {
+ foreach($selected_object_array as $object_section_value=>$object_array) {
$gacl_api->debug_text('Assign: Object ID: '. $object_section_value .' to Group: '. $_POST['group_id']);
foreach ($object_array as $object_value) {
@@ -56,14 +56,13 @@
//showarray($_POST['selected_'.$_POST['group_type']]);
//Parse the form values
- //foreach ($_POST['selected_aro'] as $aro_value) {
- while (list(,$object_value) = @each($_POST['selected_'.$_POST['group_type']])) {
+ foreach ($_POST['selected_'.$_POST['group_type']] as $object_value) {
$split_object_value = explode('^', $object_value);
$selected_object_array[$split_object_value[0]][] = $split_object_value[1];
}
//Insert ARO -> GROUP mappings
- while (list($object_section_value,$object_array) = @each($selected_object_array)) {
+ foreach($selected_object_array as $object_section_value=>$object_array) {
$gacl_api->debug_text('Assign: Object ID: '. $object_section_value .' to Group: '. $_POST['group_id']);
foreach ($object_array as $object_value) {
diff --git a/admin/edit_group.php b/admin/edit_group.php
index 23a86d9..15e5b04 100644
--- a/admin/edit_group.php
+++ b/admin/edit_group.php
@@ -30,7 +30,7 @@
case 'Delete':
$gacl_api->debug_text('Delete');
- if (count($_POST['delete_group']) > 0) {
+ if (phpgacl_legacy_count($_POST['delete_group']) > 0) {
//Always reparent children when deleting a group.
foreach ($_POST['delete_group'] as $group_id) {
$gacl_api->debug_text('Deleting group_id: '. $group_id);
@@ -41,7 +41,7 @@
}
}
- if (count($retry) > 0) {
+ if (phpgacl_legacy_count($retry) > 0) {
foreach($retry as $group_id) {
$gacl_api->del_group($group_id, TRUE, $group_type);
}
diff --git a/admin/edit_object_sections.php b/admin/edit_object_sections.php
index 6c12115..2fd07f3 100644
--- a/admin/edit_object_sections.php
+++ b/admin/edit_object_sections.php
@@ -34,7 +34,7 @@
switch ($_POST['action']) {
case 'Delete':
- if (count($_POST['delete_sections']) > 0) {
+ if (phpgacl_legacy_count($_POST['delete_sections']) > 0) {
foreach($_POST['delete_sections'] as $id) {
$gacl_api->del_object_section($id, $object_type, TRUE);
}
@@ -48,7 +48,7 @@
$gacl_api->debug_text("Submit!!");
//Update sections
- while (list(,$row) = @each($_POST['sections'])) {
+ foreach($_POST['sections'] as $row) {
list($id, $value, $order, $name) = $row;
$gacl_api->edit_object_section($id, $name, $value, $order,0,$object_type );
}
@@ -58,7 +58,7 @@
unset($name);
//Insert new sections
- while (list(,$row) = @each($_POST['new_sections'])) {
+ foreach($_POST['new_sections'] as $row) {
list($value, $order, $name) = $row;
if (!empty($value) AND !empty($order) AND !empty($name)) {
@@ -79,7 +79,7 @@
$sections = array();
- while (list(,$row) = @each($rows)) {
+ foreach($rows as $row) {
list($id, $value, $order_value, $name) = $row;
$sections[] = array(
diff --git a/admin/edit_objects.php b/admin/edit_objects.php
index 90a2f62..3c854c4 100644
--- a/admin/edit_objects.php
+++ b/admin/edit_objects.php
@@ -33,7 +33,7 @@
switch ($_POST['action']) {
case 'Delete':
- if (count($_POST['delete_object']) > 0) {
+ if (phpgacl_legacy_count($_POST['delete_object']) > 0) {
foreach($_POST['delete_object'] as $id) {
$gacl_api->del_object($id, $object_type, TRUE);
}
@@ -47,7 +47,7 @@
$gacl_api->debug_text("Submit!!");
//Update objects
- while (list(,$row) = @each($_POST['objects'])) {
+ foreach($_POST['objects'] as $row) {
list($id, $value, $order, $name) = $row;
$gacl_api->edit_object($id, $_POST['section_value'], $name, $value, $order, 0, $object_type);
}
@@ -58,7 +58,7 @@
unset($name);
//Insert new sections
- while (list(,$row) = @each($_POST['new_objects'])) {
+ foreach($_POST['new_objects'] as $row) {
list($value, $order, $name) = $row;
if (!empty($value) AND !empty($name)) {
@@ -86,7 +86,7 @@
$rs = $db->pageexecute($query, $gacl_api->_items_per_page, $_GET['page']);
$rows = $rs->GetRows();
- while (list(,$row) = @each($rows)) {
+ foreach($rows as $row) {
list($id, $section_value, $value, $order_value, $name) = $row;
$objects[] = array(
diff --git a/admin/gacl_admin_api.class.php b/admin/gacl_admin_api.class.php
index 400dc08..5c27f94 100644
--- a/admin/gacl_admin_api.class.php
+++ b/admin/gacl_admin_api.class.php
@@ -81,6 +81,8 @@ function return_page($url="") {
}
if (!$debug OR $debug==0) {
+ # fix CVE-2020-13565: sanitize URL
+ $url=preg_replace('/^([a-z0-9\s%;\+]+:\/\/+)+/i','',$url);
header("Location: $url\n\n");
} else {
$this->debug_text("return_page(): URL: $url -- Referer: $_SERVER[HTTP_REFERRER]");
diff --git a/admin/object_search.php b/admin/object_search.php
index bec1d30..8579707 100644
--- a/admin/object_search.php
+++ b/admin/object_search.php
@@ -24,7 +24,7 @@ function array_walk_trim(&$array_field) {
$exploded_value_search_str = explode("\n", $value_search_str);
$exploded_name_search_str = explode("\n", $name_search_str);
- if (count($exploded_value_search_str) > 1 OR count($exploded_name_search_str) > 1) {
+ if (phpgacl_legacy_count($exploded_value_search_str) > 1 OR phpgacl_legacy_count($exploded_name_search_str) > 1) {
//Given a list, lets try to match all lines in it.
array_walk($exploded_value_search_str, 'array_walk_trim');
array_walk($exploded_name_search_str, 'array_walk_trim');
@@ -45,7 +45,7 @@ function array_walk_trim(&$array_field) {
WHERE section_value='. $db->qstr($_GET['section_value']) .'
AND (';
- if (count($exploded_value_search_str) > 1) {
+ if (phpgacl_legacy_count($exploded_value_search_str) > 1) {
$query .= 'lower(value) IN ('. implode(',', $exploded_value_search_str) .')';
} else {
$query .= 'lower(value) LIKE ' . $db->qstr($value_search_str);
@@ -53,7 +53,7 @@ function array_walk_trim(&$array_field) {
$query .= ' OR ';
- if (count($exploded_name_search_str) > 1) {
+ if (phpgacl_legacy_count($exploded_name_search_str) > 1) {
$query .= 'lower(name) IN ('. implode(',', $exploded_name_search_str) .')';
} else {
$query .= 'lower(name) LIKE ' . $db->qstr($name_search_str);
diff --git a/admin/smarty/libs/plugins/function.fetch.php b/admin/smarty/libs/plugins/function.fetch.php
index 81b1bfc..8b36ce3 100644
--- a/admin/smarty/libs/plugins/function.fetch.php
+++ b/admin/smarty/libs/plugins/function.fetch.php
@@ -181,12 +181,12 @@ function smarty_function_fetch($params, &$smarty)
$content .= fgets($fp,4096);
}
fclose($fp);
- $csplit = split("\r\n\r\n",$content,2);
+ $csplit = explode("\r\n\r\n",$content,2);
$content = $csplit[1];
if(!empty($params['assign_headers'])) {
- $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0]));
+ $smarty->assign($params['assign_headers'],explode("\r\n",$csplit[0]));
}
}
} else {
diff --git a/adodb/.mailmap b/adodb/.mailmap
new file mode 100644
index 0000000..1f2f7e7
--- /dev/null
+++ b/adodb/.mailmap
@@ -0,0 +1,4 @@
+Andreas Fernandez
+Mike Benoit MikeB
+Mike Benoit mike.benoit
+
diff --git a/adodb/LICENSE.md b/adodb/LICENSE.md
new file mode 100644
index 0000000..d00e2b1
--- /dev/null
+++ b/adodb/LICENSE.md
@@ -0,0 +1,499 @@
+ADOdb License
+=============
+
+The ADOdb Library is dual-licensed, released under both the
+[BSD 3-clause](#bsd-3-clause-license) and the
+[GNU Lesser General Public License (LGPL) v2.1](#gnu-lesser-general-public-license)
+or, at your option, any later version.
+
+In plain English, you do not need to distribute your application in source code form,
+nor do you need to distribute ADOdb source code, provided you follow the rest of
+terms of the BSD license.
+
+For more information about ADOdb, visit https://adodb.org/
+
+BSD 3-Clause License
+--------------------
+
+(c) 2000-2013 John Lim (jlim@natsoft.com)
+(c) 2014 Damien Regad, Mark Newnham and the ADOdb community
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+### DISCLAIMER
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+GNU LESSER GENERAL PUBLIC LICENSE
+---------------------------------
+
+_Version 2.1, February 1999_
+_Copyright © 1991, 1999 Free Software Foundation, Inc._
+_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+_This is the first released version of the Lesser GPL. It also counts
+as the successor of the GNU Library Public License, version 2, hence
+the version number 2.1._
+
+### Preamble
+
+The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+We protect your rights with a two-step method: **(1)** we copyright the
+library, and **(2)** we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+We call this license the “Lesser” General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+“work based on the library” and a “work that uses the library”. The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+**0.** This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called “this License”).
+Each licensee is addressed as “you”.
+
+A “library” means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+The “Library”, below, refers to any such software library or work
+which has been distributed under these terms. A “work based on the
+Library” means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term “modification”.)
+
+“Source code” for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+**1.** You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+**2.** You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+* **a)** The modified work must itself be a software library.
+* **b)** You must cause the files modified to carry prominent notices
+stating that you changed the files and the date of any change.
+* **c)** You must cause the whole of the work to be licensed at no
+charge to all third parties under the terms of this License.
+* **d)** If a facility in the modified Library refers to a function or a
+table of data to be supplied by an application program that uses
+the facility, other than as an argument passed when the facility
+is invoked, then you must make a good faith effort to ensure that,
+in the event an application does not supply such function or
+table, the facility still operates, and performs whatever part of
+its purpose remains meaningful.
+(For example, a function in a library to compute square roots has
+a purpose that is entirely well-defined independent of the
+application. Therefore, Subsection 2d requires that any
+application-supplied function or table used by this function must
+be optional: if the application does not supply it, the square
+root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+**3.** You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+**4.** You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+**5.** A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a “work that uses the Library”. Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+However, linking a “work that uses the Library” with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a “work that uses the
+library”. The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+When a “work that uses the Library” uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+**6.** As an exception to the Sections above, you may also combine or
+link a “work that uses the Library” with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+* **a)** Accompany the work with the complete corresponding
+machine-readable source code for the Library including whatever
+changes were used in the work (which must be distributed under
+Sections 1 and 2 above); and, if the work is an executable linked
+with the Library, with the complete machine-readable “work that
+uses the Library”, as object code and/or source code, so that the
+user can modify the Library and then relink to produce a modified
+executable containing the modified Library. (It is understood
+that the user who changes the contents of definitions files in the
+Library will not necessarily be able to recompile the application
+to use the modified definitions.)
+* **b)** Use a suitable shared library mechanism for linking with the
+Library. A suitable mechanism is one that (1) uses at run time a
+copy of the library already present on the user's computer system,
+rather than copying library functions into the executable, and (2)
+will operate properly with a modified version of the library, if
+the user installs one, as long as the modified version is
+interface-compatible with the version that the work was made with.
+* **c)** Accompany the work with a written offer, valid for at
+least three years, to give the same user the materials
+specified in Subsection 6a, above, for a charge no more
+than the cost of performing this distribution.
+* **d)** If distribution of the work is made by offering access to copy
+from a designated place, offer equivalent access to copy the above
+specified materials from the same place.
+* **e)** Verify that the user has already received a copy of these
+materials or that you have already sent this user a copy.
+
+For an executable, the required form of the “work that uses the
+Library” must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+**7.** You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+* **a)** Accompany the combined library with a copy of the same work
+based on the Library, uncombined with any other library
+facilities. This must be distributed under the terms of the
+Sections above.
+* **b)** Give prominent notice with the combined library of the fact
+that part of it is a work based on the Library, and explaining
+where to find the accompanying uncombined form of the same work.
+
+**8.** You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+**9.** You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+**10.** Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+**11.** If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+**12.** If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+**13.** The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+“any later version”, you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+**14.** If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+### NO WARRANTY
+
+**15.** BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY “AS IS” WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+**16.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+_END OF TERMS AND CONDITIONS_
diff --git a/adodb/README.md b/adodb/README.md
new file mode 100644
index 0000000..e432b2f
--- /dev/null
+++ b/adodb/README.md
@@ -0,0 +1,102 @@
+ADOdb Library for PHP
+======================
+
+[](https://gitter.im/adodb/adodb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[](https://sourceforge.net/projects/adodb/files/latest/download)
+
+(c) 2000-2013 John Lim (jlim@natsoft.com)
+(c) 2014 Damien Regad, Mark Newnham and the
+ [ADOdb community](https://github.com/ADOdb/ADOdb/graphs/contributors)
+
+The ADOdb Library is dual-licensed, released under both the
+[BSD 3-Clause](https://github.com/ADOdb/ADOdb/blob/master/LICENSE.md#bsd-3-clause-license)
+and the
+[GNU Lesser General Public Licence (LGPL) v2.1](https://github.com/ADOdb/ADOdb/blob/master/LICENSE.md#gnu-lesser-general-public-license)
+or, at your option, any later version.
+This means you can use it in proprietary products;
+see [License](https://github.com/ADOdb/ADOdb/blob/master/LICENSE.md) for details.
+
+Home page: https://adodb.org/
+
+
+Introduction
+============
+
+PHP's database access functions are not standardized. This creates a
+need for a database class library to hide the differences between the
+different databases (encapsulate the differences) so we can easily
+switch databases.
+
+The library currently supports MySQL, Firebird & Interbase, PostgreSQL, SQLite3, Oracle,
+Microsoft SQL Server, Foxpro ODBC, Access ODBC, Informix, DB2, Sybase,
+Sybase SQL Anywhere, generic ODBC and Microsoft's ADO.
+
+We hope more people will contribute drivers to support other databases.
+
+
+Installation
+============
+
+Unpack all the files into a directory accessible by your web server.
+
+To test, try modifying some of the tutorial examples.
+Make sure you customize the connection settings correctly.
+
+You can debug using:
+
+``` php
+debug = true;
+$db->connect($server, $user, $password, $database);
+$rs = $db->execute('select * from some_small_table');
+print "";
+print_r($rs->getRows());
+print " ";
+```
+
+
+Documentation and Examples
+==========================
+
+Refer to the [ADOdb website](https://adodb.org/) for library documentation and examples. The documentation can also be [downloaded for offline viewing](https://sourceforge.net/projects/adodb/files/Documentation/).
+
+- [Main documentation](https://adodb.org/dokuwiki/doku.php?id=v5:userguide:userguide_index): Query, update and insert records using a portable API.
+- [Data dictionary](https://adodb.org/dokuwiki/doku.php?id=v5:dictionary:dictionary_index) describes how to create database tables and indexes in a portable manner.
+- [Database performance monitoring](https://adodb.org/dokuwiki/doku.php?id=v5:performance:performance_index) allows you to perform health checks, tune and monitor your database.
+- [Database-backed sessions](https://adodb.org/dokuwiki/doku.php?id=v5:session:session_index).
+
+There is also a [tutorial](https://adodb.org/dokuwiki/doku.php?id=v5:userguide:mysql_tutorial) that contrasts ADOdb code with PHP native MySQL code.
+
+
+Files
+=====
+
+- `adodb.inc.php` is the library's main file. You only need to include this file.
+- `adodb-*.inc.php` are the database specific driver code.
+- `adodb-session.php` is the PHP4 session handling code.
+- `test.php` contains a list of test commands to exercise the class library.
+- `testdatabases.inc.php` contains the list of databases to apply the tests on.
+- `Benchmark.php` is a simple benchmark to test the throughput of a SELECT
+statement for databases described in testdatabases.inc.php. The benchmark
+tables are created in test.php.
+
+
+Support
+=======
+
+To discuss with the ADOdb development team and users, connect to our
+[Gitter chatroom](https://gitter.im/adodb/adodb) using your Github credentials.
+
+Please report bugs, issues and feature requests on Github:
+
+https://github.com/ADOdb/ADOdb/issues
+
+You may also find legacy issues in
+
+- the [SourceForge tickets section](http://sourceforge.net/p/adodb/_list/tickets)
+
+However, please note that they are not actively monitored and should
+only be used as reference.
diff --git a/adodb/adodb-active-record.inc.php b/adodb/adodb-active-record.inc.php
index c5c6cb7..8f3b005 100644
--- a/adodb/adodb-active-record.inc.php
+++ b/adodb/adodb-active-record.inc.php
@@ -1,27 +1,36 @@
_dbat
$_ADODB_ACTIVE_DBS = array();
-
+$ACTIVE_RECORD_SAFETY = true;
+$ADODB_ACTIVE_DEFVALS = false;
+$ADODB_ACTIVE_CACHESECS = 0;
class ADODB_Active_DB {
var $db; // ADOConnection
@@ -33,28 +42,45 @@ class ADODB_Active_Table {
var $flds; // assoc array of adofieldobjs, indexed by fieldname
var $keys; // assoc array of primary keys, indexed by fieldname
var $_created; // only used when stored as a cached file
+ var $_belongsTo = array();
+ var $_hasMany = array();
}
+// $db = database connection
+// $index = name of index - can be associative, for an example see
+// PHPLens Issue No: 17790
// returns index into $_ADODB_ACTIVE_DBS
-function ADODB_SetDatabaseAdapter(&$db)
+function ADODB_SetDatabaseAdapter(&$db, $index=false)
{
global $_ADODB_ACTIVE_DBS;
-
- foreach($_ADODB_ACTIVE_DBS as $k => $d) {
- if ($d->db == $db) return $k;
- }
-
- $obj = new ADODB_Active_DB();
- $obj->db =& $db;
- $obj->tables = array();
-
- $_ADODB_ACTIVE_DBS[] = $obj;
-
- return sizeof($_ADODB_ACTIVE_DBS)-1;
+
+ foreach($_ADODB_ACTIVE_DBS as $k => $d) {
+ if($d->db === $db) {
+ return $k;
+ }
+ }
+
+ $obj = new ADODB_Active_DB();
+ $obj->db = $db;
+ $obj->tables = array();
+
+ if ($index == false) {
+ $index = sizeof($_ADODB_ACTIVE_DBS);
+ }
+
+ $_ADODB_ACTIVE_DBS[$index] = $obj;
+
+ return sizeof($_ADODB_ACTIVE_DBS)-1;
}
class ADODB_Active_Record {
+ static $_changeNames = true; // dynamically pluralize table names
+
+ /** @var bool|string Allows override of global $ADODB_QUOTE_FIELDNAMES */
+ public $_quoteNames;
+
+ static $_foreignSuffix = '_id'; //
var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
var $_table; // tablename, if set in class definition then use it as table name
var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
@@ -62,104 +88,338 @@ class ADODB_Active_Record {
var $_saved = false; // indicates whether data is already inserted.
var $_lasterr = false; // last error message
var $_original = false; // the original values loaded or inserted, refreshed on update
-
+
+ var $foreignName; // CFR: class name when in a relationship
+
+ var $lockMode = ' for update '; // you might want to change to
+
+ static function UseDefaultValues($bool=null)
+ {
+ global $ADODB_ACTIVE_DEFVALS;
+ if (isset($bool)) {
+ $ADODB_ACTIVE_DEFVALS = $bool;
+ }
+ return $ADODB_ACTIVE_DEFVALS;
+ }
+
// should be static
- function SetDatabaseAdapter(&$db)
+ static function SetDatabaseAdapter(&$db, $index=false)
{
- return ADODB_SetDatabaseAdapter($db);
+ return ADODB_SetDatabaseAdapter($db, $index);
}
-
- // php4 constructor
- function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
+
+
+ public function __set($name, $value)
{
- ADODB_Active_Record::__construct($table,$pkeyarr,$db);
+ $name = str_replace(' ', '_', $name);
+ $this->$name = $value;
}
-
+
// php5 constructor
function __construct($table = false, $pkeyarr=false, $db=false)
{
- global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
-
+ global $_ADODB_ACTIVE_DBS, $ADODB_QUOTE_FIELDNAMES;
+
+ // Set the local override for field quoting, only if not defined yet
+ if (!isset($this->_quoteNames)) {
+ $this->_quoteNames = $ADODB_QUOTE_FIELDNAMES;
+ }
+
if ($db == false && is_object($pkeyarr)) {
$db = $pkeyarr;
$pkeyarr = false;
}
-
- if (!$table) {
- if (!empty($this->_table)) $table = $this->_table;
+
+ if (!$table) {
+ if (!empty($this->_table)) {
+ $table = $this->_table;
+ }
else $table = $this->_pluralize(get_class($this));
}
+ $this->foreignName = strtolower(get_class($this)); // CFR: default foreign name
if ($db) {
$this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
- } else
- $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
-
-
- if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
-
+ } else if (!isset($this->_dbat)) {
+ if (sizeof($_ADODB_ACTIVE_DBS) == 0) {
+ $this->Error(
+ "No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",
+ 'ADODB_Active_Record::__constructor'
+ );
+ }
+ end($_ADODB_ACTIVE_DBS);
+ $this->_dbat = key($_ADODB_ACTIVE_DBS);
+ }
+
$this->_table = $table;
$this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
+
$this->UpdateActiveTable($pkeyarr);
}
-
+
function __wakeup()
{
$class = get_class($this);
new $class;
}
-
+
function _pluralize($table)
{
+ if (!ADODB_Active_Record::$_changeNames) {
+ return $table;
+ }
+
$ut = strtoupper($table);
$len = strlen($table);
$lastc = $ut[$len-1];
$lastc2 = substr($ut,$len-2);
switch ($lastc) {
case 'S':
- return $table.'es';
+ return $table.'es';
case 'Y':
return substr($table,0,$len-1).'ies';
- case 'X':
+ case 'X':
return $table.'es';
- case 'H':
- if ($lastc2 == 'CH' || $lastc2 == 'SH')
+ case 'H':
+ if ($lastc2 == 'CH' || $lastc2 == 'SH') {
return $table.'es';
+ }
default:
return $table.'s';
}
}
-
+
+ // CFR Lamest singular inflector ever - @todo Make it real!
+ // Note: There is an assumption here...and it is that the argument's length >= 4
+ function _singularize($tables)
+ {
+
+ if (!ADODB_Active_Record::$_changeNames) {
+ return $table;
+ }
+
+ $ut = strtoupper($tables);
+ $len = strlen($tables);
+ if($ut[$len-1] != 'S') {
+ return $tables; // I know...forget oxen
+ }
+ if($ut[$len-2] != 'E') {
+ return substr($tables, 0, $len-1);
+ }
+ switch($ut[$len-3]) {
+ case 'S':
+ case 'X':
+ return substr($tables, 0, $len-2);
+ case 'I':
+ return substr($tables, 0, $len-3) . 'y';
+ case 'H';
+ if($ut[$len-4] == 'C' || $ut[$len-4] == 'S') {
+ return substr($tables, 0, $len-2);
+ }
+ default:
+ return substr($tables, 0, $len-1); // ?
+ }
+ }
+
+ function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+ {
+ $ar = new $foreignClass($foreignRef);
+ $ar->foreignName = $foreignRef;
+ $ar->UpdateActiveTable();
+ $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
+ $table =& $this->TableInfo();
+ $table->_hasMany[$foreignRef] = $ar;
+ # $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
+ }
+
+ // use when you don't want ADOdb to auto-pluralize tablename
+ static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+ {
+ $ar = new ADODB_Active_Record($table);
+ $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
+ }
+
+ // use when you don't want ADOdb to auto-pluralize tablename
+ static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+ {
+ if (!is_array($tablePKey)) {
+ $tablePKey = array($tablePKey);
+ }
+ $ar = new ADODB_Active_Record($table,$tablePKey);
+ $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
+ }
+
+
+ // use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined.
+ // e.g. class Person will generate relationship for table Persons
+ static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
+ {
+ $ar = new $parentclass();
+ $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
+ }
+
+
+ function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+ {
+ global $inflector;
+
+ $ar = new $parentClass($this->_pluralize($foreignRef));
+ $ar->foreignName = $foreignRef;
+ $ar->parentKey = $parentKey;
+ $ar->UpdateActiveTable();
+ $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
+
+ $table =& $this->TableInfo();
+ $table->_belongsTo[$foreignRef] = $ar;
+ # $this->$foreignRef = $this->_belongsTo[$foreignRef];
+ }
+
+ static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+ {
+ $ar = new $class();
+ $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
+ }
+
+ static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+ {
+ $ar = new ADOdb_Active_Record($table);
+ $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
+ }
+
+ static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
+ {
+ if (!is_array($tablePKey)) {
+ $tablePKey = array($tablePKey);
+ }
+ $ar = new ADOdb_Active_Record($table, $tablePKey);
+ $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
+ }
+
+
+ /**
+ * __get Access properties - used for lazy loading
+ *
+ * @param mixed $name
+ * @access protected
+ * @return mixed
+ */
+ function __get($name)
+ {
+ return $this->LoadRelations($name, '', -1, -1);
+ }
+
+ /**
+ * @param string $name
+ * @param string $whereOrderBy : eg. ' AND field1 = value ORDER BY field2'
+ * @param offset
+ * @param limit
+ * @return mixed
+ */
+ function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1)
+ {
+ $extras = array();
+ $table = $this->TableInfo();
+ if ($limit >= 0) {
+ $extras['limit'] = $limit;
+ }
+ if ($offset >= 0) {
+ $extras['offset'] = $offset;
+ }
+
+ if (strlen($whereOrderBy)) {
+ if (!preg_match('/^[ \n\r]*AND/i', $whereOrderBy)) {
+ if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i', $whereOrderBy)) {
+ $whereOrderBy = 'AND ' . $whereOrderBy;
+ }
+ }
+ }
+
+ if(!empty($table->_belongsTo[$name])) {
+ $obj = $table->_belongsTo[$name];
+ $columnName = $obj->foreignKey;
+ if(empty($this->$columnName)) {
+ $this->$name = null;
+ }
+ else {
+ if ($obj->parentKey) {
+ $key = $obj->parentKey;
+ }
+ else {
+ $key = reset($table->keys);
+ }
+
+ $arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras);
+ if ($arrayOfOne) {
+ $this->$name = $arrayOfOne[0];
+ return $arrayOfOne[0];
+ }
+ }
+ }
+ if(!empty($table->_hasMany[$name])) {
+ $obj = $table->_hasMany[$name];
+ $key = reset($table->keys);
+ $id = @$this->$key;
+ if (!is_numeric($id)) {
+ $db = $this->DB();
+ $id = $db->qstr($id);
+ }
+ $objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras);
+ if (!$objs) {
+ $objs = array();
+ }
+ $this->$name = $objs;
+ return $objs;
+ }
+
+ return array();
+ }
//////////////////////////////////
-
+
// update metadata
function UpdateActiveTable($pkeys=false,$forceUpdate=false)
{
- global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
-
- $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];
+ global $_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
+ global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE;
+
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
$table = $this->_table;
$tables = $activedb->tables;
$tableat = $this->_tableat;
if (!$forceUpdate && !empty($tables[$tableat])) {
- $tobj =& $tables[$tableat];
- foreach($tobj->flds as $name => $fld)
- $this->$name = null;
+
+ $acttab = $tables[$tableat];
+ foreach($acttab->flds as $name => $fld) {
+ if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) {
+ $this->$name = $fld->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
+ }
return;
}
-
- $db =& $activedb->db;
+ $db = $activedb->db;
$fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
$fp = fopen($fname,'r');
@flock($fp, LOCK_SH);
$acttab = unserialize(fread($fp,100000));
fclose($fp);
- if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
+ if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
// abs(rand()) randomizes deletion, reducing contention to delete/refresh file
// ideally, you should cache at least 32 secs
+
+ foreach($acttab->flds as $name => $fld) {
+ if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) {
+ $this->$name = $fld->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
+ }
+
$activedb->tables[$table] = $acttab;
-
+
//if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
return;
} else if ($db->debug) {
@@ -168,11 +428,22 @@ function UpdateActiveTable($pkeys=false,$forceUpdate=false)
}
$activetab = new ADODB_Active_Table();
$activetab->name = $table;
-
-
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ if ($db->fetchMode !== false) {
+ $savem = $db->SetFetchMode(false);
+ }
+
$cols = $db->MetaColumns($table);
+
+ if (isset($savem)) {
+ $db->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
if (!$cols) {
- $this->Error("Invalid table name: $table",'UpdateActiveTable');
+ $this->Error("Invalid table name: $table",'UpdateActiveTable');
return false;
}
$fld = reset($cols);
@@ -180,186 +451,293 @@ function UpdateActiveTable($pkeys=false,$forceUpdate=false)
if (isset($fld->primary_key)) {
$pkeys = array();
foreach($cols as $name => $fld) {
- if (!empty($fld->primary_key)) $pkeys[] = $name;
+ if (!empty($fld->primary_key)) {
+ $pkeys[] = $name;
+ }
}
- } else
+ } else
$pkeys = $this->GetPrimaryKeys($db, $table);
}
if (empty($pkeys)) {
$this->Error("No primary key found for table $table",'UpdateActiveTable');
return false;
}
-
+
$attr = array();
$keys = array();
-
- switch($ADODB_ASSOC_CASE) {
- case 0:
+
+ switch (ADODB_ASSOC_CASE) {
+ case ADODB_ASSOC_CASE_LOWER:
foreach($cols as $name => $fldobj) {
$name = strtolower($name);
- $this->$name = null;
+ if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
+ $this->$name = $fldobj->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
$attr[$name] = $fldobj;
}
foreach($pkeys as $k => $name) {
$keys[strtolower($name)] = strtolower($name);
}
break;
-
- case 1:
+
+ case ADODB_ASSOC_CASE_UPPER:
foreach($cols as $name => $fldobj) {
$name = strtoupper($name);
- $this->$name = null;
+
+ if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
+ $this->$name = $fldobj->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
$attr[$name] = $fldobj;
}
-
+
foreach($pkeys as $k => $name) {
$keys[strtoupper($name)] = strtoupper($name);
}
break;
default:
foreach($cols as $name => $fldobj) {
- $name = ($name);
- $this->$name = null;
+
+ if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
+ $this->$name = $fldobj->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
$attr[$name] = $fldobj;
}
foreach($pkeys as $k => $name) {
- $keys[$name] = ($name);
+ $keys[$name] = $cols[strtoupper($name)]->name;
}
break;
}
-
+
$activetab->keys = $keys;
$activetab->flds = $attr;
if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
$activetab->_created = time();
$s = serialize($activetab);
- if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
+ if (!function_exists('adodb_write_file')) {
+ include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+ }
adodb_write_file($fname,$s);
}
+ if (isset($activedb->tables[$table])) {
+ $oldtab = $activedb->tables[$table];
+
+ if ($oldtab) {
+ $activetab->_belongsTo = $oldtab->_belongsTo;
+ $activetab->_hasMany = $oldtab->_hasMany;
+ }
+ }
$activedb->tables[$table] = $activetab;
}
-
+
function GetPrimaryKeys(&$db, $table)
{
return $db->MetaPrimaryKeys($table);
}
-
- // error handler for both PHP4+5.
+
+ // error handler for both PHP4+5.
function Error($err,$fn)
{
global $_ADODB_ACTIVE_DBS;
-
+
$fn = get_class($this).'::'.$fn;
$this->_lasterr = $fn.': '.$err;
-
- if ($this->_dbat < 0) $db = false;
+
+ if ($this->_dbat < 0) {
+ $db = false;
+ }
else {
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
- $db =& $activedb->db;
+ $db = $activedb->db;
}
-
- if (function_exists('adodb_throw')) {
- if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
- else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
- } else
- if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
-
+
+ if (function_exists('adodb_throw')) {
+ if (!$db) {
+ adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
+ }
+ else {
+ adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
+ }
+ } else {
+ if (!$db || $db->debug) {
+ ADOConnection::outp($this->_lasterr);
+ }
+ }
+
}
-
+
// return last error message
function ErrorMsg()
{
if (!function_exists('adodb_throw')) {
- if ($this->_dbat < 0) $db = false;
- else $db = $this->DB();
-
+ if ($this->_dbat < 0) {
+ $db = false;
+ }
+ else {
+ $db = $this->DB();
+ }
+
// last error could be database error too
- if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
+ if ($db && $db->ErrorMsg()) {
+ return $db->ErrorMsg();
+ }
}
return $this->_lasterr;
}
-
+
+ function ErrorNo()
+ {
+ if ($this->_dbat < 0) {
+ return -9999; // no database connection...
+ }
+ $db = $this->DB();
+
+ return (int) $db->ErrorNo();
+ }
+
+
// retrieve ADOConnection from _ADODB_Active_DBs
- function &DB()
+ function DB()
{
global $_ADODB_ACTIVE_DBS;
-
+
if ($this->_dbat < 0) {
$false = false;
$this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
return $false;
}
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
- $db =& $activedb->db;
+ $db = $activedb->db;
return $db;
}
-
+
// retrieve ADODB_Active_Table
function &TableInfo()
{
global $_ADODB_ACTIVE_DBS;
-
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
- $table =& $activedb->tables[$this->_tableat];
+ $table = $activedb->tables[$this->_tableat];
return $table;
}
-
+
+
+ // I have an ON INSERT trigger on a table that sets other columns in the table.
+ // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
+ function Reload()
+ {
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table = $this->TableInfo();
+ $where = $this->GenWhere($db, $table);
+ return($this->Load($where));
+ }
+
+
// set a numeric array (using natural table field ordering) as object properties
function Set(&$row)
{
- $db =& $this->DB();
-
+ global $ACTIVE_RECORD_SAFETY;
+
+ $db = $this->DB();
+
if (!$row) {
- $this->_saved = false;
+ $this->_saved = false;
return false;
}
-
+
$this->_saved = true;
-
- $table =& $this->TableInfo();
- if (sizeof($table->flds) != sizeof($row)) {
+
+ $table = $this->TableInfo();
+ if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
+ #
+ $bad_size = TRUE;
+ if (sizeof($row) == 2 * sizeof($table->flds)) {
+ // Only keep string keys
+ $keys = array_filter(array_keys($row), 'is_string');
+ if (sizeof($keys) == sizeof($table->flds)) {
+ $bad_size = FALSE;
+ }
+ }
+ if ($bad_size) {
$this->Error("Table structure of $this->_table has changed","Load");
return false;
}
-
- $cnt = 0;
+ #
+ }
+ else
+ $keys = array_keys($row);
+
+ #
+ reset($keys);
+ $this->_original = array();
foreach($table->flds as $name=>$fld) {
- $this->$name = $row[$cnt];
- $cnt += 1;
+ $value = $row[current($keys)];
+ $this->$name = $value;
+ $this->_original[] = $value;
+ next($keys);
}
- $this->_original = $row;
+
+ #
return true;
}
-
+
// get last inserted id for INSERT
function LastInsertID(&$db,$fieldname)
{
- if ($db->hasInsertID)
+ if ($db->hasInsertID) {
$val = $db->Insert_ID($this->_table,$fieldname);
- else
+ }
+ else {
$val = false;
-
- if (is_null($val) || $val === false) {
+ }
+
+ if (is_null($val) || $val === false)
+ {
+ $SQL = sprintf("SELECT MAX(%s) FROM %s",
+ $this->nameQuoter($db,$fieldname),
+ $this->nameQuoter($db,$this->_table)
+ );
// this might not work reliably in multi-user environment
- return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
+ return $db->GetOne($SQL);
}
return $val;
}
-
+
// quote data in where clause
function doquote(&$db, $val,$t)
{
switch($t) {
+ case 'L':
+ if (strpos($db->databaseType,'postgres') !== false) {
+ return $db->qstr($val);
+ }
case 'D':
case 'T':
- if (empty($val)) return 'null';
-
+ if (empty($val)) {
+ return 'null';
+ }
+ case 'B':
+ case 'N':
case 'C':
case 'X':
- if (is_null($val)) return 'null';
-
- if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") {
+ if (is_null($val)) {
+ return 'null';
+ }
+
+ if (strlen($val)>0 &&
+ (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")
+ ) {
return $db->qstr($val);
break;
}
@@ -368,78 +746,155 @@ function doquote(&$db, $val,$t)
break;
}
}
-
+
// generate where clause for an UPDATE/SELECT
function GenWhere(&$db, &$table)
{
$keys = $table->keys;
$parr = array();
-
+
foreach($keys as $k) {
$f = $table->flds[$k];
if ($f) {
- $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
+ $columnName = $this->nameQuoter($db,$k);
+ $parr[] = $columnName.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
}
}
- return implode(' and ', $parr);
+ return implode(' AND ', $parr);
}
-
-
+
+
+ function _QName($n,$db=false)
+ {
+ if (!ADODB_Active_Record::$_quoteNames) {
+ return $n;
+ }
+ if (!$db) {
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ }
+ return $db->nameQuote.$n.$db->nameQuote;
+ }
+
//------------------------------------------------------------ Public functions below
-
- function Load($where,$bindarr=false)
+
+ function Load($where=null,$bindarr=false, $lock = false)
{
- $db =& $this->DB(); if (!$db) return false;
+ global $ADODB_FETCH_MODE;
+
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
$this->_where = $where;
-
- $save = $db->SetFetchMode(ADODB_FETCH_NUM);
- $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
- $db->SetFetchMode($save);
-
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($db->fetchMode !== false) {
+ $savem = $db->SetFetchMode(false);
+ }
+
+ $qry = sprintf("SELECT * FROM %s",
+ $this->nameQuoter($db,$this->_table)
+ );
+
+ if($where) {
+ $qry .= ' WHERE '.$where;
+ }
+ if ($lock) {
+ $qry .= $this->lockMode;
+ }
+
+ $row = $db->GetRow($qry,$bindarr);
+
+ if (isset($savem)) {
+ $db->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
return $this->Set($row);
}
-
+
+ function LoadLocked($where=null, $bindarr=false)
+ {
+ $this->Load($where,$bindarr,true);
+ }
+
+ # useful for multiple record inserts
+ # see PHPLens Issue No: 17795
+ function Reset()
+ {
+ $this->_where=null;
+ $this->_saved = false;
+ $this->_lasterr = false;
+ $this->_original = false;
+ $vars=get_object_vars($this);
+ foreach($vars as $k=>$v){
+ if(substr($k,0,1)!=='_'){
+ $this->{$k}=null;
+ }
+ }
+ $this->foreignName=strtolower(get_class($this));
+ return true;
+ }
+
// false on error
function Save()
{
- if ($this->_saved) $ok = $this->Update();
- else $ok = $this->Insert();
-
+ if ($this->_saved) {
+ $ok = $this->Update();
+ }
+ else {
+ $ok = $this->Insert();
+ }
+
return $ok;
}
-
+
+
// false on error
function Insert()
{
- $db =& $this->DB(); if (!$db) return false;
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
$cnt = 0;
- $table =& $this->TableInfo();
-
+ $table = $this->TableInfo();
+
$valarr = array();
$names = array();
$valstr = array();
foreach($table->flds as $name=>$fld) {
$val = $this->$name;
- if(!is_null($val) || !array_key_exists($name, $table->keys)) {
+ if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) {
$valarr[] = $val;
- $names[] = $name;
+ $names[] = $this->nameQuoter($db,$name);
$valstr[] = $db->Param($cnt);
$cnt += 1;
}
}
-
+
if (empty($names)){
foreach($table->flds as $name=>$fld) {
$valarr[] = null;
- $names[] = $name;
+ $names[] = $this->nameQuoter($db,$name);
$valstr[] = $db->Param($cnt);
$cnt += 1;
}
}
- $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
+
+ $tableName = $this->nameQuoter($db,$this->_table);
+ $sql = sprintf('INSERT INTO %s (%s) VALUES (%s)',
+ $tableName,
+ implode(',',$names),
+ implode(',',$valstr)
+ );
$ok = $db->Execute($sql,$valarr);
-
+
if ($ok) {
$this->_saved = true;
$autoinc = false;
@@ -454,47 +909,63 @@ function Insert()
$this->$k = $this->LastInsertID($db,$k);
}
}
-
+
$this->_original = $valarr;
return !empty($ok);
}
-
+
function Delete()
{
- $db =& $this->DB(); if (!$db) return false;
- $table =& $this->TableInfo();
-
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table = $this->TableInfo();
+
$where = $this->GenWhere($db,$table);
- $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
+
+ $tableName = $this->nameQuoter($db,$this->_table);
+
+ $sql = sprintf('DELETE FROM %s WHERE %s',
+ $tableName,
+ $where
+ );
+
$ok = $db->Execute($sql);
-
+
return $ok ? true : false;
}
-
+
// returns an array of active record objects
- function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
+ function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
{
- $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
- $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
+ $db = $this->DB();
+ if (!$db || empty($this->_table)) {
+ return false;
+ }
+ $arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra);
return $arr;
}
-
+
// returns 0 on error, 1 on update, 2 on insert
function Replace()
{
- global $ADODB_ASSOC_CASE;
-
- $db =& $this->DB(); if (!$db) return false;
- $table =& $this->TableInfo();
-
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table = $this->TableInfo();
+
$pkey = $table->keys;
-
+
foreach($table->flds as $name=>$fld) {
$val = $this->$name;
/*
if (is_null($val)) {
if (isset($fld->not_null) && $fld->not_null) {
- if (isset($fld->default_value) && strlen($fld->default_value)) continue;
+ if (isset($fld->default_value) && strlen($fld->default_value)) {
+ continue;
+ }
else {
$this->Error("Cannot update null into $name","Replace");
return false;
@@ -502,24 +973,48 @@ function Replace()
}
}*/
if (is_null($val) && !empty($fld->auto_increment)) {
- continue;
- }
+ continue;
+ }
+
+ if (is_array($val)) {
+ continue;
+ }
+
$t = $db->MetaType($fld->type);
$arr[$name] = $this->doquote($db,$val,$t);
$valarr[] = $val;
}
-
- if (!is_array($pkey)) $pkey = array($pkey);
-
-
- if ($ADODB_ASSOC_CASE == 0)
- foreach($pkey as $k => $v)
- $pkey[$k] = strtolower($v);
- elseif ($ADODB_ASSOC_CASE == 0)
- foreach($pkey as $k => $v)
- $pkey[$k] = strtoupper($v);
-
- $ok = $db->Replace($this->_table,$arr,$pkey);
+
+ if (!is_array($pkey)) {
+ $pkey = array($pkey);
+ }
+
+ switch (ADODB_ASSOC_CASE) {
+ case ADODB_ASSOC_CASE_LOWER:
+ foreach ($pkey as $k => $v) {
+ $pkey[$k] = strtolower($v);
+ }
+ break;
+ case ADODB_ASSOC_CASE_UPPER:
+ foreach ($pkey as $k => $v) {
+ $pkey[$k] = strtoupper($v);
+ }
+ break;
+ }
+
+ $newArr = array();
+ foreach($arr as $k=>$v)
+ $newArr[$this->nameQuoter($db,$k)] = $v;
+ $arr = $newArr;
+
+ $newPkey = array();
+ foreach($pkey as $k=>$v)
+ $newPkey[$k] = $this->nameQuoter($db,$v);
+ $pkey = $newPkey;
+
+ $tableName = $this->nameQuoter($db,$this->_table);
+
+ $ok = $db->Replace($tableName,$arr,$pkey);
if ($ok) {
$this->_saved = true; // 1= update 2=insert
if ($ok == 2) {
@@ -535,25 +1030,28 @@ function Replace()
$this->$k = $this->LastInsertID($db,$k);
}
}
-
- $this->_original =& $valarr;
- }
+
+ $this->_original = $valarr;
+ }
return $ok;
}
// returns 0 on error, 1 on update, -1 if no change in data (no update)
function Update()
{
- $db =& $this->DB(); if (!$db) return false;
- $table =& $this->TableInfo();
-
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table = $this->TableInfo();
+
$where = $this->GenWhere($db, $table);
-
+
if (!$where) {
$this->error("Where missing for table $table", "Update");
return false;
}
- $valarr = array();
+ $valarr = array();
$neworig = array();
$pairs = array();
$i = -1;
@@ -562,47 +1060,151 @@ function Update()
$i += 1;
$val = $this->$name;
$neworig[] = $val;
-
- if (isset($table->keys[$name])) {
+
+ if (isset($table->keys[$name]) || is_array($val)) {
continue;
}
-
+
if (is_null($val)) {
if (isset($fld->not_null) && $fld->not_null) {
- if (isset($fld->default_value) && strlen($fld->default_value)) continue;
+ if (isset($fld->default_value) && strlen($fld->default_value)) {
+ continue;
+ }
else {
$this->Error("Cannot set field $name to NULL","Update");
return false;
}
}
}
-
- if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
+
+ if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) {
+ continue;
+ }
+
+ if (is_null($this->_original[$i]) && is_null($val)) {
continue;
- }
+ }
+
$valarr[] = $val;
- $pairs[] = $name.'='.$db->Param($cnt);
+ $pairs[] = $this->nameQuoter($db,$name).'='.$db->Param($cnt);
$cnt += 1;
}
-
-
- if (!$cnt) return -1;
- $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
+
+
+ if (!$cnt) {
+ return -1;
+ }
+
+ $tableName = $this->nameQuoter($db,$this->_table);
+
+ $sql = sprintf('UPDATE %s SET %s WHERE %s',
+ $tableName,
+ implode(',',$pairs),
+ $where);
+
$ok = $db->Execute($sql,$valarr);
if ($ok) {
- $this->_original =& $neworig;
+ $this->_original = $neworig;
return 1;
}
return 0;
}
-
+
function GetAttributeNames()
{
- $table =& $this->TableInfo();
- if (!$table) return false;
+ $table = $this->TableInfo();
+ if (!$table) {
+ return false;
+ }
return array_keys($table->flds);
}
-
+
+ /**
+ * Quotes the table, column and field names.
+ *
+ * This honours the internal {@see $_quoteNames} property, which overrides
+ * the global $ADODB_QUOTE_FIELDNAMES directive.
+ *
+ * @param ADOConnection $db The database connection
+ * @param string $name The table or column name to quote
+ *
+ * @return string The quoted name
+ */
+ private function nameQuoter($db, $name)
+ {
+ global $ADODB_QUOTE_FIELDNAMES;
+
+ $save = $ADODB_QUOTE_FIELDNAMES;
+ $ADODB_QUOTE_FIELDNAMES = $this->_quoteNames;
+
+ $string = _adodb_quote_fieldname($db, $name);
+
+ $ADODB_QUOTE_FIELDNAMES = $save;
+
+ return $string;
+ }
+
};
-?>
\ No newline at end of file
+function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
+ $extra)
+{
+global $_ADODB_ACTIVE_DBS;
+
+
+ $save = $db->SetFetchMode(ADODB_FETCH_NUM);
+
+ $qry = "select * from ".$table;
+
+ if (!empty($whereOrderBy)) {
+ $qry .= ' WHERE '.$whereOrderBy;
+ }
+ if(isset($extra['limit'])) {
+ $rows = false;
+ if(isset($extra['offset'])) {
+ $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset'],$bindarr);
+ } else {
+ $rs = $db->SelectLimit($qry, $extra['limit'],-1,$bindarr);
+ }
+ if ($rs) {
+ while (!$rs->EOF) {
+ $rows[] = $rs->fields;
+ $rs->MoveNext();
+ }
+ }
+ } else
+ $rows = $db->GetAll($qry,$bindarr);
+
+ $db->SetFetchMode($save);
+
+ $false = false;
+
+ if ($rows === false) {
+ return $false;
+ }
+
+
+ if (!class_exists($class)) {
+ $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
+ return $false;
+ }
+ $arr = array();
+ // arrRef will be the structure that knows about our objects.
+ // It is an associative array.
+ // We will, however, return arr, preserving regular 0.. order so that
+ // obj[0] can be used by app developers.
+ $arrRef = array();
+ $bTos = array(); // Will store belongTo's indices if any
+ foreach($rows as $row) {
+
+ $obj = new $class($table,$primkeyArr,$db);
+ if ($obj->ErrorNo()){
+ $db->_errorMsg = $obj->ErrorMsg();
+ return $false;
+ }
+ $obj->Set($row);
+ $arr[] = $obj;
+ } // foreach($rows as $row)
+
+ return $arr;
+}
diff --git a/adodb/adodb-active-recordx.inc.php b/adodb/adodb-active-recordx.inc.php
new file mode 100644
index 0000000..5de5b13
--- /dev/null
+++ b/adodb/adodb-active-recordx.inc.php
@@ -0,0 +1,1489 @@
+_dbat
+$_ADODB_ACTIVE_DBS = array();
+$ACTIVE_RECORD_SAFETY = true; // CFR: disabled while playing with relations
+$ADODB_ACTIVE_DEFVALS = false;
+
+class ADODB_Active_DB {
+ var $db; // ADOConnection
+ var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
+}
+
+class ADODB_Active_Table {
+ var $name; // table name
+ var $flds; // assoc array of adofieldobjs, indexed by fieldname
+ var $keys; // assoc array of primary keys, indexed by fieldname
+ var $_created; // only used when stored as a cached file
+ var $_belongsTo = array();
+ var $_hasMany = array();
+ var $_colsCount; // total columns count, including relations
+
+ function updateColsCount()
+ {
+ $this->_colsCount = sizeof($this->flds);
+ foreach($this->_belongsTo as $foreignTable)
+ $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
+ foreach($this->_hasMany as $foreignTable)
+ $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
+ }
+}
+
+// returns index into $_ADODB_ACTIVE_DBS
+function ADODB_SetDatabaseAdapter(&$db)
+{
+ global $_ADODB_ACTIVE_DBS;
+
+ foreach($_ADODB_ACTIVE_DBS as $k => $d) {
+ if ($d->db === $db) {
+ return $k;
+ }
+ }
+
+ $obj = new ADODB_Active_DB();
+ $obj->db = $db;
+ $obj->tables = array();
+
+ $_ADODB_ACTIVE_DBS[] = $obj;
+
+ return sizeof($_ADODB_ACTIVE_DBS)-1;
+}
+
+
+class ADODB_Active_Record {
+ static $_changeNames = true; // dynamically pluralize table names
+ static $_foreignSuffix = '_id'; //
+ var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
+ var $_table; // tablename, if set in class definition then use it as table name
+ var $_sTable; // singularized table name
+ var $_pTable; // pluralized table name
+ var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
+ var $_where; // where clause set in Load()
+ var $_saved = false; // indicates whether data is already inserted.
+ var $_lasterr = false; // last error message
+ var $_original = false; // the original values loaded or inserted, refreshed on update
+
+ var $foreignName; // CFR: class name when in a relationship
+
+ static function UseDefaultValues($bool=null)
+ {
+ global $ADODB_ACTIVE_DEFVALS;
+ if (isset($bool)) {
+ $ADODB_ACTIVE_DEFVALS = $bool;
+ }
+ return $ADODB_ACTIVE_DEFVALS;
+ }
+
+ // should be static
+ static function SetDatabaseAdapter(&$db)
+ {
+ return ADODB_SetDatabaseAdapter($db);
+ }
+
+
+ public function __set($name, $value)
+ {
+ $name = str_replace(' ', '_', $name);
+ $this->$name = $value;
+ }
+
+ // php5 constructor
+ // Note: if $table is defined, then we will use it as our table name
+ // Otherwise we will use our classname...
+ // In our database, table names are pluralized (because there can be
+ // more than one row!)
+ // Similarly, if $table is defined here, it has to be plural form.
+ //
+ // $options is an array that allows us to tweak the constructor's behaviour
+ // if $options['refresh'] is true, we re-scan our metadata information
+ // if $options['new'] is true, we forget all relations
+ function __construct($table = false, $pkeyarr=false, $db=false, $options=array())
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ if ($db == false && is_object($pkeyarr)) {
+ $db = $pkeyarr;
+ $pkeyarr = false;
+ }
+
+ if($table) {
+ // table argument exists. It is expected to be
+ // already plural form.
+ $this->_pTable = $table;
+ $this->_sTable = $this->_singularize($this->_pTable);
+ }
+ else {
+ // We will use current classname as table name.
+ // We need to pluralize it for the real table name.
+ $this->_sTable = strtolower(get_class($this));
+ $this->_pTable = $this->_pluralize($this->_sTable);
+ }
+ $this->_table = &$this->_pTable;
+
+ $this->foreignName = $this->_sTable; // CFR: default foreign name (singular)
+
+ if ($db) {
+ $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
+ } else
+ $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
+
+
+ if ($this->_dbat < 0) {
+ $this->Error(
+ "No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",
+ 'ADODB_Active_Record::__constructor'
+ );
+ }
+
+ $this->_tableat = $this->_table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
+
+ // CFR: Just added this option because UpdateActiveTable() can refresh its information
+ // but there was no way to ask it to do that.
+ $forceUpdate = (isset($options['refresh']) && true === $options['refresh']);
+ $this->UpdateActiveTable($pkeyarr, $forceUpdate);
+ if(isset($options['new']) && true === $options['new']) {
+ $table =& $this->TableInfo();
+ unset($table->_hasMany);
+ unset($table->_belongsTo);
+ $table->_hasMany = array();
+ $table->_belongsTo = array();
+ }
+ }
+
+ function __wakeup()
+ {
+ $class = get_class($this);
+ new $class;
+ }
+
+ // CFR: Constants found in Rails
+ static $IrregularP = array(
+ 'PERSON' => 'people',
+ 'MAN' => 'men',
+ 'WOMAN' => 'women',
+ 'CHILD' => 'children',
+ 'COW' => 'kine',
+ );
+
+ static $IrregularS = array(
+ 'PEOPLE' => 'PERSON',
+ 'MEN' => 'man',
+ 'WOMEN' => 'woman',
+ 'CHILDREN' => 'child',
+ 'KINE' => 'cow',
+ );
+
+ static $WeIsI = array(
+ 'EQUIPMENT' => true,
+ 'INFORMATION' => true,
+ 'RICE' => true,
+ 'MONEY' => true,
+ 'SPECIES' => true,
+ 'SERIES' => true,
+ 'FISH' => true,
+ 'SHEEP' => true,
+ );
+
+ function _pluralize($table)
+ {
+ if (!ADODB_Active_Record::$_changeNames) {
+ return $table;
+ }
+ $ut = strtoupper($table);
+ if(isset(self::$WeIsI[$ut])) {
+ return $table;
+ }
+ if(isset(self::$IrregularP[$ut])) {
+ return self::$IrregularP[$ut];
+ }
+ $len = strlen($table);
+ $lastc = $ut[$len-1];
+ $lastc2 = substr($ut,$len-2);
+ switch ($lastc) {
+ case 'S':
+ return $table.'es';
+ case 'Y':
+ return substr($table,0,$len-1).'ies';
+ case 'X':
+ return $table.'es';
+ case 'H':
+ if ($lastc2 == 'CH' || $lastc2 == 'SH') {
+ return $table.'es';
+ }
+ default:
+ return $table.'s';
+ }
+ }
+
+ // CFR Lamest singular inflector ever - @todo Make it real!
+ // Note: There is an assumption here...and it is that the argument's length >= 4
+ function _singularize($table)
+ {
+
+ if (!ADODB_Active_Record::$_changeNames) {
+ return $table;
+ }
+ $ut = strtoupper($table);
+ if(isset(self::$WeIsI[$ut])) {
+ return $table;
+ }
+ if(isset(self::$IrregularS[$ut])) {
+ return self::$IrregularS[$ut];
+ }
+ $len = strlen($table);
+ if($ut[$len-1] != 'S') {
+ return $table; // I know...forget oxen
+ }
+ if($ut[$len-2] != 'E') {
+ return substr($table, 0, $len-1);
+ }
+ switch($ut[$len-3]) {
+ case 'S':
+ case 'X':
+ return substr($table, 0, $len-2);
+ case 'I':
+ return substr($table, 0, $len-3) . 'y';
+ case 'H';
+ if($ut[$len-4] == 'C' || $ut[$len-4] == 'S') {
+ return substr($table, 0, $len-2);
+ }
+ default:
+ return substr($table, 0, $len-1); // ?
+ }
+ }
+
+ /*
+ * ar->foreignName will contain the name of the tables associated with this table because
+ * these other tables' rows may also be referenced by this table using theirname_id or the provided
+ * foreign keys (this index name is stored in ar->foreignKey)
+ *
+ * this-table.id = other-table-#1.this-table_id
+ * = other-table-#2.this-table_id
+ */
+ function hasMany($foreignRef,$foreignKey=false)
+ {
+ $ar = new ADODB_Active_Record($foreignRef);
+ $ar->foreignName = $foreignRef;
+ $ar->UpdateActiveTable();
+ $ar->foreignKey = ($foreignKey) ? $foreignKey : strtolower(get_class($this)) . self::$_foreignSuffix;
+
+ $table =& $this->TableInfo();
+ if(!isset($table->_hasMany[$foreignRef])) {
+ $table->_hasMany[$foreignRef] = $ar;
+ $table->updateColsCount();
+ }
+# @todo Can I make this guy be lazy?
+ $this->$foreignRef = $table->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
+ }
+
+ /**
+ * ar->foreignName will contain the name of the tables associated with this table because
+ * this table's rows may also be referenced by those tables using thistable_id or the provided
+ * foreign keys (this index name is stored in ar->foreignKey)
+ *
+ * this-table.other-table_id = other-table.id
+ */
+ function belongsTo($foreignRef,$foreignKey=false)
+ {
+ global $inflector;
+
+ $ar = new ADODB_Active_Record($this->_pluralize($foreignRef));
+ $ar->foreignName = $foreignRef;
+ $ar->UpdateActiveTable();
+ $ar->foreignKey = ($foreignKey) ? $foreignKey : $ar->foreignName . self::$_foreignSuffix;
+
+ $table =& $this->TableInfo();
+ if(!isset($table->_belongsTo[$foreignRef])) {
+ $table->_belongsTo[$foreignRef] = $ar;
+ $table->updateColsCount();
+ }
+ $this->$foreignRef = $table->_belongsTo[$foreignRef];
+ }
+
+ /**
+ * __get Access properties - used for lazy loading
+ *
+ * @param mixed $name
+ * @access protected
+ * @return void
+ */
+ function __get($name)
+ {
+ return $this->LoadRelations($name, '', -1. -1);
+ }
+
+ function LoadRelations($name, $whereOrderBy, $offset=-1, $limit=-1)
+ {
+ $extras = array();
+ if($offset >= 0) {
+ $extras['offset'] = $offset;
+ }
+ if($limit >= 0) {
+ $extras['limit'] = $limit;
+ }
+ $table =& $this->TableInfo();
+
+ if (strlen($whereOrderBy)) {
+ if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy)) {
+ if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy)) {
+ $whereOrderBy = 'AND '.$whereOrderBy;
+ }
+ }
+ }
+
+ if(!empty($table->_belongsTo[$name])) {
+ $obj = $table->_belongsTo[$name];
+ $columnName = $obj->foreignKey;
+ if(empty($this->$columnName)) {
+ $this->$name = null;
+ }
+ else {
+ if(($k = reset($obj->TableInfo()->keys))) {
+ $belongsToId = $k;
+ }
+ else {
+ $belongsToId = 'id';
+ }
+
+ $arrayOfOne =
+ $obj->Find(
+ $belongsToId.'='.$this->$columnName.' '.$whereOrderBy, false, false, $extras);
+ $this->$name = $arrayOfOne[0];
+ }
+ return $this->$name;
+ }
+ if(!empty($table->_hasMany[$name])) {
+ $obj = $table->_hasMany[$name];
+ if(($k = reset($table->keys))) {
+ $hasManyId = $k;
+ }
+ else {
+ $hasManyId = 'id';
+ }
+
+ $this->$name =
+ $obj->Find(
+ $obj->foreignKey.'='.$this->$hasManyId.' '.$whereOrderBy, false, false, $extras);
+ return $this->$name;
+ }
+ }
+ //////////////////////////////////
+
+ // update metadata
+ function UpdateActiveTable($pkeys=false,$forceUpdate=false)
+ {
+ global $_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
+ global $ADODB_ACTIVE_DEFVALS, $ADODB_FETCH_MODE;
+
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+
+ $table = $this->_table;
+ $tables = $activedb->tables;
+ $tableat = $this->_tableat;
+ if (!$forceUpdate && !empty($tables[$tableat])) {
+
+ $tobj = $tables[$tableat];
+ foreach($tobj->flds as $name => $fld) {
+ if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) {
+ $this->$name = $fld->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
+ }
+ return;
+ }
+
+ $db = $activedb->db;
+ $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
+ if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
+ $fp = fopen($fname,'r');
+ @flock($fp, LOCK_SH);
+ $acttab = unserialize(fread($fp,100000));
+ fclose($fp);
+ if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
+ // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
+ // ideally, you should cache at least 32 secs
+ $activedb->tables[$table] = $acttab;
+
+ //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
+ return;
+ } else if ($db->debug) {
+ ADOConnection::outp("Refreshing cached active record file: $fname");
+ }
+ }
+ $activetab = new ADODB_Active_Table();
+ $activetab->name = $table;
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ if ($db->fetchMode !== false) {
+ $savem = $db->SetFetchMode(false);
+ }
+
+ $cols = $db->MetaColumns($table);
+
+ if (isset($savem)) {
+ $db->SetFetchMode($savem);
+ }
+ $ADODB_FETCH_MODE = $save;
+
+ if (!$cols) {
+ $this->Error("Invalid table name: $table",'UpdateActiveTable');
+ return false;
+ }
+ $fld = reset($cols);
+ if (!$pkeys) {
+ if (isset($fld->primary_key)) {
+ $pkeys = array();
+ foreach($cols as $name => $fld) {
+ if (!empty($fld->primary_key)) {
+ $pkeys[] = $name;
+ }
+ }
+ } else {
+ $pkeys = $this->GetPrimaryKeys($db, $table);
+ }
+ }
+ if (empty($pkeys)) {
+ $this->Error("No primary key found for table $table",'UpdateActiveTable');
+ return false;
+ }
+
+ $attr = array();
+ $keys = array();
+
+ switch (ADODB_ASSOC_CASE) {
+ case ADODB_ASSOC_CASE_LOWER:
+ foreach($cols as $name => $fldobj) {
+ $name = strtolower($name);
+ if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
+ $this->$name = $fldobj->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
+ $attr[$name] = $fldobj;
+ }
+ foreach($pkeys as $k => $name) {
+ $keys[strtolower($name)] = strtolower($name);
+ }
+ break;
+
+ case ADODB_ASSOC_CASE_UPPER:
+ foreach($cols as $name => $fldobj) {
+ $name = strtoupper($name);
+
+ if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
+ $this->$name = $fldobj->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
+ $attr[$name] = $fldobj;
+ }
+
+ foreach($pkeys as $k => $name) {
+ $keys[strtoupper($name)] = strtoupper($name);
+ }
+ break;
+ default:
+ foreach($cols as $name => $fldobj) {
+ $name = ($fldobj->name);
+
+ if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
+ $this->$name = $fldobj->default_value;
+ }
+ else {
+ $this->$name = null;
+ }
+ $attr[$name] = $fldobj;
+ }
+ foreach($pkeys as $k => $name) {
+ $keys[$name] = $cols[$name]->name;
+ }
+ break;
+ }
+
+ $activetab->keys = $keys;
+ $activetab->flds = $attr;
+ $activetab->updateColsCount();
+
+ if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
+ $activetab->_created = time();
+ $s = serialize($activetab);
+ if (!function_exists('adodb_write_file')) {
+ include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
+ }
+ adodb_write_file($fname,$s);
+ }
+ if (isset($activedb->tables[$table])) {
+ $oldtab = $activedb->tables[$table];
+
+ if ($oldtab) {
+ $activetab->_belongsTo = $oldtab->_belongsTo;
+ $activetab->_hasMany = $oldtab->_hasMany;
+ }
+ }
+ $activedb->tables[$table] = $activetab;
+ }
+
+ function GetPrimaryKeys(&$db, $table)
+ {
+ return $db->MetaPrimaryKeys($table);
+ }
+
+ // error handler for both PHP4+5.
+ function Error($err,$fn)
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ $fn = get_class($this).'::'.$fn;
+ $this->_lasterr = $fn.': '.$err;
+
+ if ($this->_dbat < 0) {
+ $db = false;
+ }
+ else {
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+ $db = $activedb->db;
+ }
+
+ if (function_exists('adodb_throw')) {
+ if (!$db) {
+ adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
+ }
+ else {
+ adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
+ }
+ } else {
+ if (!$db || $db->debug) {
+ ADOConnection::outp($this->_lasterr);
+ }
+ }
+
+ }
+
+ // return last error message
+ function ErrorMsg()
+ {
+ if (!function_exists('adodb_throw')) {
+ if ($this->_dbat < 0) {
+ $db = false;
+ }
+ else {
+ $db = $this->DB();
+ }
+
+ // last error could be database error too
+ if ($db && $db->ErrorMsg()) {
+ return $db->ErrorMsg();
+ }
+ }
+ return $this->_lasterr;
+ }
+
+ function ErrorNo()
+ {
+ if ($this->_dbat < 0) {
+ return -9999; // no database connection...
+ }
+ $db = $this->DB();
+
+ return (int) $db->ErrorNo();
+ }
+
+
+ // retrieve ADOConnection from _ADODB_Active_DBs
+ function DB()
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ if ($this->_dbat < 0) {
+ $false = false;
+ $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
+ return $false;
+ }
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+ $db = $activedb->db;
+ return $db;
+ }
+
+ // retrieve ADODB_Active_Table
+ function &TableInfo()
+ {
+ global $_ADODB_ACTIVE_DBS;
+
+ $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
+ $table = $activedb->tables[$this->_tableat];
+ return $table;
+ }
+
+
+ // I have an ON INSERT trigger on a table that sets other columns in the table.
+ // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
+ function Reload()
+ {
+ $db =& $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table =& $this->TableInfo();
+ $where = $this->GenWhere($db, $table);
+ return($this->Load($where));
+ }
+
+
+ // set a numeric array (using natural table field ordering) as object properties
+ function Set(&$row)
+ {
+ global $ACTIVE_RECORD_SAFETY;
+
+ $db = $this->DB();
+
+ if (!$row) {
+ $this->_saved = false;
+ return false;
+ }
+
+ $this->_saved = true;
+
+ $table = $this->TableInfo();
+ $sizeofFlds = sizeof($table->flds);
+ $sizeofRow = sizeof($row);
+ if ($ACTIVE_RECORD_SAFETY && $table->_colsCount != $sizeofRow && $sizeofFlds != $sizeofRow) {
+ #
+ $bad_size = TRUE;
+ if($sizeofRow == 2 * $table->_colsCount || $sizeofRow == 2 * $sizeofFlds) {
+ // Only keep string keys
+ $keys = array_filter(array_keys($row), 'is_string');
+ if (sizeof($keys) == sizeof($table->flds)) {
+ $bad_size = FALSE;
+ }
+ }
+ if ($bad_size) {
+ $this->Error("Table structure of $this->_table has changed","Load");
+ return false;
+ }
+ #
+ }
+ else {
+ $keys = array_keys($row);
+ }
+
+ #
+ reset($keys);
+ $this->_original = array();
+ foreach($table->flds as $name=>$fld) {
+ $value = $row[current($keys)];
+ $this->$name = $value;
+ $this->_original[] = $value;
+ if(!next($keys)) {
+ break;
+ }
+ }
+ $table =& $this->TableInfo();
+ foreach($table->_belongsTo as $foreignTable) {
+ $ft = $foreignTable->TableInfo();
+ $propertyName = $ft->name;
+ foreach($ft->flds as $name=>$fld) {
+ $value = $row[current($keys)];
+ $foreignTable->$name = $value;
+ $foreignTable->_original[] = $value;
+ if(!next($keys)) {
+ break;
+ }
+ }
+ }
+ foreach($table->_hasMany as $foreignTable) {
+ $ft = $foreignTable->TableInfo();
+ foreach($ft->flds as $name=>$fld) {
+ $value = $row[current($keys)];
+ $foreignTable->$name = $value;
+ $foreignTable->_original[] = $value;
+ if(!next($keys)) {
+ break;
+ }
+ }
+ }
+ #
+
+ return true;
+ }
+
+ // get last inserted id for INSERT
+ function LastInsertID(&$db,$fieldname)
+ {
+ if ($db->hasInsertID) {
+ $val = $db->Insert_ID($this->_table,$fieldname);
+ }
+ else {
+ $val = false;
+ }
+
+ if (is_null($val) || $val === false) {
+ // this might not work reliably in multi-user environment
+ return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
+ }
+ return $val;
+ }
+
+ // quote data in where clause
+ function doquote(&$db, $val,$t)
+ {
+ switch($t) {
+ case 'D':
+ case 'T':
+ if (empty($val)) {
+ return 'null';
+ }
+ case 'C':
+ case 'X':
+ if (is_null($val)) {
+ return 'null';
+ }
+ if (strlen($val)>0 &&
+ (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")
+ ) {
+ return $db->qstr($val);
+ break;
+ }
+ default:
+ return $val;
+ break;
+ }
+ }
+
+ // generate where clause for an UPDATE/SELECT
+ function GenWhere(&$db, &$table)
+ {
+ $keys = $table->keys;
+ $parr = array();
+
+ foreach($keys as $k) {
+ $f = $table->flds[$k];
+ if ($f) {
+ $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
+ }
+ }
+ return implode(' and ', $parr);
+ }
+
+
+ //------------------------------------------------------------ Public functions below
+
+ function Load($where=null,$bindarr=false)
+ {
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $this->_where = $where;
+
+ $save = $db->SetFetchMode(ADODB_FETCH_NUM);
+ $qry = "select * from ".$this->_table;
+ $table =& $this->TableInfo();
+
+ if(($k = reset($table->keys))) {
+ $hasManyId = $k;
+ }
+ else {
+ $hasManyId = 'id';
+ }
+
+ foreach($table->_belongsTo as $foreignTable) {
+ if(($k = reset($foreignTable->TableInfo()->keys))) {
+ $belongsToId = $k;
+ }
+ else {
+ $belongsToId = 'id';
+ }
+ $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+ $this->_table.'.'.$foreignTable->foreignKey.'='.
+ $foreignTable->_table.'.'.$belongsToId;
+ }
+ foreach($table->_hasMany as $foreignTable)
+ {
+ $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+ $this->_table.'.'.$hasManyId.'='.
+ $foreignTable->_table.'.'.$foreignTable->foreignKey;
+ }
+ if($where) {
+ $qry .= ' WHERE '.$where;
+ }
+
+ // Simple case: no relations. Load row and return.
+ if((count($table->_hasMany) + count($table->_belongsTo)) < 1) {
+ $row = $db->GetRow($qry,$bindarr);
+ if(!$row) {
+ return false;
+ }
+ $db->SetFetchMode($save);
+ return $this->Set($row);
+ }
+
+ // More complex case when relations have to be collated
+ $rows = $db->GetAll($qry,$bindarr);
+ if(!$rows) {
+ return false;
+ }
+ $db->SetFetchMode($save);
+ if(count($rows) < 1) {
+ return false;
+ }
+ $class = get_class($this);
+ $isFirstRow = true;
+
+ if(($k = reset($this->TableInfo()->keys))) {
+ $myId = $k;
+ }
+ else {
+ $myId = 'id';
+ }
+ $index = 0; $found = false;
+ /** @todo Improve by storing once and for all in table metadata */
+ /** @todo Also re-use info for hasManyId */
+ foreach($this->TableInfo()->flds as $fld) {
+ if($fld->name == $myId) {
+ $found = true;
+ break;
+ }
+ $index++;
+ }
+ if(!$found) {
+ $this->outp_throw("Unable to locate key $myId for $class in Load()",'Load');
+ }
+
+ foreach($rows as $row) {
+ $rowId = intval($row[$index]);
+ if($rowId > 0) {
+ if($isFirstRow) {
+ $isFirstRow = false;
+ if(!$this->Set($row)) {
+ return false;
+ }
+ }
+ $obj = new $class($table,false,$db);
+ $obj->Set($row);
+ // TODO Copy/paste code below: bad!
+ if(count($table->_hasMany) > 0) {
+ foreach($table->_hasMany as $foreignTable) {
+ $foreignName = $foreignTable->foreignName;
+ if(!empty($obj->$foreignName)) {
+ if(!is_array($this->$foreignName)) {
+ $foreignObj = $this->$foreignName;
+ $this->$foreignName = array(clone($foreignObj));
+ }
+ else {
+ $foreignObj = $obj->$foreignName;
+ array_push($this->$foreignName, clone($foreignObj));
+ }
+ }
+ }
+ }
+ if(count($table->_belongsTo) > 0) {
+ foreach($table->_belongsTo as $foreignTable) {
+ $foreignName = $foreignTable->foreignName;
+ if(!empty($obj->$foreignName)) {
+ if(!is_array($this->$foreignName)) {
+ $foreignObj = $this->$foreignName;
+ $this->$foreignName = array(clone($foreignObj));
+ }
+ else {
+ $foreignObj = $obj->$foreignName;
+ array_push($this->$foreignName, clone($foreignObj));
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ // false on error
+ function Save()
+ {
+ if ($this->_saved) {
+ $ok = $this->Update();
+ }
+ else {
+ $ok = $this->Insert();
+ }
+
+ return $ok;
+ }
+
+ // CFR: Sometimes we may wish to consider that an object is not to be replaced but inserted.
+ // Sample use case: an 'undo' command object (after a delete())
+ function Dirty()
+ {
+ $this->_saved = false;
+ }
+
+ // false on error
+ function Insert()
+ {
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $cnt = 0;
+ $table = $this->TableInfo();
+
+ $valarr = array();
+ $names = array();
+ $valstr = array();
+
+ foreach($table->flds as $name=>$fld) {
+ $val = $this->$name;
+ if(!is_null($val) || !array_key_exists($name, $table->keys)) {
+ $valarr[] = $val;
+ $names[] = $name;
+ $valstr[] = $db->Param($cnt);
+ $cnt += 1;
+ }
+ }
+
+ if (empty($names)){
+ foreach($table->flds as $name=>$fld) {
+ $valarr[] = null;
+ $names[] = $name;
+ $valstr[] = $db->Param($cnt);
+ $cnt += 1;
+ }
+ }
+ $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
+ $ok = $db->Execute($sql,$valarr);
+
+ if ($ok) {
+ $this->_saved = true;
+ $autoinc = false;
+ foreach($table->keys as $k) {
+ if (is_null($this->$k)) {
+ $autoinc = true;
+ break;
+ }
+ }
+ if ($autoinc && sizeof($table->keys) == 1) {
+ $k = reset($table->keys);
+ $this->$k = $this->LastInsertID($db,$k);
+ }
+ }
+
+ $this->_original = $valarr;
+ return !empty($ok);
+ }
+
+ function Delete()
+ {
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table = $this->TableInfo();
+
+ $where = $this->GenWhere($db,$table);
+ $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
+ $ok = $db->Execute($sql);
+
+ return $ok ? true : false;
+ }
+
+ // returns an array of active record objects
+ function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
+ {
+ $db = $this->DB();
+ if (!$db || empty($this->_table)) {
+ return false;
+ }
+ $table =& $this->TableInfo();
+ $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
+ array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
+ return $arr;
+ }
+
+ // CFR: In introduced this method to ensure that inner workings are not disturbed by
+ // subclasses...for instance when GetActiveRecordsClass invokes Find()
+ // Why am I not invoking parent::Find?
+ // Shockingly because I want to preserve PHP4 compatibility.
+ function packageFind($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
+ {
+ $db = $this->DB();
+ if (!$db || empty($this->_table)) {
+ return false;
+ }
+ $table =& $this->TableInfo();
+ $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
+ array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
+ return $arr;
+ }
+
+ // returns 0 on error, 1 on update, 2 on insert
+ function Replace()
+ {
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table = $this->TableInfo();
+
+ $pkey = $table->keys;
+
+ foreach($table->flds as $name=>$fld) {
+ $val = $this->$name;
+ /*
+ if (is_null($val)) {
+ if (isset($fld->not_null) && $fld->not_null) {
+ if (isset($fld->default_value) && strlen($fld->default_value)) {
+ continue;
+ }
+ else {
+ $this->Error("Cannot update null into $name","Replace");
+ return false;
+ }
+ }
+ }*/
+ if (is_null($val) && !empty($fld->auto_increment)) {
+ continue;
+ }
+ $t = $db->MetaType($fld->type);
+ $arr[$name] = $this->doquote($db,$val,$t);
+ $valarr[] = $val;
+ }
+
+ if (!is_array($pkey)) {
+ $pkey = array($pkey);
+ }
+
+
+ switch (ADODB_ASSOC_CASE) {
+ case ADODB_ASSOC_CASE_LOWER:
+ foreach($pkey as $k => $v) {
+ $pkey[$k] = strtolower($v);
+ }
+ break;
+ case ADODB_ASSOC_CASE_UPPER:
+ foreach($pkey as $k => $v) {
+ $pkey[$k] = strtoupper($v);
+ }
+ break;
+ }
+
+ $ok = $db->Replace($this->_table,$arr,$pkey);
+ if ($ok) {
+ $this->_saved = true; // 1= update 2=insert
+ if ($ok == 2) {
+ $autoinc = false;
+ foreach($table->keys as $k) {
+ if (is_null($this->$k)) {
+ $autoinc = true;
+ break;
+ }
+ }
+ if ($autoinc && sizeof($table->keys) == 1) {
+ $k = reset($table->keys);
+ $this->$k = $this->LastInsertID($db,$k);
+ }
+ }
+
+ $this->_original = $valarr;
+ }
+ return $ok;
+ }
+
+ // returns 0 on error, 1 on update, -1 if no change in data (no update)
+ function Update()
+ {
+ $db = $this->DB();
+ if (!$db) {
+ return false;
+ }
+ $table = $this->TableInfo();
+
+ $where = $this->GenWhere($db, $table);
+
+ if (!$where) {
+ $this->error("Where missing for table $table", "Update");
+ return false;
+ }
+ $valarr = array();
+ $neworig = array();
+ $pairs = array();
+ $i = -1;
+ $cnt = 0;
+ foreach($table->flds as $name=>$fld) {
+ $i += 1;
+ $val = $this->$name;
+ $neworig[] = $val;
+
+ if (isset($table->keys[$name])) {
+ continue;
+ }
+
+ if (is_null($val)) {
+ if (isset($fld->not_null) && $fld->not_null) {
+ if (isset($fld->default_value) && strlen($fld->default_value)) {
+ continue;
+ }
+ else {
+ $this->Error("Cannot set field $name to NULL","Update");
+ return false;
+ }
+ }
+ }
+
+ if (isset($this->_original[$i]) && $val === $this->_original[$i]) {
+ continue;
+ }
+ $valarr[] = $val;
+ $pairs[] = $name.'='.$db->Param($cnt);
+ $cnt += 1;
+ }
+
+
+ if (!$cnt) {
+ return -1;
+ }
+ $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
+ $ok = $db->Execute($sql,$valarr);
+ if ($ok) {
+ $this->_original = $neworig;
+ return 1;
+ }
+ return 0;
+ }
+
+ function GetAttributeNames()
+ {
+ $table = $this->TableInfo();
+ if (!$table) {
+ return false;
+ }
+ return array_keys($table->flds);
+ }
+
+};
+
+function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bindarr, $primkeyArr,
+ $extra, $relations)
+{
+ global $_ADODB_ACTIVE_DBS;
+
+ if (empty($extra['loading'])) {
+ $extra['loading'] = ADODB_LAZY_AR;
+ }
+ $save = $db->SetFetchMode(ADODB_FETCH_NUM);
+ $table = &$tableObj->_table;
+ $tableInfo =& $tableObj->TableInfo();
+ if(($k = reset($tableInfo->keys))) {
+ $myId = $k;
+ }
+ else {
+ $myId = 'id';
+ }
+ $index = 0; $found = false;
+ /** @todo Improve by storing once and for all in table metadata */
+ /** @todo Also re-use info for hasManyId */
+ foreach($tableInfo->flds as $fld)
+ {
+ if($fld->name == $myId) {
+ $found = true;
+ break;
+ }
+ $index++;
+ }
+ if(!$found) {
+ $db->outp_throw("Unable to locate key $myId for $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
+ }
+
+ $qry = "select * from ".$table;
+ if(ADODB_JOIN_AR == $extra['loading']) {
+ if(!empty($relations['belongsTo'])) {
+ foreach($relations['belongsTo'] as $foreignTable) {
+ if(($k = reset($foreignTable->TableInfo()->keys))) {
+ $belongsToId = $k;
+ }
+ else {
+ $belongsToId = 'id';
+ }
+
+ $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+ $table.'.'.$foreignTable->foreignKey.'='.
+ $foreignTable->_table.'.'.$belongsToId;
+ }
+ }
+ if(!empty($relations['hasMany'])) {
+ if(empty($relations['foreignName'])) {
+ $db->outp_throw("Missing foreignName is relation specification in GetActiveRecordsClass()",'GetActiveRecordsClass');
+ }
+ if(($k = reset($tableInfo->keys))) {
+ $hasManyId = $k;
+ }
+ else {
+ $hasManyId = 'id';
+ }
+
+ foreach($relations['hasMany'] as $foreignTable) {
+ $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
+ $table.'.'.$hasManyId.'='.
+ $foreignTable->_table.'.'.$foreignTable->foreignKey;
+ }
+ }
+ }
+ if (!empty($whereOrderBy)) {
+ $qry .= ' WHERE '.$whereOrderBy;
+ }
+ if(isset($extra['limit'])) {
+ $rows = false;
+ if(isset($extra['offset'])) {
+ $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset']);
+ } else {
+ $rs = $db->SelectLimit($qry, $extra['limit']);
+ }
+ if ($rs) {
+ while (!$rs->EOF) {
+ $rows[] = $rs->fields;
+ $rs->MoveNext();
+ }
+ }
+ } else
+ $rows = $db->GetAll($qry,$bindarr);
+
+ $db->SetFetchMode($save);
+
+ $false = false;
+
+ if ($rows === false) {
+ return $false;
+ }
+
+
+ if (!isset($_ADODB_ACTIVE_DBS)) {
+ include_once(ADODB_DIR.'/adodb-active-record.inc.php');
+ }
+ if (!class_exists($class)) {
+ $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
+ return $false;
+ }
+ $uniqArr = array(); // CFR Keep track of records for relations
+ $arr = array();
+ // arrRef will be the structure that knows about our objects.
+ // It is an associative array.
+ // We will, however, return arr, preserving regular 0.. order so that
+ // obj[0] can be used by app developers.
+ $arrRef = array();
+ $bTos = array(); // Will store belongTo's indices if any
+ foreach($rows as $row) {
+
+ $obj = new $class($table,$primkeyArr,$db);
+ if ($obj->ErrorNo()){
+ $db->_errorMsg = $obj->ErrorMsg();
+ return $false;
+ }
+ $obj->Set($row);
+ // CFR: FIXME: Insane assumption here:
+ // If the first column returned is an integer, then it's a 'id' field
+ // And to make things a bit worse, I use intval() rather than is_int() because, in fact,
+ // $row[0] is not an integer.
+ //
+ // So, what does this whole block do?
+ // When relationships are found, we perform JOINs. This is fast. But not accurate:
+ // instead of returning n objects with their n' associated cousins,
+ // we get n*n' objects. This code fixes this.
+ // Note: to-many relationships mess around with the 'limit' parameter
+ $rowId = intval($row[$index]);
+
+ if(ADODB_WORK_AR == $extra['loading']) {
+ $arrRef[$rowId] = $obj;
+ $arr[] = &$arrRef[$rowId];
+ if(!isset($indices)) {
+ $indices = $rowId;
+ }
+ else {
+ $indices .= ','.$rowId;
+ }
+ if(!empty($relations['belongsTo'])) {
+ foreach($relations['belongsTo'] as $foreignTable) {
+ $foreignTableRef = $foreignTable->foreignKey;
+ // First array: list of foreign ids we are looking for
+ if(empty($bTos[$foreignTableRef])) {
+ $bTos[$foreignTableRef] = array();
+ }
+ // Second array: list of ids found
+ if(empty($obj->$foreignTableRef)) {
+ continue;
+ }
+ if(empty($bTos[$foreignTableRef][$obj->$foreignTableRef])) {
+ $bTos[$foreignTableRef][$obj->$foreignTableRef] = array();
+ }
+ $bTos[$foreignTableRef][$obj->$foreignTableRef][] = $obj;
+ }
+ }
+ continue;
+ }
+
+ if($rowId>0) {
+ if(ADODB_JOIN_AR == $extra['loading']) {
+ $isNewObj = !isset($uniqArr['_'.$row[0]]);
+ if($isNewObj) {
+ $uniqArr['_'.$row[0]] = $obj;
+ }
+
+ // TODO Copy/paste code below: bad!
+ if(!empty($relations['hasMany'])) {
+ foreach($relations['hasMany'] as $foreignTable) {
+ $foreignName = $foreignTable->foreignName;
+ if(!empty($obj->$foreignName)) {
+ $masterObj = &$uniqArr['_'.$row[0]];
+ // Assumption: this property exists in every object since they are instances of the same class
+ if(!is_array($masterObj->$foreignName)) {
+ // Pluck!
+ $foreignObj = $masterObj->$foreignName;
+ $masterObj->$foreignName = array(clone($foreignObj));
+ }
+ else {
+ // Pluck pluck!
+ $foreignObj = $obj->$foreignName;
+ array_push($masterObj->$foreignName, clone($foreignObj));
+ }
+ }
+ }
+ }
+ if(!empty($relations['belongsTo'])) {
+ foreach($relations['belongsTo'] as $foreignTable) {
+ $foreignName = $foreignTable->foreignName;
+ if(!empty($obj->$foreignName)) {
+ $masterObj = &$uniqArr['_'.$row[0]];
+ // Assumption: this property exists in every object since they are instances of the same class
+ if(!is_array($masterObj->$foreignName)) {
+ // Pluck!
+ $foreignObj = $masterObj->$foreignName;
+ $masterObj->$foreignName = array(clone($foreignObj));
+ }
+ else {
+ // Pluck pluck!
+ $foreignObj = $obj->$foreignName;
+ array_push($masterObj->$foreignName, clone($foreignObj));
+ }
+ }
+ }
+ }
+ if(!$isNewObj) {
+ unset($obj); // We do not need this object itself anymore and do not want it re-added to the main array
+ }
+ }
+ else if(ADODB_LAZY_AR == $extra['loading']) {
+ // Lazy loading: we need to give AdoDb a hint that we have not really loaded
+ // anything, all the while keeping enough information on what we wish to load.
+ // Let's do this by keeping the relevant info in our relationship arrays
+ // but get rid of the actual properties.
+ // We will then use PHP's __get to load these properties on-demand.
+ if(!empty($relations['hasMany'])) {
+ foreach($relations['hasMany'] as $foreignTable) {
+ $foreignName = $foreignTable->foreignName;
+ if(!empty($obj->$foreignName)) {
+ unset($obj->$foreignName);
+ }
+ }
+ }
+ if(!empty($relations['belongsTo'])) {
+ foreach($relations['belongsTo'] as $foreignTable) {
+ $foreignName = $foreignTable->foreignName;
+ if(!empty($obj->$foreignName)) {
+ unset($obj->$foreignName);
+ }
+ }
+ }
+ }
+ }
+
+ if(isset($obj)) {
+ $arr[] = $obj;
+ }
+ }
+
+ if(ADODB_WORK_AR == $extra['loading']) {
+ // The best of both worlds?
+ // Here, the number of queries is constant: 1 + n*relationship.
+ // The second query will allow us to perform a good join
+ // while preserving LIMIT etc.
+ if(!empty($relations['hasMany'])) {
+ foreach($relations['hasMany'] as $foreignTable) {
+ $foreignName = $foreignTable->foreignName;
+ $className = ucfirst($foreignTable->_singularize($foreignName));
+ $obj = new $className();
+ $dbClassRef = $foreignTable->foreignKey;
+ $objs = $obj->packageFind($dbClassRef.' IN ('.$indices.')');
+ foreach($objs as $obj) {
+ if(!is_array($arrRef[$obj->$dbClassRef]->$foreignName)) {
+ $arrRef[$obj->$dbClassRef]->$foreignName = array();
+ }
+ array_push($arrRef[$obj->$dbClassRef]->$foreignName, $obj);
+ }
+ }
+
+ }
+ if(!empty($relations['belongsTo'])) {
+ foreach($relations['belongsTo'] as $foreignTable) {
+ $foreignTableRef = $foreignTable->foreignKey;
+ if(empty($bTos[$foreignTableRef])) {
+ continue;
+ }
+ if(($k = reset($foreignTable->TableInfo()->keys))) {
+ $belongsToId = $k;
+ }
+ else {
+ $belongsToId = 'id';
+ }
+ $origObjsArr = $bTos[$foreignTableRef];
+ $bTosString = implode(',', array_keys($bTos[$foreignTableRef]));
+ $foreignName = $foreignTable->foreignName;
+ $className = ucfirst($foreignTable->_singularize($foreignName));
+ $obj = new $className();
+ $objs = $obj->packageFind($belongsToId.' IN ('.$bTosString.')');
+ foreach($objs as $obj)
+ {
+ foreach($origObjsArr[$obj->$belongsToId] as $idx=>$origObj)
+ {
+ $origObj->$foreignName = $obj;
+ }
+ }
+ }
+ }
+ }
+
+ return $arr;
+}
diff --git a/adodb/adodb-csvlib.inc.php b/adodb/adodb-csvlib.inc.php
index e7923db..c81254b 100644
--- a/adodb/adodb-csvlib.inc.php
+++ b/adodb/adodb-csvlib.inc.php
@@ -1,4 +1,26 @@
FieldCount() : 0;
-
+
if ($sql) $sql = urlencode($sql);
// metadata setup
-
+
if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete
if (is_object($conn)) {
$sql .= ','.$conn->Affected_Rows();
$sql .= ','.$conn->Insert_ID();
} else
$sql .= ',,';
-
+
$text = "====-1,0,$sql\n";
return $text;
}
$tt = ($rs->timeCreated) ? $rs->timeCreated : time();
-
+
## changed format from ====0 to ====1
$line = "====1,$tt,$sql\n";
-
+
if ($rs->databaseType == 'array') {
- $rows =& $rs->_array;
+ $rows = $rs->_array;
} else {
$rows = array();
- while (!$rs->EOF) {
+ while (!$rs->EOF) {
$rows[] = $rs->fields;
$rs->MoveNext();
- }
+ }
}
-
+
for($i=0; $i < $max; $i++) {
- $o =& $rs->FetchField($i);
+ $o = $rs->FetchField($i);
$flds[] = $o;
}
-
+
$savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
$class = $rs->connection->arrayClass;
$rs2 = new $class();
+ $rs2->timeCreated = $rs->timeCreated; # memcache fix
$rs2->sql = $rs->sql;
- $rs2->oldProvider = $rs->dataProvider;
+ $rs2->oldProvider = $rs->dataProvider;
$rs2->InitArrayFields($rows,$flds);
$rs2->fetchMode = $savefetch;
return $line.serialize($rs2);
}
-
+
/**
-* Open CSV file and convert it into Data.
+* Open CSV file and convert it into Data.
*
* @param url file/ftp/http url
* @param err returns the error message
* @param timeout dispose if recordset has been alive for $timeout secs
*
-* @return recordset, or false if error occured. If no
-* error occurred in sql INSERT/UPDATE/DELETE,
+* @return recordset, or false if error occurred. If no
+* error occurred in sql INSERT/UPDATE/DELETE,
* empty recordset is returned
*/
- function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
+ function csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
{
$false = false;
$err = false;
@@ -102,7 +107,7 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
@flock($fp, LOCK_SH);
$arr = array();
$ttl = 0;
-
+
if ($meta = fgetcsv($fp, 32000, ",")) {
// check if error message
if (strncmp($meta[0],'****',4) === 0) {
@@ -112,10 +117,10 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
}
// check for meta data
// $meta[0] is -1 means return an empty recordset
- // $meta[1] contains a time
-
+ // $meta[1] contains a time
+
if (strncmp($meta[0], '====',4) === 0) {
-
+
if ($meta[0] == "====-1") {
if (sizeof($meta) < 5) {
$err = "Corrupt first line for format -1";
@@ -123,12 +128,12 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
return $false;
}
fclose($fp);
-
+
if ($timeout > 0) {
$err = " Illegal Timeout $timeout ";
return $false;
}
-
+
$rs = new $rsclass($val=true);
$rs->fields = array();
$rs->timeCreated = $meta[1];
@@ -136,9 +141,9 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
$rs->_numOfFields = 0;
$rs->sql = urldecode($meta[2]);
$rs->affectedrows = (integer)$meta[3];
- $rs->insertid = $meta[4];
+ $rs->insertid = $meta[4];
return $rs;
- }
+ }
# Under high volume loads, we want only 1 thread/process to _write_file
# so that we don't have 50 processes queueing to write the same data.
# We use probabilistic timeout, ahead of time.
@@ -148,7 +153,7 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
# -1 sec after timeout give processes 1/4 chance of timing out
# +0 sec after timeout, give processes 100% chance of timing out
if (sizeof($meta) > 1) {
- if($timeout >0){
+ if($timeout >0){
$tdiff = (integer)( $meta[1]+$timeout - time());
if ($tdiff <= 2) {
switch($tdiff) {
@@ -160,7 +165,7 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
return $false;
}
break;
- case 2:
+ case 2:
if ((rand() & 15) == 0) {
fclose($fp);
$err = "Timeout 2";
@@ -174,12 +179,12 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
return $false;
}
break;
- default:
+ default:
fclose($fp);
$err = "Timeout 0";
return $false;
} // switch
-
+
} // if check flush cache
}// (timeout>0)
$ttl = $meta[1];
@@ -189,7 +194,7 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
if ($meta[0] === '====1') {
// slurp in the data
$MAXSIZE = 128000;
-
+
$text = fread($fp,$MAXSIZE);
if (strlen($text)) {
while ($txt = fread($fp,$MAXSIZE)) {
@@ -205,7 +210,7 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
}
return $rs;
}
-
+
$meta = false;
$meta = fgetcsv($fp, 32000, ",");
if (!$meta) {
@@ -235,21 +240,19 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
$err = "Recordset had unexpected EOF 2";
return $false;
}
-
+
// slurp in the data
$MAXSIZE = 128000;
-
+
$text = '';
while ($txt = fread($fp,$MAXSIZE)) {
$text .= $txt;
}
-
+
fclose($fp);
@$arr = unserialize($text);
- //var_dump($arr);
if (!is_array($arr)) {
$err = "Recordset had unexpected EOF (in serialized recordset)";
- if (get_magic_quotes_runtime()) $err .= ". Magic Quotes Runtime should be disabled!";
return $false;
}
$rs = new $rsclass();
@@ -257,17 +260,18 @@ function &csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
$rs->InitArrayFields($arr,$flds);
return $rs;
}
-
+
/**
* Save a file $filename and its $contents (normally for caching) with file locking
+ * Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
*/
function adodb_write_file($filename, $contents,$debug=false)
- {
+ {
# http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
# So to simulate locking, we assume that rename is an atomic operation.
- # First we delete $filename, then we create a $tempfile write to it and
- # rename to the desired $filename. If the rename works, then we successfully
+ # First we delete $filename, then we create a $tempfile write to it and
+ # rename to the desired $filename. If the rename works, then we successfully
# modified the file exclusively.
# What a stupid need - having to simulate locking.
# Risks:
@@ -277,36 +281,39 @@ function adodb_write_file($filename, $contents,$debug=false)
# 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and cache updated
if (strncmp(PHP_OS,'WIN',3) === 0) {
// skip the decimal place
- $mtime = substr(str_replace(' ','_',microtime()),2);
+ $mtime = substr(str_replace(' ','_',microtime()),2);
// getmypid() actually returns 0 on Win98 - never mind!
$tmpname = $filename.uniqid($mtime).getmypid();
- if (!($fd = @fopen($tmpname,'a'))) return false;
- $ok = ftruncate($fd,0);
- if (!fwrite($fd,$contents)) $ok = false;
+ if (!($fd = @fopen($tmpname,'w'))) return false;
+ if (fwrite($fd,$contents)) $ok = true;
+ else $ok = false;
fclose($fd);
- chmod($tmpname,0644);
- // the tricky moment
- @unlink($filename);
- if (!@rename($tmpname,$filename)) {
- unlink($tmpname);
- $ok = false;
- }
- if (!$ok) {
- if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
+
+ if ($ok) {
+ @chmod($tmpname,0644);
+ // the tricky moment
+ @unlink($filename);
+ if (!@rename($tmpname,$filename)) {
+ @unlink($tmpname);
+ $ok = 0;
+ }
+ if (!$ok) {
+ if ($debug) ADOConnection::outp( " Rename $tmpname ".($ok? 'ok' : 'failed'));
+ }
}
return $ok;
}
if (!($fd = @fopen($filename, 'a'))) return false;
if (flock($fd, LOCK_EX) && ftruncate($fd, 0)) {
- $ok = fwrite( $fd, $contents );
+ if (fwrite( $fd, $contents )) $ok = true;
+ else $ok = false;
fclose($fd);
- chmod($filename,0644);
+ @chmod($filename,0644);
}else {
fclose($fd);
if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename \n");
$ok = false;
}
-
+
return $ok;
}
-?>
\ No newline at end of file
diff --git a/adodb/adodb-datadict.inc.php b/adodb/adodb-datadict.inc.php
index 9674cd9..dbed95d 100644
--- a/adodb/adodb-datadict.inc.php
+++ b/adodb/adodb-datadict.inc.php
@@ -1,30 +1,35 @@
$str
";
-$a= Lens_ParseArgs($str);
+$a= lens_ParseArgs($str);
print "
-
+
This function changes/adds new fields to your table. You don't
have to know if the col is new or not. It will check on its own.
*/
- function ChangeTableSQL($tablename, $flds, $tableoptions = false)
+ function changeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false)
{
global $ADODB_FETCH_MODE;
-
+
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
- if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
-
+ if ($this->connection->fetchMode !== false) $savem = $this->connection->setFetchMode(false);
+
// check table exists
$save_handler = $this->connection->raiseErrorFn;
$this->connection->raiseErrorFn = '';
- $cols = $this->MetaColumns($tablename);
+ $cols = $this->metaColumns($tablename);
$this->connection->raiseErrorFn = $save_handler;
-
- if (isset($savem)) $this->connection->SetFetchMode($savem);
+
+ if (isset($savem)) $this->connection->setFetchMode($savem);
$ADODB_FETCH_MODE = $save;
-
- if ( empty($cols)) {
- return $this->CreateTableSQL($tablename, $flds, $tableoptions);
+
+ if ( empty($cols)) {
+ return $this->createTableSQL($tablename, $flds, $tableoptions);
}
-
+
if (is_array($flds)) {
// Cycle through the update fields, comparing
// existing fields to fields to update.
@@ -742,43 +1027,63 @@ function ChangeTableSQL($tablename, $flds, $tableoptions = false)
$obj = $cols[$k];
if (isset($obj->not_null) && $obj->not_null)
$v = str_replace('NOT NULL','',$v);
+ if (isset($obj->auto_increment) && $obj->auto_increment && empty($v['AUTOINCREMENT']))
+ $v = str_replace('AUTOINCREMENT','',$v);
$c = $cols[$k];
$ml = $c->max_length;
- $mt = $this->MetaType($c->type,$ml);
+ $mt = $this->metaType($c->type,$ml);
+
+ if (isset($c->scale)) $sc = $c->scale;
+ else $sc = 99; // always force change if scale not known.
+
+ if ($sc == -1) $sc = false;
+ list($fsize, $fprec) = $this->_getSizePrec($v['SIZE']);
+
if ($ml == -1) $ml = '';
if ($mt == 'X') $ml = $v['SIZE'];
- if (($mt != $v['TYPE']) || $ml != $v['SIZE']) {
+ if (($mt != $v['TYPE']) || ($ml != $fsize || $sc != $fprec) || (isset($v['AUTOINCREMENT']) && $v['AUTOINCREMENT'] != $obj->auto_increment)) {
$holdflds[$k] = $v;
}
} else {
$holdflds[$k] = $v;
- }
+ }
}
$flds = $holdflds;
}
-
+
// already exists, alter table instead
- list($lines,$pkey) = $this->_GenFields($flds);
- $alter = 'ALTER TABLE ' . $this->TableName($tablename);
+ list($lines,$pkey,$idxs) = $this->_genFields($flds);
+ // genfields can return FALSE at times
+ if ($lines == null) $lines = array();
+ $alter = 'ALTER TABLE ' . $this->tableName($tablename);
$sql = array();
foreach ( $lines as $id => $v ) {
if ( isset($cols[$id]) && is_object($cols[$id]) ) {
-
- $flds = Lens_ParseArgs($v,',');
-
+
+ $flds = lens_ParseArgs($v,',');
+
// We are trying to change the size of the field, if not allowed, simply ignore the request.
- if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)) continue;
-
+ // $flds[1] holds the type, $flds[2] holds the size -postnuke addition
+ if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)
+ && (isset($flds[0][2]) && is_numeric($flds[0][2]))) {
+ if ($this->debug) ADOConnection::outp(sprintf("%s cannot be changed to %s currently ", $flds[0][0], $flds[0][1]));
+ #echo "$this->alterCol cannot be changed to $flds currently ";
+ continue;
+ }
$sql[] = $alter . $this->alterCol . ' ' . $v;
} else {
$sql[] = $alter . $this->addCol . ' ' . $v;
}
}
-
+
+ if ($dropOldFlds) {
+ foreach ( $cols as $id => $v )
+ if ( !isset($lines[$id]) )
+ $sql[] = $alter . $this->dropCol . ' ' . $v->name;
+ }
return $sql;
}
} // class
-?>
\ No newline at end of file
diff --git a/adodb/adodb-error.inc.php b/adodb/adodb-error.inc.php
index c66d4d7..517cf9b 100644
--- a/adodb/adodb-error.inc.php
+++ b/adodb/adodb-error.inc.php
@@ -1,17 +1,27 @@
DB_ERROR_NOSUCHTABLE,
- '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/' => DB_ERROR_ALREADY_EXISTS,
- '/divide by zero$/' => DB_ERROR_DIVZERO,
- '/pg_atoi: error in .*: can\'t parse /' => DB_ERROR_INVALID_NUMBER,
- '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => DB_ERROR_NOSUCHFIELD,
- '/parser: parse error at or near \"/' => DB_ERROR_SYNTAX,
- '/referential integrity violation/' => DB_ERROR_CONSTRAINT,
- '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key violates unique constraint/'
- => DB_ERROR_ALREADY_EXISTS
- );
+ // Postgres has no lock-wait timeout. The best we could do would be to set a statement timeout.
+ static $error_regexps = array(
+ '(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$' => DB_ERROR_NOSUCHTABLE,
+ 'Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key.*violates unique constraint' => DB_ERROR_ALREADY_EXISTS,
+ 'database ".+" does not exist$' => DB_ERROR_NOSUCHDB,
+ '(divide|division) by zero$' => DB_ERROR_DIVZERO,
+ 'pg_atoi: error in .*: can\'t parse ' => DB_ERROR_INVALID_NUMBER,
+ 'ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']' => DB_ERROR_NOSUCHFIELD,
+ '(parser: parse|syntax) error at or near \"' => DB_ERROR_SYNTAX,
+ 'referential integrity violation' => DB_ERROR_CONSTRAINT,
+ 'deadlock detected$' => DB_ERROR_DEADLOCK,
+ 'canceling statement due to statement timeout$' => DB_ERROR_STATEMENT_TIMEOUT,
+ 'could not serialize access due to' => DB_ERROR_SERIALIZATION_FAILURE
+ );
reset($error_regexps);
- while (list($regexp,$code) = each($error_regexps)) {
- if (preg_match($regexp, $errormsg)) {
- return $code;
- }
- }
- // Fall back to DB_ERROR if there was no mapping.
- return DB_ERROR;
+ foreach ($error_regexps as $regexp => $code) {
+ if (preg_match("/$regexp/mi", $errormsg)) {
+ return $code;
+ }
+ }
+ // Fall back to DB_ERROR if there was no mapping.
+ return DB_ERROR;
}
-
+
function adodb_error_odbc()
{
static $MAP = array(
@@ -169,7 +189,7 @@ function adodb_error_ibase()
-923 => DB_ERROR_CONNECT_FAILED,
-924 => DB_ERROR_CONNECT_FAILED
);
-
+
return $MAP;
}
@@ -187,7 +207,7 @@ function adodb_error_ifx()
'-1210' => DB_ERROR_INVALID_DATE,
'-1212' => DB_ERROR_INVALID_DATE
);
-
+
return $MAP;
}
@@ -206,7 +226,7 @@ function adodb_error_oci8()
2291 => DB_ERROR_CONSTRAINT,
2449 => DB_ERROR_CONSTRAINT
);
-
+
return $MAP;
}
@@ -216,7 +236,7 @@ function adodb_error_mssql()
208 => DB_ERROR_NOSUCHTABLE,
2601 => DB_ERROR_ALREADY_EXISTS
);
-
+
return $MAP;
}
@@ -225,7 +245,7 @@ function adodb_error_sqlite()
static $MAP = array(
1 => DB_ERROR_SYNTAX
);
-
+
return $MAP;
}
@@ -237,9 +257,9 @@ function adodb_error_mysql()
1006 => DB_ERROR_CANNOT_CREATE,
1007 => DB_ERROR_ALREADY_EXISTS,
1008 => DB_ERROR_CANNOT_DROP,
- 1045 => DB_ERROR_ACCESS_VIOLATION,
+ 1045 => DB_ERROR_ACCESS_VIOLATION,
1046 => DB_ERROR_NODBSELECTED,
- 1049 => DB_ERROR_NOSUCHDB,
+ 1049 => DB_ERROR_NOSUCHDB,
1050 => DB_ERROR_ALREADY_EXISTS,
1051 => DB_ERROR_NOSUCHTABLE,
1054 => DB_ERROR_NOSUCHFIELD,
@@ -249,10 +269,9 @@ function adodb_error_mysql()
1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
1146 => DB_ERROR_NOSUCHTABLE,
1048 => DB_ERROR_CONSTRAINT,
- 2002 => DB_ERROR_CONNECT_FAILED,
- 2005 => DB_ERROR_CONNECT_FAILED
+ 2002 => DB_ERROR_CONNECT_FAILED,
+ 2005 => DB_ERROR_CONNECT_FAILED
);
-
+
return $MAP;
}
-?>
\ No newline at end of file
diff --git a/adodb/adodb-errorhandler.inc.php b/adodb/adodb-errorhandler.inc.php
index 41f2c48..0cd3f21 100644
--- a/adodb/adodb-errorhandler.inc.php
+++ b/adodb/adodb-errorhandler.inc.php
@@ -1,19 +1,26 @@
$s";
- trigger_error($s,ADODB_ERROR_HANDLER_TYPE);
+ trigger_error($s,ADODB_ERROR_HANDLER_TYPE);
}
-?>
diff --git a/adodb/adodb-errorpear.inc.php b/adodb/adodb-errorpear.inc.php
index 143d8fc..2bb1594 100644
--- a/adodb/adodb-errorpear.inc.php
+++ b/adodb/adodb-errorpear.inc.php
@@ -1,15 +1,24 @@
!$s";
}
/**
* Returns last PEAR_Error object. This error might be for an error that
-* occured several sql statements ago.
+* occurred several sql statements ago.
*/
-function &ADODB_PEAR_Error()
+function ADODB_PEAR_Error()
{
global $ADODB_Last_PEAR_Error;
return $ADODB_Last_PEAR_Error;
}
-
-?>
\ No newline at end of file
diff --git a/adodb/adodb-exceptions.inc.php b/adodb/adodb-exceptions.inc.php
index 394f7dc..9f1176f 100644
--- a/adodb/adodb-exceptions.inc.php
+++ b/adodb/adodb-exceptions.inc.php
@@ -1,20 +1,25 @@
sql = $p1;
+ $this->sql = is_array($p1) ? $p1[0] : $p1;
$this->params = $p2;
- $s = "$dbms error: [$errno: $errmsg] in $fn(\"$p1\")\n";
+ $s = "$dbms error: [$errno: $errmsg] in $fn(\"$this->sql\")";
break;
-
+
case 'PCONNECT':
case 'CONNECT':
$user = $thisConnection->user;
- $s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)\n";
+ $s = "$dbms error: [$errno: $errmsg] in $fn($p1, '$user', '****', $p2)";
break;
default:
- $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)\n";
+ $s = "$dbms error: [$errno: $errmsg] in $fn($p1, $p2)";
break;
}
-
+
$this->dbms = $dbms;
if ($thisConnection) {
$this->host = $thisConnection->host;
@@ -51,32 +56,29 @@ function __construct($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
}
$this->fn = $fn;
$this->msg = $errmsg;
-
+
if (!is_numeric($errno)) $errno = -1;
parent::__construct($s,$errno);
}
}
/**
-* Default Error Handler. This will be called with the following params
+* Default Error Handler.
*
-* @param $dbms the RDBMS you are connecting to
-* @param $fn the name of the calling function (in uppercase)
-* @param $errno the native error number from the database
-* @param $errmsg the native error msg from the database
-* @param $p1 $fn specific parameter - see below
-* @param $P2 $fn specific parameter - see below
+* @param string $dbms the RDBMS you are connecting to
+* @param string $fn the name of the calling function (in uppercase)
+* @param int $errno the native error number from the database
+* @param string $errmsg the native error msg from the database
+* @param mixed $p1 $fn specific parameter - see below
+* @param mixed $p2 $fn specific parameter - see below
*/
function adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
{
global $ADODB_EXCEPTION;
-
+
if (error_reporting() == 0) return; // obey @ protocol
if (is_string($ADODB_EXCEPTION)) $errfn = $ADODB_EXCEPTION;
else $errfn = 'ADODB_EXCEPTION';
throw new $errfn($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection);
}
-
-
-?>
\ No newline at end of file
diff --git a/adodb/adodb-iterator.inc.php b/adodb/adodb-iterator.inc.php
deleted file mode 100644
index 86e2895..0000000
--- a/adodb/adodb-iterator.inc.php
+++ /dev/null
@@ -1,85 +0,0 @@
-Execute("select * from adoxyz");
- foreach($rs as $k => $v) {
- echo $k; print_r($v); echo " ";
- }
-
-
- Iterator code based on http://cvs.php.net/cvs.php/php-src/ext/spl/examples/cachingiterator.inc?login=2
- */
-
-
- class ADODB_Iterator implements Iterator {
-
- private $rs;
-
- function __construct($rs)
- {
- $this->rs = $rs;
- }
- function rewind()
- {
- $this->rs->MoveFirst();
- }
-
- function valid()
- {
- return !$this->rs->EOF;
- }
-
- function key()
- {
- return $this->rs->_currentRow;
- }
-
- function current()
- {
- return $this->rs->fields;
- }
-
- function next()
- {
- $this->rs->MoveNext();
- }
-
- function __call($func, $params)
- {
- return call_user_func_array(array($this->rs, $func), $params);
- }
-
-
- function hasMore()
- {
- return !$this->rs->EOF;
- }
-
-}
-
-
-class ADODB_BASE_RS implements IteratorAggregate {
- function getIterator() {
- return new ADODB_Iterator($this);
- }
-
- /* this is experimental - i don't really know what to return... */
- function __toString()
- {
- include_once(ADODB_DIR.'/toexport.inc.php');
- return _adodb_export($this,',',',',false,true);
- }
-}
-
-
-?>
\ No newline at end of file
diff --git a/adodb/adodb-lib.inc.php b/adodb/adodb-lib.inc.php
index 51c45c7..ced5e12 100644
--- a/adodb/adodb-lib.inc.php
+++ b/adodb/adodb-lib.inc.php
@@ -1,4 +1,25 @@
array_pop($tmp)];
+ }
+ if ($arr)
+ if (strpos($arr[1], '(') !== false) {
+ $at = strpos($sql, $arr[1]);
+ $cntin = 0;
+ for ($i=$at, $max=strlen($sql); $i < $max; $i++) {
+ $ch = $sql[$i];
+ if ($ch == '(') {
+ $cntin += 1;
+ } elseif($ch == ')') {
+ $cntin -= 1;
+ if ($cntin < 0) {
+ break;
+ }
+ }
+ }
+ $sql = substr($sql,0,$at).substr($sql,$i);
+ } else {
+ $sql = str_replace($arr[1], '', $sql);
+ }
+
+ return $sql;
+}
+
+if (false) {
+ $sql = 'select * from (select a from b order by a(b),b(c) desc)';
+ $sql = '(select * from abc order by 1)';
+ die(adodb_strip_order_by($sql));
+}
function adodb_probetypes(&$array,&$types,$probe=8)
{
@@ -22,26 +70,26 @@ function adodb_probetypes(&$array,&$types,$probe=8)
$types = array();
if ($probe > sizeof($array)) $max = sizeof($array);
else $max = $probe;
-
-
+
+
for ($j=0;$j < $max; $j++) {
- $row =& $array[$j];
+ $row = $array[$j];
if (!$row) break;
$i = -1;
foreach($row as $v) {
$i += 1;
if (isset($types[$i]) && $types[$i]=='C') continue;
-
+
//print " ($i ".$types[$i]. "$v) ";
$v = trim($v);
-
+
if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) {
$types[$i] = 'C'; // once C, always C
-
+
continue;
}
- if ($j == 0) {
+ if ($j == 0) {
// If empty string, we presume is character
// test for integer for 1st row only
// after that it is up to testing other rows to prove
@@ -51,21 +99,22 @@ function adodb_probetypes(&$array,&$types,$probe=8)
else $types[$i] = 'I';
continue;
}
-
+
if (strpos($v,'.') !== false) $types[$i] = 'N';
-
+
}
}
+
}
-function &adodb_transpose(&$arr, &$newarr, &$hdr)
+function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs)
{
$oldX = sizeof(reset($arr));
- $oldY = sizeof($arr);
-
+ $oldY = sizeof($arr);
+
if ($hdr) {
$startx = 1;
- $hdr = array();
+ $hdr = array('Fields');
for ($y = 0; $y < $oldY; $y++) {
$hdr[] = $arr[$y][0];
}
@@ -73,369 +122,395 @@ function &adodb_transpose(&$arr, &$newarr, &$hdr)
$startx = 0;
for ($x = $startx; $x < $oldX; $x++) {
- $newarr[] = array();
+ if ($fobjs) {
+ $o = $fobjs[$x];
+ $newarr[] = array($o->name);
+ } else
+ $newarr[] = array();
+
for ($y = 0; $y < $oldY; $y++) {
$newarr[$x-$startx][] = $arr[$y][$x];
}
}
}
-// Force key to upper.
-// See also http://www.php.net/manual/en/function.array-change-key-case.php
-function _array_change_key_case($an_array)
-{
- if (is_array($an_array)) {
- $new_array = array();
- foreach($an_array as $key=>$value)
- $new_array[strtoupper($key)] = $value;
-
- return $new_array;
- }
-
- return $an_array;
-}
function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
{
- if (count($fieldArray) == 0) return 0;
- $first = true;
- $uSet = '';
-
- if (!is_array($keyCol)) {
- $keyCol = array($keyCol);
- }
- foreach($fieldArray as $k => $v) {
- if ($autoQuote && !is_numeric($v) and strncmp($v,"'",1) !== 0 and strcasecmp($v,'null')!=0) {
- $v = $zthis->qstr($v);
- $fieldArray[$k] = $v;
- }
- if (in_array($k,$keyCol)) continue; // skip UPDATE if is key
-
- if ($first) {
- $first = false;
- $uSet = "$k=$v";
- } else
- $uSet .= ",$k=$v";
- }
-
- $where = false;
- foreach ($keyCol as $v) {
- if (isset($fieldArray[$v])) {
- if ($where) $where .= ' and '.$v.'='.$fieldArray[$v];
- else $where = $v.'='.$fieldArray[$v];
- }
+ // Add Quote around table name to support use of spaces / reserved keywords
+ $table=sprintf('%s%s%s', $zthis->nameQuote,$table,$zthis->nameQuote);
+
+ if (count($fieldArray) == 0) return 0;
+
+ if (!is_array($keyCol)) {
+ $keyCol = array($keyCol);
+ }
+ $uSet = '';
+ foreach($fieldArray as $k => $v) {
+ if ($v === null) {
+ $v = 'NULL';
+ $fieldArray[$k] = $v;
+ } else if ($autoQuote && /*!is_numeric($v) /*and strncmp($v,"'",1) !== 0 -- sql injection risk*/ strcasecmp($v,$zthis->null2null)!=0) {
+ $v = $zthis->qstr($v);
+ $fieldArray[$k] = $v;
}
-
- if ($uSet && $where) {
- $update = "UPDATE $table SET $uSet WHERE $where";
-
- $rs = $zthis->Execute($update);
-
-
- if ($rs) {
- if ($zthis->poorAffectedRows) {
- /*
- The Select count(*) wipes out any errors that the update would have returned.
- http://phplens.com/lens/lensforum/msgs.php?id=5696
- */
- if ($zthis->ErrorNo()<>0) return 0;
-
- # affected_rows == 0 if update field values identical to old values
- # for mysql - which is silly.
-
- $cnt = $zthis->GetOne("select count(*) from $table where $where");
- if ($cnt > 0) return 1; // record already exists
- } else {
- if (($zthis->Affected_Rows()>0)) return 1;
- }
- } else
- return 0;
+ if (in_array($k,$keyCol)) continue; // skip UPDATE if is key
+
+ // Add Quote around column name to support use of spaces / reserved keywords
+ $uSet .= sprintf(',%s%s%s=%s',$zthis->nameQuote,$k,$zthis->nameQuote,$v);
+ }
+ $uSet = ltrim($uSet, ',');
+
+ // Add Quote around column name in where clause
+ $where = '';
+ foreach ($keyCol as $v) {
+ if (isset($fieldArray[$v])) {
+ $where .= sprintf(' and %s%s%s=%s ', $zthis->nameQuote,$v,$zthis->nameQuote,$fieldArray[$v]);
}
-
- // print "Error=".$this->ErrorNo().'
';
- $first = true;
- foreach($fieldArray as $k => $v) {
- if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
-
- if ($first) {
- $first = false;
- $iCols = "$k";
- $iVals = "$v";
+ }
+ if ($where) {
+ $where = substr($where, 5);
+ }
+
+ if ($uSet && $where) {
+ $update = "UPDATE $table SET $uSet WHERE $where";
+ $rs = $zthis->Execute($update);
+
+ if ($rs) {
+ if ($zthis->poorAffectedRows) {
+ // The Select count(*) wipes out any errors that the update would have returned.
+ // PHPLens Issue No: 5696
+ if ($zthis->ErrorNo()<>0) return 0;
+
+ // affected_rows == 0 if update field values identical to old values
+ // for mysql - which is silly.
+ $cnt = $zthis->GetOne("select count(*) from $table where $where");
+ if ($cnt > 0) return 1; // record already exists
} else {
- $iCols .= ",$k";
- $iVals .= ",$v";
- }
- }
- $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
- $rs = $zthis->Execute($insert);
- return ($rs) ? 2 : 0;
+ if (($zthis->Affected_Rows()>0)) return 1;
+ }
+ } else
+ return 0;
+ }
+
+ $iCols = $iVals = '';
+ foreach($fieldArray as $k => $v) {
+ if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
+
+ // Add Quote around Column Name
+ $iCols .= sprintf(',%s%s%s',$zthis->nameQuote,$k,$zthis->nameQuote);
+ $iVals .= ",$v";
+ }
+ $iCols = ltrim($iCols, ',');
+ $iVals = ltrim($iVals, ',');
+
+ $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
+ $rs = $zthis->Execute($insert);
+ return ($rs) ? 2 : 0;
}
-// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
$size=0, $selectAttr='',$compareFields0=true)
{
- $hasvalue = false;
-
- if ($multiple or is_array($defstr)) {
- if ($size==0) $size=5;
- $attr = ' multiple size="'.$size.'"';
- if (!strpos($name,'[]')) $name .= '[]';
- } else if ($size) $attr = ' size="'.$size.'"';
- else $attr ='';
-
- $s = '';
- if ($blank1stItem)
- if (is_string($blank1stItem)) {
- $barr = explode(':',$blank1stItem);
- if (sizeof($barr) == 1) $barr[] = '';
- $s .= "\n".$barr[1]." ";
- } else $s .= "\n ";
+ global $ADODB_FETCH_MODE;
+
+ $s = _adodb_getmenu_select($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr);
+
+ $hasvalue = $zthis->FieldCount() > 1;
+ if (!$hasvalue) {
+ $compareFields0 = true;
+ }
- if ($zthis->FieldCount() > 1) $hasvalue=true;
- else $compareFields0 = true;
-
$value = '';
- $optgroup = null;
- $firstgroup = true;
- $fieldsize = $zthis->FieldCount();
while(!$zthis->EOF) {
$zval = rtrim(reset($zthis->fields));
- if ($blank1stItem && $zval=="") {
+ if ($blank1stItem && $zval == "") {
$zthis->MoveNext();
continue;
}
- if ($fieldsize > 1) {
- if (isset($zthis->fields[1]))
- $zval2 = rtrim($zthis->fields[1]);
- else
- $zval2 = rtrim(next($zthis->fields));
- }
- $selected = ($compareFields0) ? $zval : $zval2;
-
- $group = '';
- if ($fieldsize > 2) {
- $group = rtrim($zthis->fields[2]);
- }
-/*
- if ($optgroup != $group) {
- $optgroup = $group;
- if ($firstgroup) {
- $firstgroup = false;
- $s .="\n";
- } else {
- $s .="\n ";
- $s .="\n";
- }
- }
-*/
- if ($hasvalue)
- $value = " value='".htmlspecialchars($zval2)."'";
-
- if (is_array($defstr)) {
-
- if (in_array($selected,$defstr))
- $s .= "\n".htmlspecialchars($zval).' ';
- else
- $s .= "\n'.htmlspecialchars($zval).' ';
- }
- else {
- if (strcasecmp($selected,$defstr)==0)
- $s .= "\n".htmlspecialchars($zval).' ';
- else
- $s .= "\n'.htmlspecialchars($zval).' ';
+ if ($hasvalue) {
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC) {
+ // Get 2nd field's value regardless of its name
+ $zval2 = current(array_slice($zthis->fields, 1, 1));
+ } else {
+ // With NUM or BOTH fetch modes, we have a numeric index
+ $zval2 = $zthis->fields[1];
+ }
+ $zval2 = trim($zval2);
+ $value = 'value="' . htmlspecialchars($zval2) . '"';
}
+
+ $s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval);
+
$zthis->MoveNext();
} // while
-
- // closing last optgroup
- if($optgroup != null) {
- $s .= "\n ";
- }
+
return $s ."\n \n";
}
-// Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
$size=0, $selectAttr='',$compareFields0=true)
{
- $hasvalue = false;
-
- if ($multiple or is_array($defstr)) {
- if ($size==0) $size=5;
- $attr = ' multiple size="'.$size.'"';
- if (!strpos($name,'[]')) $name .= '[]';
- } else if ($size) $attr = ' size="'.$size.'"';
- else $attr ='';
-
- $s = '';
- if ($blank1stItem)
- if (is_string($blank1stItem)) {
- $barr = explode(':',$blank1stItem);
- if (sizeof($barr) == 1) $barr[] = '';
- $s .= "\n".$barr[1]." ";
- } else $s .= "\n ";
+ global $ADODB_FETCH_MODE;
+
+ $s = _adodb_getmenu_select($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr);
+
+ $hasvalue = $zthis->FieldCount() > 1;
+ $hasgroup = $zthis->FieldCount() > 2;
+ if (!$hasvalue) {
+ $compareFields0 = true;
+ }
- if ($zthis->FieldCount() > 1) $hasvalue=true;
- else $compareFields0 = true;
-
$value = '';
- $optgroup = null;
- $firstgroup = true;
- $fieldsize = sizeof($zthis->fields);
+ $optgroup = null;
+ $firstgroup = true;
while(!$zthis->EOF) {
$zval = rtrim(reset($zthis->fields));
+ $group = '';
if ($blank1stItem && $zval=="") {
$zthis->MoveNext();
continue;
}
- if ($fieldsize > 1) {
- if (isset($zthis->fields[1]))
- $zval2 = rtrim($zthis->fields[1]);
- else
- $zval2 = rtrim(next($zthis->fields));
- }
- $selected = ($compareFields0) ? $zval : $zval2;
-
- $group = '';
- if (isset($zthis->fields[2])) {
- $group = rtrim($zthis->fields[2]);
- }
-
- if ($optgroup != $group) {
- $optgroup = $group;
- if ($firstgroup) {
- $firstgroup = false;
- $s .="\n";
- } else {
- $s .="\n ";
- $s .="\n";
- }
- }
-
- if ($hasvalue)
- $value = " value='".htmlspecialchars($zval2)."'";
-
- if (is_array($defstr)) {
-
- if (in_array($selected,$defstr))
- $s .= "\n".htmlspecialchars($zval).' ';
- else
- $s .= "\n'.htmlspecialchars($zval).' ';
+ if ($hasvalue) {
+ if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC) {
+ // Get 2nd field's value regardless of its name
+ $fields = array_slice($zthis->fields, 1);
+ $zval2 = current($fields);
+ if ($hasgroup) {
+ $group = trim(next($fields));
+ }
+ } else {
+ // With NUM or BOTH fetch modes, we have a numeric index
+ $zval2 = $zthis->fields[1];
+ if ($hasgroup) {
+ $group = trim($zthis->fields[2]);
+ }
+ }
+ $zval2 = trim($zval2);
+ $value = "value='".htmlspecialchars($zval2)."'";
}
- else {
- if (strcasecmp($selected,$defstr)==0)
- $s .= "\n".htmlspecialchars($zval).' ';
- else
- $s .= "\n'.htmlspecialchars($zval).' ';
+
+ if ($optgroup != $group) {
+ $optgroup = $group;
+ if ($firstgroup) {
+ $firstgroup = false;
+ } else {
+ $s .="\n ";
+ }
+ $s .="\n";
}
+
+ $s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval);
+
$zthis->MoveNext();
} // while
-
- // closing last optgroup
- if($optgroup != null) {
- $s .= "\n ";
+
+ // closing last optgroup
+ if($optgroup != null) {
+ $s .= "\n";
}
return $s ."\n \n";
}
+/**
+ * Generate the opening SELECT tag for getmenu functions.
+ *
+ * ADOdb internal function, used by _adodb_getmenu() and _adodb_getmenu_gp().
+ *
+ * @param string $name
+ * @param string $defstr
+ * @param bool $blank1stItem
+ * @param bool $multiple
+ * @param int $size
+ * @param string $selectAttr
+ *
+ * @return string HTML
+ */
+function _adodb_getmenu_select($name, $defstr = '', $blank1stItem = true,
+ $multiple = false, $size = 0, $selectAttr = '')
+{
+ if ($multiple || is_array($defstr)) {
+ if ($size == 0 ) {
+ $size = 5;
+ }
+ $attr = ' multiple size="' . $size . '"';
+ if (!strpos($name,'[]')) {
+ $name .= '[]';
+ }
+ } elseif ($size) {
+ $attr = ' size="' . $size . '"';
+ } else {
+ $attr = '';
+ }
+
+ $html = '';
+ if ($blank1stItem) {
+ if (is_string($blank1stItem)) {
+ $barr = explode(':',$blank1stItem);
+ if (sizeof($barr) == 1) {
+ $barr[] = '';
+ }
+ $html .= "\n" . $barr[1] . " ";
+ } else {
+ $html .= "\n ";
+ }
+ }
+
+ return $html;
+}
+
+/**
+ * Print the OPTION tags for getmenu functions.
+ *
+ * ADOdb internal function, used by _adodb_getmenu() and _adodb_getmenu_gp().
+ *
+ * @param string $defstr Default values
+ * @param string $compare Value to compare against defaults
+ * @param string $value Ready-to-print `value="xxx"` (or empty) string
+ * @param string $display Display value
+ *
+ * @return string HTML
+ */
+function _adodb_getmenu_option($defstr, $compare, $value, $display)
+{
+ if ( is_array($defstr) && in_array($compare, $defstr)
+ || !is_array($defstr) && strcasecmp($compare, $defstr) == 0
+ ) {
+ $selected = ' selected="selected"';
+ } else {
+ $selected = '';
+ }
+
+ return "\n" . htmlspecialchars($display) . ' ';
+}
/*
Count the number of records this sql statement will return by using
query rewriting heuristics...
-
+
Does not work with UNIONs, except with postgresql and oracle.
-
+
Usage:
-
+
$conn->Connect(...);
$cnt = _adodb_getcount($conn, $sql);
-
+
*/
-function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
+function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
{
$qryRecs = 0;
-
- if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) ||
- preg_match('/\s+GROUP\s+BY\s+/is',$sql) ||
- preg_match('/\s+UNION\s+/is',$sql)) {
+
+ /*
+ * These databases require a "SELECT * FROM (SELECT" type
+ * statement to have an alias for the result
+ */
+ $requiresAlias = '';
+ $requiresAliasArray = array('postgres9','postgres','mysql','mysqli','mssql','mssqlnative','sqlsrv');
+ if (in_array($zthis->databaseType,$requiresAliasArray)
+ || in_array($zthis->dsnType,$requiresAliasArray)
+ ) {
+ $requiresAlias = '_ADODB_ALIAS_';
+ }
+
+ if (!empty($zthis->_nestedSQL)
+ || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql)
+ || preg_match('/\s+GROUP\s+BY\s+/is',$sql)
+ || preg_match('/\s+UNION\s+/is',$sql)
+ ) {
+ $rewritesql = adodb_strip_order_by($sql);
+
// ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias
// but this is only supported by oracle and postgresql...
if ($zthis->dataProvider == 'oci8') {
-
- $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql);
-
// Allow Oracle hints to be used for query optimization, Chris Wrye
if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) {
- $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")";
+ $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")";
} else
- $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")";
-
- } else if (strncmp($zthis->databaseType,'postgres',8) == 0) {
- $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$sql);
- $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";
+ $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")";
+ } else {
+ $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) $requiresAlias";
}
+
} else {
- // now replace SELECT ... FROM with SELECT COUNT(*) FROM
- $rewritesql = preg_replace(
- '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
+ // Replace 'SELECT ... FROM' with 'SELECT COUNT(*) FROM'
+ // Parse the query one char at a time starting after the SELECT
+ // to find the FROM clause's position, ignoring any sub-queries.
+ $start = stripos($sql, 'SELECT') + 7;
+ if ($start === false) {
+ // Not a SELECT statement - probably should trigger an exception here
+ return 0;
+ }
+ $len = strlen($sql);
+ $numParentheses = 0;
+ for ($pos = $start; $pos < $len; $pos++) {
+ switch ($sql[$pos]) {
+ case '(': $numParentheses++; continue 2;
+ case ')': $numParentheses--; continue 2;
+ }
+ // Ignore whatever is between parentheses (sub-queries)
+ if ($numParentheses > 0) {
+ continue;
+ }
+ // Exit loop if 'FROM' keyword was found
+ if (strtoupper(substr($sql, $pos, 4)) == 'FROM') {
+ break;
+ }
+ }
+ $rewritesql = 'SELECT COUNT(*) ' . substr($sql, $pos);
-
-
- // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails
+ // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails
// with mssql, access and postgresql. Also a good speedup optimization - skips sorting!
- // also see http://phplens.com/lens/lensforum/msgs.php?id=12752
- if (preg_match('/\sORDER\s+BY\s*\(/i',$rewritesql))
- $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$rewritesql);
- else
- $rewritesql = preg_replace('/(\sORDER\s+BY\s[^)]*)/is','',$rewritesql);
+ // also see PHPLens Issue No: 12752
+ $rewritesql = adodb_strip_order_by($rewritesql);
}
-
-
-
+
if (isset($rewritesql) && $rewritesql != $sql) {
- if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[1];
-
+ if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) {
+ $rewritesql .= $limitarr[0];
+ }
+
if ($secs2cache) {
// we only use half the time of secs2cache because the count can quickly
// become inaccurate if new records are added
$qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
-
+
} else {
$qryRecs = $zthis->GetOne($rewritesql,$inputarr);
- }
+ }
if ($qryRecs !== false) return $qryRecs;
}
+
//--------------------------------------------
// query rewrite failed - so try slower way...
-
-
+
// strip off unneeded ORDER BY if no UNION
- if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
- else $rewritesql = preg_replace('/(\sORDER\s+BY\s.*)/is','',$sql);
-
- if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
-
- $rstest = &$zthis->Execute($rewritesql,$inputarr);
- if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
-
+ if (preg_match('/\s*UNION\s*/is', $sql)) {
+ $rewritesql = $sql;
+ } else {
+ $rewritesql = $rewritesql = adodb_strip_order_by($sql);
+ }
+
+ if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) {
+ $rewritesql .= $limitarr[0];
+ }
+
+ if ($secs2cache) {
+ $rstest = $zthis->CacheExecute($secs2cache,$rewritesql,$inputarr);
+ if (!$rstest) $rstest = $zthis->CacheExecute($secs2cache,$sql,$inputarr);
+ } else {
+ $rstest = $zthis->Execute($rewritesql,$inputarr);
+ if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
+ }
if ($rstest) {
- $qryRecs = $rstest->RecordCount();
- if ($qryRecs == -1) {
- global $ADODB_EXTENSION;
- // some databases will return -1 on MoveLast() - change to MoveNext()
- if ($ADODB_EXTENSION) {
- while(!$rstest->EOF) {
- adodb_movenext($rstest);
- }
- } else {
- while(!$rstest->EOF) {
- $rstest->MoveNext();
- }
+ $qryRecs = $rstest->RecordCount();
+ if ($qryRecs == -1) {
+ // some databases will return -1 on MoveLast() - change to MoveNext()
+ while(!$rstest->EOF) {
+ $rstest->MoveNext();
}
$qryRecs = $rstest->_currentRow;
}
@@ -448,53 +523,53 @@ function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
/*
Code originally from "Cornel G"
- This code might not work with SQL that has UNION in it
-
+ This code might not work with SQL that has UNION in it
+
Also if you are using CachePageExecute(), there is a strong possibility that
data will get out of synch. use CachePageExecute() only with tables that
rarely change.
*/
-function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
- $inputarr=false, $secs2cache=0)
+function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
+ $inputarr=false, $secs2cache=0)
{
$atfirstpage = false;
$atlastpage = false;
$lastpageno=1;
- // If an invalid nrows is supplied,
+ // If an invalid nrows is supplied,
// we assume a default value of 10 rows per page
if (!isset($nrows) || $nrows <= 0) $nrows = 10;
$qryRecs = false; //count records for no offset
-
+
$qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
$lastpageno = (int) ceil($qryRecs / $nrows);
$zthis->_maxRecordCount = $qryRecs;
-
- // ***** Here we check whether $page is the last page or
- // whether we are trying to retrieve
+
+ // ***** Here we check whether $page is the last page or
+ // whether we are trying to retrieve
// a page number greater than the last page number.
if ($page >= $lastpageno) {
$page = $lastpageno;
$atlastpage = true;
}
-
+
// If page number <= 1, then we are at the first page
- if (empty($page) || $page <= 1) {
+ if (empty($page) || $page <= 1) {
$page = 1;
$atfirstpage = true;
}
-
+
// We get the data we want
$offset = $nrows * ($page-1);
- if ($secs2cache > 0)
- $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
- else
- $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
+ if ($secs2cache > 0)
+ $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
+ else
+ $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
+
-
// Before returning the RecordSet, we set the pagination properties we need
if ($rsreturn) {
$rsreturn->_maxRecordCount = $qryRecs;
@@ -507,47 +582,87 @@ function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
return $rsreturn;
}
-// Iván Oliva version
-function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
+// Iván Oliva version
+function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
{
$atfirstpage = false;
$atlastpage = false;
-
- if (!isset($page) || $page <= 1) { // If page number <= 1, then we are at the first page
+
+ if (!isset($page) || $page <= 1) {
+ // If page number <= 1, then we are at the first page
$page = 1;
$atfirstpage = true;
}
- if ($nrows <= 0) $nrows = 10; // If an invalid nrows is supplied, we assume a default value of 10 rows per page
-
- // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than
- // the last page number.
- $pagecounter = $page + 1;
- $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
- if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
- else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
- if ($rstest) {
- while ($rstest && $rstest->EOF && $pagecounter>0) {
- $atlastpage = true;
- $pagecounter--;
- $pagecounteroffset = $nrows * ($pagecounter - 1);
- $rstest->Close();
- if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
- else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
- }
- if ($rstest) $rstest->Close();
+ if ($nrows <= 0) {
+ // If an invalid nrows is supplied, we assume a default value of 10 rows per page
+ $nrows = 10;
}
- if ($atlastpage) { // If we are at the last page or beyond it, we are going to retrieve it
- $page = $pagecounter;
- if ($page == 1) $atfirstpage = true; // We have to do this again in case the last page is the same as the first
- //... page, that is, the recordset has only 1 page.
+
+ $pagecounteroffset = ($page * $nrows) - $nrows;
+
+ // To find out if there are more pages of rows, simply increase the limit or
+ // nrows by 1 and see if that number of records was returned. If it was,
+ // then we know there is at least one more page left, otherwise we are on
+ // the last page. Therefore allow non-Count() paging with single queries
+ // rather than three queries as was done before.
+ $test_nrows = $nrows + 1;
+ if ($secs2cache > 0) {
+ $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
+ } else {
+ $rsreturn = $zthis->SelectLimit($sql, $test_nrows, $pagecounteroffset, $inputarr, $secs2cache);
}
-
- // We get the data we want
- $offset = $nrows * ($page-1);
- if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
- else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
-
+
+ // Now check to see if the number of rows returned was the higher value we asked for or not.
+ if ( $rsreturn->_numOfRows == $test_nrows ) {
+ // Still at least 1 more row, so we are not on last page yet...
+ // Remove the last row from the RS.
+ $rsreturn->_numOfRows = ( $rsreturn->_numOfRows - 1 );
+ } elseif ( $rsreturn->_numOfRows == 0 && $page > 1 ) {
+ // Likely requested a page that doesn't exist, so need to find the last
+ // page and return it. Revert to original method and loop through pages
+ // until we find some data...
+ $pagecounter = $page + 1;
+ $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
+
+ $rstest = $rsreturn;
+ if ($rstest) {
+ while ($rstest && $rstest->EOF && $pagecounter > 0) {
+ $atlastpage = true;
+ $pagecounter--;
+ $pagecounteroffset = $nrows * ($pagecounter - 1);
+ $rstest->Close();
+ if ($secs2cache>0) {
+ $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
+ }
+ else {
+ $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
+ }
+ }
+ if ($rstest) $rstest->Close();
+ }
+ if ($atlastpage) {
+ // If we are at the last page or beyond it, we are going to retrieve it
+ $page = $pagecounter;
+ if ($page == 1) {
+ // We have to do this again in case the last page is the same as
+ // the first page, that is, the recordset has only 1 page.
+ $atfirstpage = true;
+ }
+ }
+ // We get the data we want
+ $offset = $nrows * ($page-1);
+ if ($secs2cache > 0) {
+ $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
+ }
+ else {
+ $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
+ }
+ } elseif ( $rsreturn->_numOfRows < $test_nrows ) {
+ // Rows is less than what we asked for, so must be at the last page.
+ $atlastpage = true;
+ }
+
// Before returning the RecordSet, we set the pagination properties we need
if ($rsreturn) {
$rsreturn->rowsPerPage = $nrows;
@@ -558,140 +673,193 @@ function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputar
return $rsreturn;
}
-function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2)
+/**
+ * Performs case conversion and quoting of the given field name.
+ *
+ * See Global variable $ADODB_QUOTE_FIELDNAMES.
+ *
+ * @param ADOConnection $zthis
+ * @param string $fieldName
+ *
+ * @return string Quoted field name
+ */
+function _adodb_quote_fieldname($zthis, $fieldName)
{
- if (!$rs) {
- printf(ADODB_BAD_RS,'GetUpdateSQL');
- return false;
+ global $ADODB_QUOTE_FIELDNAMES;
+
+ // Case conversion - defaults to UPPER
+ $case = is_bool($ADODB_QUOTE_FIELDNAMES) ? 'UPPER' : $ADODB_QUOTE_FIELDNAMES;
+ switch ($case) {
+ case 'LOWER':
+ $fieldName = strtolower($fieldName);
+ break;
+ case 'NATIVE':
+ // Do nothing
+ break;
+ case 'UPPER':
+ case 'BRACKETS':
+ default:
+ $fieldName = strtoupper($fieldName);
+ break;
+ }
+
+ // Quote field if requested, or necessary (field contains space)
+ if ($ADODB_QUOTE_FIELDNAMES || strpos($fieldName, ' ') !== false ) {
+ if ($ADODB_QUOTE_FIELDNAMES === 'BRACKETS') {
+ return $zthis->leftBracket . $fieldName . $zthis->rightBracket;
+ } else {
+ return $zthis->nameQuote . $fieldName . $zthis->nameQuote;
}
-
- $fieldUpdatedCount = 0;
- $arrFields = _array_change_key_case($arrFields);
+ } else {
+ return $fieldName;
+ }
+}
- $hasnumeric = isset($rs->fields[0]);
- $setFields = '';
-
- // Loop through all of the fields in the recordset
- for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
- // Get the field from the recordset
- $field = $rs->FetchField($i);
-
- // If the recordset field is one
- // of the fields passed in then process.
- $upperfname = strtoupper($field->name);
- if (adodb_key_exists($upperfname,$arrFields,$force)) {
-
- // If the existing field value in the recordset
- // is different from the value passed in then
- // go ahead and append the field name and new value to
- // the update query.
-
- if ($hasnumeric) $val = $rs->fields[$i];
- else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
- else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
- else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
- else $val = '';
-
-
- if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
- // Set the counter for the number of fields that will be updated.
- $fieldUpdatedCount++;
-
- // Based on the datatype of the field
- // Format the value properly for the database
- $type = $rs->MetaType($field->type);
-
-
- if ($type == 'null') {
- $type = 'C';
- }
-
- if (strpos($upperfname,' ') !== false)
- $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
- else
- $fnameq = $upperfname;
-
-
- // is_null requires php 4.0.4
- //********************************************************//
- if (is_null($arrFields[$upperfname])
+function _adodb_getupdatesql(&$zthis, &$rs, $arrFields, $forceUpdate=false, $force=2)
+{
+ if (!$rs) {
+ printf(ADODB_BAD_RS,'GetUpdateSQL');
+ return false;
+ }
+
+ $fieldUpdatedCount = 0;
+ if (is_array($arrFields))
+ $arrFields = array_change_key_case($arrFields,CASE_UPPER);
+
+ $hasnumeric = isset($rs->fields[0]);
+ $setFields = '';
+
+ // Loop through all of the fields in the recordset
+ for ($i=0, $max=$rs->fieldCount(); $i < $max; $i++) {
+ // Get the field from the recordset
+ $field = $rs->fetchField($i);
+
+ // If the recordset field is one
+ // of the fields passed in then process.
+ $upperfname = strtoupper($field->name);
+ if (adodb_key_exists($upperfname, $arrFields, $force)) {
+
+ // If the existing field value in the recordset
+ // is different from the value passed in then
+ // go ahead and append the field name and new value to
+ // the update query.
+
+ if ($hasnumeric) $val = $rs->fields[$i];
+ else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
+ else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
+ else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
+ else $val = '';
+
+ if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
+ // Set the counter for the number of fields that will be updated.
+ $fieldUpdatedCount++;
+
+ // Based on the datatype of the field
+ // Format the value properly for the database
+ $type = $rs->metaType($field->type);
+
+ if ($type == 'null') {
+ $type = 'C';
+ }
+
+ $fnameq = _adodb_quote_fieldname($zthis, $field->name);
+
+ //********************************************************//
+ if (is_null($arrFields[$upperfname])
|| (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
- || $arrFields[$upperfname] === 'null'
- )
- {
- switch ($force) {
+ || $arrFields[$upperfname] === $zthis->null2null
+ ) {
- //case 0:
- // //Ignore empty values. This is allready handled in "adodb_key_exists" function.
- //break;
+ switch ($force) {
+
+ //case 0:
+ // // Ignore empty values. This is already handled in "adodb_key_exists" function.
+ // break;
+
+ case 1:
+ // set null
+ $setFields .= $fnameq . " = null, ";
+ break;
+
+ case 2:
+ // set empty
+ $arrFields[$upperfname] = "";
+ $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, $arrFields);
+ break;
- case 1:
- //Set null
- $setFields .= $field->name . " = null, ";
- break;
-
- case 2:
- //Set empty
- $arrFields[$upperfname] = "";
- $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
- break;
default:
- case 3:
- //Set the value that was given in array, so you can give both null and empty values
- if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === 'null') {
- $setFields .= $field->name . " = null, ";
- } else {
- $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
- }
- break;
- }
- //********************************************************//
- } else {
- //we do this so each driver can customize the sql for
- //DB specific column types.
- //Oracle needs BLOB types to be handled with a returning clause
- //postgres has special needs as well
- $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
- $arrFields, $magicq);
+ case 3:
+ // set the value that was given in array, so you can give both null and empty values
+ if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
+ $setFields .= $fnameq . " = null, ";
+ } else {
+ $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, $arrFields);
+ }
+ break;
+
+ case ADODB_FORCE_NULL_AND_ZERO:
+
+ switch ($type) {
+ case 'N':
+ case 'I':
+ case 'L':
+ $setFields .= $fnameq . ' = 0, ';
+ break;
+ default:
+ $setFields .= $fnameq . ' = null, ';
+ break;
+ }
+ break;
+
}
+ //********************************************************//
+ } else {
+ // we do this so each driver can customize the sql for
+ // DB specific column types.
+ // Oracle needs BLOB types to be handled with a returning clause
+ // postgres has special needs as well
+ $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, $arrFields);
}
}
}
+ }
- // If there were any modified fields then build the rest of the update query.
- if ($fieldUpdatedCount > 0 || $forceUpdate) {
- // Get the table name from the existing query.
- if (!empty($rs->tableName)) $tableName = $rs->tableName;
- else {
- preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
- $tableName = $tableName[1];
- }
- // Get the full where clause excluding the word "WHERE" from
- // the existing query.
- preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
-
- $discard = false;
- // not a good hack, improvements?
- if ($whereClause) {
- #var_dump($whereClause);
- if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
- else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
- else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
- else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see http://sourceforge.net/tracker/index.php?func=detail&aid=1379638&group_id=42718&atid=433976
- } else
- $whereClause = array(false,false);
-
- if ($discard)
- $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
-
- $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2);
- if (strlen($whereClause[1]) > 0)
- $sql .= ' WHERE '.$whereClause[1];
+ // If there were any modified fields then build the rest of the update query.
+ if ($fieldUpdatedCount > 0 || $forceUpdate) {
+ // Get the table name from the existing query.
+ if (!empty($rs->tableName)) {
+ $tableName = $rs->tableName;
+ } else {
+ preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
+ $tableName = $tableName[1];
+ }
- return $sql;
+ // Get the full where clause excluding the word "WHERE" from the existing query.
+ preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
+ $discard = false;
+ // not a good hack, improvements?
+ if ($whereClause) {
+ #var_dump($whereClause);
+ if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
+ else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
+ else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
+ else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see https://sourceforge.net/p/adodb/bugs/37/
} else {
- return false;
+ $whereClause = array(false, false);
+ }
+
+ if ($discard) {
+ $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
+ }
+
+ $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2);
+ if (strlen($whereClause[1]) > 0) {
+ $sql .= ' WHERE '.$whereClause[1];
+ }
+ return $sql;
+ } else {
+ return false;
}
}
@@ -702,20 +870,20 @@ function adodb_key_exists($key, &$arr,$force=2)
return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0);
}
- if (isset($arr[$key])) return true;
+ if (isset($arr[$key]))
+ return true;
## null check below
- if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
- return false;
+ return array_key_exists($key,$arr);
}
/**
* There is a special case of this function for the oci8 driver.
* The proper way to handle an insert w/ a blob in oracle requires
* a returning clause with bind variables and a descriptor blob.
- *
- *
+ *
+ *
*/
-function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
+function _adodb_getinsertsql(&$zthis, &$rs, $arrFields, $force=2)
{
static $cacheRS = false;
static $cacheSig = 0;
@@ -725,23 +893,24 @@ function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
$values = '';
$fields = '';
$recordSet = null;
- $arrFields = _array_change_key_case($arrFields);
+ if (is_array($arrFields))
+ $arrFields = array_change_key_case($arrFields,CASE_UPPER);
$fieldInsertedCount = 0;
-
+
if (is_string($rs)) {
//ok we have a table name
//try and get the column info ourself.
- $tableName = $rs;
-
+ $tableName = $rs;
+
//we need an object for the recordSet
//because we have to call MetaType.
//php can't do a $rsclass::MetaType()
$rsclass = $zthis->rsPrefix.$zthis->databaseType;
$recordSet = new $rsclass(-1,$zthis->fetchMode);
- $recordSet->connection = &$zthis;
-
+ $recordSet->connection = $zthis;
+
if (is_string($cacheRS) && $cacheRS == $rs) {
- $columns =& $cacheCols;
+ $columns = $cacheCols;
} else {
$columns = $zthis->MetaColumns( $tableName );
$cacheRS = $tableName;
@@ -749,81 +918,91 @@ function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
}
} else if (is_subclass_of($rs, 'adorecordset')) {
if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
- $columns =& $cacheCols;
+ $columns = $cacheCols;
} else {
- for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
+ for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
$columns[] = $rs->FetchField($i);
$cacheRS = $cacheSig;
$cacheCols = $columns;
$rs->insertSig = $cacheSig++;
}
- $recordSet =& $rs;
-
+ $recordSet = $rs;
+
} else {
printf(ADODB_BAD_RS,'GetInsertSQL');
return false;
}
// Loop through all of the fields in the recordset
- foreach( $columns as $field ) {
+ foreach( $columns as $field ) {
$upperfname = strtoupper($field->name);
if (adodb_key_exists($upperfname,$arrFields,$force)) {
$bad = false;
- if (strpos($upperfname,' ') !== false)
- $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
- else
- $fnameq = $upperfname;
-
+ $fnameq = _adodb_quote_fieldname($zthis, $field->name);
$type = $recordSet->MetaType($field->type);
-
+
/********************************************************/
if (is_null($arrFields[$upperfname])
|| (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
- || $arrFields[$upperfname] === 'null'
+ || $arrFields[$upperfname] === $zthis->null2null
)
{
switch ($force) {
- case 0: // we must always set null if missing
+ case ADODB_FORCE_IGNORE: // we must always set null if missing
$bad = true;
break;
-
- case 1:
+
+ case ADODB_FORCE_NULL:
$values .= "null, ";
break;
-
- case 2:
+
+ case ADODB_FORCE_EMPTY:
//Set empty
$arrFields[$upperfname] = "";
- $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq);
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
break;
default:
- case 3:
+ case ADODB_FORCE_VALUE:
//Set the value that was given in array, so you can give both null and empty values
- if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === 'null') {
+ if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
$values .= "null, ";
} else {
- $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
}
break;
+
+ case ADODB_FORCE_NULL_AND_ZERO:
+ switch ($type)
+ {
+ case 'N':
+ case 'I':
+ case 'L':
+ $values .= '0, ';
+ break;
+ default:
+ $values .= "null, ";
+ break;
+ }
+ break;
+
} // switch
/*********************************************************/
} else {
//we do this so each driver can customize the sql for
- //DB specific column types.
+ //DB specific column types.
//Oracle needs BLOB types to be handled with a returning clause
//postgres has special needs as well
- $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,
- $arrFields, $magicq);
+ $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields);
}
-
+
if ($bad) continue;
// Set the counter for the number of fields that will be inserted.
$fieldInsertedCount++;
-
-
+
+
// Get the name of the fields to insert
$fields .= $fnameq . ", ";
}
@@ -832,15 +1011,15 @@ function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
// If there were any inserted fields then build the rest of the insert query.
if ($fieldInsertedCount <= 0) return false;
-
+
// Get the table name from the existing query.
if (!$tableName) {
if (!empty($rs->tableName)) $tableName = $rs->tableName;
else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName))
$tableName = $tableName[1];
- else
+ else
return false;
- }
+ }
// Strip off the comma and space on the end of both the fields
// and their values.
@@ -857,20 +1036,20 @@ function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
* the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
* It handles the string construction of 1 column -> sql string based on
* the column type. We want to do 'safe' handling of BLOBs
- *
+ *
* @param string the type of sql we are trying to create
- * 'I' or 'U'.
- * @param string column data type from the db::MetaType() method
+ * 'I' or 'U'.
+ * @param string column data type from the db::MetaType() method
* @param string the column name
* @param array the column value
- *
+ *
* @return string
- *
+ *
*/
-function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq)
+function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields)
{
$sql = '';
-
+
// Based on the datatype of the field
// Format the value properly for the database
switch($type) {
@@ -878,7 +1057,7 @@ function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFie
//in order to handle Blobs correctly, we need
//to do some magic for Oracle
- //we need to create a new descriptor to handle
+ //we need to create a new descriptor to handle
//this properly
if (!empty($zthis->hasReturningInto)) {
if ($action == 'I') {
@@ -895,11 +1074,11 @@ function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFie
$sql = 'empty_blob(), ';
} else {
$sql = $fnameq. '=empty_blob(), ';
- }
+ }
} else {
//this is to maintain compatibility
//with older adodb versions.
- $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
}
break;
@@ -911,7 +1090,7 @@ function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFie
//to avoid conflicts w/ dupes.
if (!empty($zthis->hasReturningInto)) {
if ($action == 'I') {
- $sql = ':xx'.$fname.'xx, ';
+ $sql = ':xx'.$fname.'xx, ';
} else {
$sql = $fnameq.'=:xx'.$fname.'xx, ';
}
@@ -922,19 +1101,19 @@ function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFie
} else {
//this is to maintain compatibility
//with older adodb versions.
- $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
- }
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
+ }
break;
-
+
default:
- $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
+ $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false);
break;
}
-
+
return $sql;
-}
-
-function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true)
+}
+
+function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $recurse=true)
{
if ($recurse) {
@@ -943,16 +1122,16 @@ function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields,
if ($type == 'L') $type = 'C';
break;
case 'oci8':
- return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq);
-
+ return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields);
+
}
}
-
+
switch($type) {
case "C":
case "X":
case 'B':
- $val = $zthis->qstr($arrFields[$fname],$magicq);
+ $val = $zthis->qstr($arrFields[$fname]);
break;
case "D":
@@ -963,17 +1142,26 @@ function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields,
$val = $zthis->DBTimeStamp($arrFields[$fname]);
break;
+ case "N":
+ $val = $arrFields[$fname];
+ if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val);
+ break;
+
+ case "I":
+ case "R":
+ $val = $arrFields[$fname];
+ if (!is_numeric($val)) $val = (integer) $val;
+ break;
+
default:
- $val = $arrFields[$fname];
+ $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence
if (empty($val)) $val = '0';
break;
}
if ($action == 'I') return $val . ", ";
-
-
+
return $fnameq . "=" . $val . ", ";
-
}
@@ -984,8 +1172,17 @@ function _adodb_debug_execute(&$zthis, $sql, $inputarr)
if ($inputarr) {
foreach($inputarr as $kk=>$vv) {
if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
- $ss .= "($kk=>'$vv') ";
+ if (is_null($vv)) $ss .= "($kk=>null) ";
+ else
+ {
+ if (is_array($vv))
+ {
+ $vv = sprintf("Array Of Values: [%s]", implode(',',$vv));
+ }
+ $ss .= "($kk=>'$vv') ";
+ }
}
+
$ss = "[ $ss ]";
}
$sqlTxt = is_array($sql) ? $sql[0] : $sql;
@@ -995,7 +1192,7 @@ function _adodb_debug_execute(&$zthis, $sql, $inputarr)
*/
// check if running from browser or command-line
$inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
-
+
$dbt = $zthis->databaseType;
if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
if ($inBrowser) {
@@ -1003,55 +1200,70 @@ function _adodb_debug_execute(&$zthis, $sql, $inputarr)
$ss = ''.htmlspecialchars($ss).'';
}
if ($zthis->debug === -1)
- ADOConnection::outp( " \n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n \n",false);
- else
- ADOConnection::outp( " \n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n \n",false);
+ ADOConnection::outp( " \n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n \n",false);
+ else if ($zthis->debug !== -99)
+ ADOConnection::outp( " \n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n \n",false);
} else {
- ADOConnection::outp("-----\n($dbt): ".$sqlTxt."\n-----\n",false);
+ $ss = "\n ".$ss;
+ if ($zthis->debug !== -99)
+ ADOConnection::outp("----- \n($dbt): ".$sqlTxt." $ss\n----- \n",false);
}
$qID = $zthis->_query($sql,$inputarr);
-
- /*
+
+ /*
Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
*/
- if ($zthis->databaseType == 'mssql') {
+ if ($zthis->databaseType == 'mssql') {
// ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
+
if($emsg = $zthis->ErrorMsg()) {
- if ($err = $zthis->ErrorNo()) ADOConnection::outp($err.': '.$emsg);
+ if ($err = $zthis->ErrorNo()) {
+ if ($zthis->debug === -99)
+ ADOConnection::outp( " \n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n \n",false);
+
+ ADOConnection::outp($err.': '.$emsg);
+ }
}
} else if (!$qID) {
+
+ if ($zthis->debug === -99)
+ if ($inBrowser) ADOConnection::outp( " \n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n \n",false);
+ else ADOConnection::outp("----- \n($dbt): ".$sqlTxt."$ss\n----- \n",false);
+
ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
}
-
+
if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
return $qID;
}
# pretty print the debug_backtrace function
-function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
+function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0,$ishtml=null)
{
if (!function_exists('debug_backtrace')) return '';
-
- $html = (isset($_SERVER['HTTP_USER_AGENT']));
+
+ if ($ishtml === null) $html = (isset($_SERVER['HTTP_USER_AGENT']));
+ else $html = $ishtml;
+
$fmt = ($html) ? " %% line %4d, file: %s " : "%% line %4d, file: %s";
$MAXSTRLEN = 128;
$s = ($html) ? '' : '';
-
+
if (is_array($printOrArr)) $traceArr = $printOrArr;
else $traceArr = debug_backtrace();
array_shift($traceArr);
array_shift($traceArr);
$tabs = sizeof($traceArr)-2;
-
+
foreach ($traceArr as $arr) {
if ($skippy) {$skippy -= 1; continue;}
$levels -= 1;
if ($levels < 0) break;
-
+
$args = array();
for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' ' : "\t";
$tabs -= 1;
@@ -1065,36 +1277,36 @@ function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
else {
$v = (string) @$v;
- $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
+ $str = htmlspecialchars(str_replace(array("\r","\n"),' ',substr($v,0,$MAXSTRLEN)));
if (strlen($v) > $MAXSTRLEN) $str .= '...';
$args[] = $str;
}
}
$s .= $arr['function'].'('.implode(', ',$args).')';
-
-
+
+
$s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
-
+
$s .= "\n";
- }
+ }
if ($html) $s .= ' ';
if ($printOrArr) print $s;
-
+
return $s;
}
/*
-function _adodb_find_from($sql)
+function _adodb_find_from($sql)
{
$sql = str_replace(array("\n","\r"), ' ', $sql);
$charCount = strlen($sql);
-
+
$inString = false;
$quote = '';
$parentheseCount = 0;
$prevChars = '';
$nextChars = '';
-
+
for($i = 0; $i < $charCount; $i++) {
@@ -1124,5 +1336,3 @@ function _adodb_find_from($sql)
}
}
*/
-
-?>
\ No newline at end of file
diff --git a/adodb/adodb-loadbalancer.inc.php b/adodb/adodb-loadbalancer.inc.php
new file mode 100644
index 0000000..2e4f392
--- /dev/null
+++ b/adodb/adodb-loadbalancer.inc.php
@@ -0,0 +1,773 @@
+ 0, 'write' => 0, 'readonly' => 0);
+
+ /**
+ * @var array Weights of all connections for each type.
+ */
+ protected $total_connection_weights = array('all' => 0, 'write' => 0, 'readonly' => 0);
+
+ /**
+ * @var bool When in transactions, always use this connection.
+ */
+ protected $pinned_connection_id = false;
+
+ /**
+ * @var array Last connection_id for each database type.
+ */
+ protected $last_connection_id = array('write' => false, 'readonly' => false, 'all' => false);
+
+ /**
+ * @var bool Session variables that must be maintained across all connections, ie: SET TIME ZONE.
+ */
+ protected $session_variables = false;
+
+ /**
+ * @var bool Called immediately after connecting to any DB.
+ */
+ protected $user_defined_session_init_sql = false;
+
+
+ /**
+ * Defines SQL queries that are executed each time a new database connection is established.
+ *
+ * @param $sql
+ * @return bool
+ */
+ public function setSessionInitSQL($sql)
+ {
+ $this->user_defined_session_init_sql[] = $sql;
+
+ return true;
+ }
+
+ /**
+ * Adds a new database connection to the pool, but no actual connection is made until its needed.
+ *
+ * @param $obj
+ * @return bool
+ * @throws Exception
+ */
+ public function addConnection($obj)
+ {
+ if ($obj instanceof ADOdbLoadBalancerConnection) {
+ $this->connections[] = $obj;
+ end($this->connections);
+ $i = key($this->connections);
+
+ $this->total_connections[$obj->type]++;
+ $this->total_connections['all']++;
+
+ $this->total_connection_weights[$obj->type] += abs($obj->weight);
+ $this->total_connection_weights['all'] += abs($obj->weight);
+
+ if ($obj->type == 'write') {
+ $this->connections_write[] = $i;
+ } else {
+ $this->connections_readonly[] = $i;
+ }
+
+ return true;
+ }
+
+ throw new Exception('Connection object is not an instance of ADOdbLoadBalancerConnection');
+ }
+
+ /**
+ * Removes a database connection from the pool.
+ *
+ * @param $i
+ * @return bool
+ */
+ public function removeConnection($i)
+ {
+ if (isset($this->connections[$i])) {
+ $obj = $this->connections[ $i ];
+
+ $this->total_connections[ $obj->type ]--;
+ $this->total_connections['all']--;
+
+ $this->total_connection_weights[ $obj->type ] -= abs($obj->weight);
+ $this->total_connection_weights['all'] -= abs($obj->weight);
+
+ if ($obj->type == 'write') {
+ unset($this->connections_write[array_search($i, $this->connections_write)]);
+ // Reindex array.
+ $this->connections_write = array_values($this->connections_write);
+ } else {
+ unset($this->connections_readonly[array_search($i, $this->connections_readonly)]);
+ // Reindex array.
+ $this->connections_readonly = array_values($this->connections_readonly);
+ }
+
+ // Remove any sticky connections as well.
+ if ($this->last_connection_id[$obj->type] == $i) {
+ $this->last_connection_id[$obj->type] = false;
+ }
+
+ unset($this->connections[$i]);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a database connection of the specified type.
+ *
+ * Takes into account the connection weight for load balancing.
+ *
+ * @param string $type Type of database connection, either: 'write' capable or 'readonly'
+ * @return bool|int|string
+ */
+ private function getConnectionByWeight($type)
+ {
+ if ($type == 'readonly') {
+ $total_weight = $this->total_connection_weights['all'];
+ } else {
+ $total_weight = $this->total_connection_weights['write'];
+ }
+
+ $i = false;
+ if (is_array($this->connections)) {
+ $n = 0;
+ $num = mt_rand(0, $total_weight);
+ foreach ($this->connections as $i => $connection_obj) {
+ if ($connection_obj->weight > 0 && ($type == 'readonly' || $connection_obj->type == 'write')) {
+ $n += $connection_obj->weight;
+ if ($n >= $num) {
+ break;
+ }
+ }
+ }
+ }
+
+ return $i;
+ }
+
+ /**
+ * Returns the proper database connection when taking into account sticky sessions and load balancing.
+ *
+ * @param $type
+ * @return bool|int|mixed|string
+ */
+ public function getLoadBalancedConnection($type)
+ {
+ if ($this->total_connections == 0) {
+ $connection_id = 0;
+ } else {
+ if ($this->enable_sticky_sessions == true && $this->last_connection_id[$type] !== false) {
+ $connection_id = $this->last_connection_id[$type];
+ } else {
+ if ($type == 'write' && $this->total_connections['write'] == 1) {
+ $connection_id = $this->connections_write[0];
+ } else {
+ $connection_id = $this->getConnectionByWeight($type);
+ }
+ }
+ }
+
+ return $connection_id;
+ }
+
+ /**
+ * Returns the ADODB connection object by connection_id.
+ *
+ * Ensures that it's connected and the session variables are executed.
+ *
+ * @param $connection_id
+ * @return bool|ADOConnection
+ * @throws Exception
+ */
+ private function _getConnection($connection_id)
+ {
+ if (isset($this->connections[$connection_id])) {
+ $connection_obj = $this->connections[$connection_id];
+ /** @var ADOConnection $adodb_obj */
+ $adodb_obj = $connection_obj->getADOdbObject();
+ if (is_object($adodb_obj) && $adodb_obj->_connectionID == false) {
+ try {
+ if ($connection_obj->persistent_connection == true) {
+ $adodb_obj->Pconnect(
+ $connection_obj->host,
+ $connection_obj->user,
+ $connection_obj->password,
+ $connection_obj->database
+ );
+ } else {
+ $adodb_obj->Connect(
+ $connection_obj->host,
+ $connection_obj->user,
+ $connection_obj->password,
+ $connection_obj->database
+ );
+ }
+ } catch (Exception $e) {
+ // Connection error, see if there are other connections to try still.
+ throw $e; // No connections left, reThrow exception so application can catch it.
+ }
+
+ if (is_array($this->user_defined_session_init_sql)) {
+ foreach ($this->user_defined_session_init_sql as $session_init_sql) {
+ $adodb_obj->Execute($session_init_sql);
+ }
+ }
+ $this->executeSessionVariables($adodb_obj);
+ }
+
+ return $adodb_obj;
+ } else {
+ throw new Exception('Unable to return Connection object...');
+ }
+ }
+
+ /**
+ * Returns the ADODB connection object by database type.
+ *
+ * Ensures that it's connected and the session variables are executed.
+ *
+ * @param string $type
+ * @param null $pin_connection
+ * @return ADOConnection|bool
+ * @throws Exception
+ */
+ public function getConnection($type = 'write', $pin_connection = null)
+ {
+ while (($type == 'write' && $this->total_connections['write'] > 0)
+ || ($type == 'readonly' && $this->total_connections['all'] > 0)
+ ) {
+ if ($this->pinned_connection_id !== false) {
+ $connection_id = $this->pinned_connection_id;
+ } else {
+ $connection_id = $this->getLoadBalancedConnection($type);
+ }
+
+ if ($connection_id !== false) {
+ try {
+ $adodb_obj = $this->_getConnection($connection_id);
+ // $connection_obj = $this->connections[$connection_id];
+ break;
+ } catch (Exception $e) {
+ // Connection error, see if there are other connections to try still.
+ $this->removeConnection($connection_id);
+ if ( ($type == 'write' && $this->total_connections['write'] == 0)
+ || ($type == 'readonly' && $this->total_connections['all'] == 0)
+ ) {
+ throw $e;
+ }
+ }
+ } else {
+ throw new Exception('Connection ID is invalid!');
+ }
+ }
+
+ $this->last_connection_id[$type] = $connection_id;
+
+ if ($pin_connection === true) {
+ $this->pinned_connection_id = $connection_id;
+ } elseif ($pin_connection === false && $adodb_obj->transOff <= 1) {
+ // UnPin connection only if we are 1 level deep in a transaction.
+ $this->pinned_connection_id = false;
+
+ // When unpinning connection, reset last_connection_id so readonly
+ // queries don't get stuck on the write capable connection.
+ $this->last_connection_id['write'] = false;
+ $this->last_connection_id['readonly'] = false;
+ }
+
+ return $adodb_obj;
+ }
+
+ /**
+ * This is a hack to work around pass by reference error.
+ *
+ * Parameter 1 to ADOConnection::GetInsertSQL() expected to be a reference,
+ * value given in adodb-loadbalancer.inc.php on line 83
+ *
+ * @param $arr
+ * @return array
+ */
+ private function makeValuesReferenced($arr)
+ {
+ $refs = array();
+
+ foreach ($arr as $key => $value) {
+ $refs[$key] = &$arr[$key];
+ }
+
+ return $refs;
+ }
+
+ /**
+ * Allow setting session variables that are maintained across connections.
+ *
+ * Its important that these are set using name/value, so it can determine
+ * if the same variable is set multiple times causing bloat/clutter when
+ * new connections are established. For example if the time_zone is set to
+ * many different ones through the course of a single connection, a new
+ * connection should only set it to the most recent value.
+ *
+ * @param $name
+ * @param $value
+ * @param bool $execute_immediately
+ * @return array|bool|mixed
+ * @throws Exception
+ */
+ public function setSessionVariable($name, $value, $execute_immediately = true)
+ {
+ $this->session_variables[$name] = $value;
+
+ if ($execute_immediately == true) {
+ return $this->executeSessionVariables();
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Executes the session variables on a given ADODB object.
+ *
+ * @param ADOConnection|bool $adodb_obj
+ * @return array|bool|mixed
+ * @throws Exception
+ */
+ private function executeSessionVariables($adodb_obj = false)
+ {
+ if (is_array($this->session_variables)) {
+ $sql = '';
+ foreach ($this->session_variables as $name => $value) {
+ // $sql .= 'SET SESSION '. $name .' '. $value;
+ // MySQL uses: SET SESSION foo_bar='foo'
+ // PGSQL uses: SET SESSION foo_bar 'foo'
+ // So leave it up to the user to pass the proper value with '=' if needed.
+ // This may be a candidate to move into ADOdb proper.
+ $sql .= 'SET SESSION ' . $name . ' ' . $value;
+ }
+
+ if ($adodb_obj !== false) {
+ return $adodb_obj->Execute($sql);
+ } else {
+ return $this->ClusterExecute($sql);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Executes the same SQL QUERY on the entire cluster of connections.
+ * Would be used for things like SET SESSION TIME ZONE calls and such.
+ *
+ * @param $sql
+ * @param bool $inputarr
+ * @param bool $return_all_results
+ * @param bool $existing_connections_only
+ * @return array|bool|mixed
+ * @throws Exception
+ */
+ public function clusterExecute(
+ $sql,
+ $inputarr = false,
+ $return_all_results = false,
+ $existing_connections_only = true
+ ) {
+ if (is_array($this->connections) && count($this->connections) > 0) {
+ foreach ($this->connections as $key => $connection_obj) {
+ if ($existing_connections_only == false
+ || ($existing_connections_only == true
+ && $connection_obj->getADOdbObject()->_connectionID !== false
+ )
+ ) {
+ $adodb_obj = $this->_getConnection($key);
+ if (is_object($adodb_obj)) {
+ $result_arr[] = $adodb_obj->Execute($sql, $inputarr);
+ }
+ }
+ }
+
+ if (isset($result_arr) && $return_all_results == true) {
+ return $result_arr;
+ } else {
+ // Loop through all results checking to see if they match, if they do return the first one
+ // otherwise return an array of all results.
+ if (isset($result_arr)) {
+ foreach ($result_arr as $result) {
+ if ($result == false) {
+ return $result_arr;
+ }
+ }
+
+ return $result_arr[0];
+ } else {
+ // When using lazy connections, there are cases where
+ // setSessionVariable() is called early on, but there are
+ // no connections to execute the queries on yet.
+ // This captures that case and forces a RETURN TRUE to occur.
+ // As likely the queries will be executed as soon as a
+ // connection is established.
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines if a SQL query is read-only or not.
+ *
+ * @param string $sql SQL Query to test.
+ * @return bool
+ */
+ public function isReadOnlyQuery($sql)
+ {
+ if ( stripos($sql, 'SELECT') === 0
+ && stripos($sql, 'FOR UPDATE') === false
+ && stripos($sql, ' INTO ') === false
+ && stripos($sql, 'LOCK IN') === false
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Use this instead of __call() as it significantly reduces the overhead of call_user_func_array().
+ *
+ * @param $sql
+ * @param bool $inputarr
+ * @return array|bool|mixed
+ * @throws Exception
+ */
+ public function execute($sql, $inputarr = false)
+ {
+ $type = 'write';
+ $pin_connection = null;
+
+ // Prevent leading spaces from causing isReadOnlyQuery/stripos from failing.
+ $sql = trim($sql);
+
+ // SELECT queries that can write and therefore must be run on a write capable connection.
+ // SELECT ... FOR UPDATE;
+ // SELECT ... INTO ...
+ // SELECT .. LOCK IN ... (MYSQL)
+ if ($this->isReadOnlyQuery($sql) == true) {
+ $type = 'readonly';
+ } elseif (stripos($sql, 'SET') === 0) {
+ // SET SQL statements should likely use setSessionVariable() instead,
+ // so state is properly maintained across connections, especially when they are lazily created.
+ return $this->ClusterExecute($sql, $inputarr);
+ }
+
+ $adodb_obj = $this->getConnection($type, $pin_connection);
+ if ($adodb_obj !== false) {
+ return $adodb_obj->Execute($sql, $inputarr);
+ }
+
+ return false;
+ }
+
+ /**
+ * Magic method to intercept method and callback to the proper ADODB object for write/readonly connections.
+ *
+ * @param string $method ADODB method to call.
+ * @param array $args Arguments to the ADODB method.
+ * @return bool|mixed
+ * @throws Exception
+ */
+ public function __call($method, $args)
+ {
+ $type = 'write';
+ $pin_connection = null;
+
+ // Intercept specific methods to determine if they are read-only or not.
+ $method = strtolower($method);
+ switch ($method) {
+ // case 'execute': // This is the direct overloaded function above instead.
+ case 'getone':
+ case 'getrow':
+ case 'getall':
+ case 'getcol':
+ case 'getassoc':
+ case 'selectlimit':
+ if ($this->isReadOnlyQuery(trim($args[0])) == true) {
+ $type = 'readonly';
+ }
+ break;
+ case 'cachegetone':
+ case 'cachegetrow':
+ case 'cachegetall':
+ case 'cachegetcol':
+ case 'cachegetassoc':
+ case 'cacheexecute':
+ case 'cacheselect':
+ case 'pageexecute':
+ case 'cachepageexecute':
+ $type = 'readonly';
+ break;
+ // case 'ignoreerrors':
+ // // When ignoreerrors is called, PIN to the connection until its called again.
+ // if (!isset($args[0]) || (isset($args[0]) && $args[0] == FALSE)) {
+ // $pin_connection = TRUE;
+ // } else {
+ // $pin_connection = FALSE;
+ // }
+ // break;
+
+ // Manual transactions
+ case 'begintrans':
+ case 'settransactionmode':
+ $pin_connection = true;
+ break;
+ case 'rollbacktrans':
+ case 'committrans':
+ $pin_connection = false;
+ break;
+ // Smart transactions
+ case 'starttrans':
+ $pin_connection = true;
+ break;
+ case 'completetrans':
+ case 'failtrans':
+ // getConnection() will only unpin the transaction if we're exiting the last nested transaction
+ $pin_connection = false;
+ break;
+
+ // Functions that don't require any connection and therefore
+ // shouldn't force a connection be established before they run.
+ case 'qstr':
+ case 'escape':
+ case 'binddate':
+ case 'bindtimestamp':
+ case 'setfetchmode':
+ $type = false; // No connection necessary.
+ break;
+
+ // Default to assuming write connection is required to be on the safe side.
+ default:
+ break;
+ }
+
+ if ($type === false) {
+ if (is_array($this->connections) && count($this->connections) > 0) {
+ foreach ($this->connections as $key => $connection_obj) {
+ $adodb_obj = $connection_obj->getADOdbObject();
+ return call_user_func_array(array($adodb_obj, $method), $this->makeValuesReferenced($args)); // Just makes the function call on the first object.
+ }
+ }
+ } else {
+ $adodb_obj = $this->getConnection($type, $pin_connection);
+ if (is_object($adodb_obj)) {
+ $result = call_user_func_array(array($adodb_obj, $method), $this->makeValuesReferenced($args));
+
+ return $result;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Magic method to proxy property getter calls back to the proper ADODB object currently in use.
+ *
+ * @param $property
+ * @return mixed
+ * @throws Exception
+ */
+ public function __get($property)
+ {
+ if (is_array($this->connections) && count($this->connections) > 0) {
+ foreach ($this->connections as $key => $connection_obj) {
+ // Just returns the property from the first object.
+ return $connection_obj->getADOdbObject()->$property;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Magic method to proxy property setter calls back to the proper ADODB object currently in use.
+ *
+ * @param $property
+ * @param $value
+ * @return mixed
+ * @throws Exception
+ */
+ public function __set($property, $value)
+ {
+ // Special function to set object properties on all objects
+ // without initiating a connection to the database.
+ if (is_array($this->connections) && count($this->connections) > 0) {
+ foreach ($this->connections as $key => $connection_obj) {
+ $connection_obj->getADOdbObject()->$property = $value;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Override the __clone() magic method.
+ */
+ private function __clone()
+ {
+ }
+}
+
+/**
+ * Class ADOdbLoadBalancerConnection
+ */
+class ADOdbLoadBalancerConnection
+{
+ /**
+ * @var bool ADOdb drive name.
+ */
+ protected $driver = false;
+
+ /**
+ * @var bool ADODB object.
+ */
+ protected $adodb_obj = false;
+
+ /**
+ * @var string Type of connection, either 'write' capable or 'readonly'
+ */
+ public $type = 'write';
+
+ /**
+ * @var int Weight of connection, lower receives less queries, higher receives more queries.
+ */
+ public $weight = 1;
+
+ /**
+ * @var bool Determines if the connection persistent.
+ */
+ public $persistent_connection = false;
+
+ /**
+ * @var string Database connection host
+ */
+ public $host = '';
+
+ /**
+ * @var string Database connection user
+ */
+ public $user = '';
+
+ /**
+ * @var string Database connection password
+ */
+ public $password = '';
+
+ /**
+ * @var string Database connection database name
+ */
+ public $database = '';
+
+ /**
+ * ADOdbLoadBalancerConnection constructor to setup the ADODB object.
+ *
+ * @param $driver
+ * @param string $type
+ * @param int $weight
+ * @param bool $persistent_connection
+ * @param string $argHostname
+ * @param string $argUsername
+ * @param string $argPassword
+ * @param string $argDatabaseName
+ */
+ public function __construct(
+ $driver,
+ $type = 'write',
+ $weight = 1,
+ $persistent_connection = false,
+ $argHostname = '',
+ $argUsername = '',
+ $argPassword = '',
+ $argDatabaseName = ''
+ ) {
+ if ($type !== 'write' && $type !== 'readonly') {
+ return false;
+ }
+
+ $this->adodb_obj = ADONewConnection($driver);
+
+ $this->type = $type;
+ $this->weight = $weight;
+ $this->persistent_connection = $persistent_connection;
+
+ $this->host = $argHostname;
+ $this->user = $argUsername;
+ $this->password = $argPassword;
+ $this->database = $argDatabaseName;
+
+ return true;
+ }
+
+ /**
+ * Returns the ADODB object for this connection.
+ *
+ * @return bool
+ */
+ public function getADOdbObject()
+ {
+ return $this->adodb_obj;
+ }
+}
diff --git a/adodb/adodb-memcache.lib.inc.php b/adodb/adodb-memcache.lib.inc.php
index fc4748a..7f110e7 100644
--- a/adodb/adodb-memcache.lib.inc.php
+++ b/adodb/adodb-memcache.lib.inc.php
@@ -1,4 +1,23 @@
pconnect($host, $port)) {
- $err = 'Can\'t connect to memcache server on: '.$host.':'.$port;
- return $false;
+ var $_connected = false;
+ var $_memcache = false;
+
+ function __construct(&$obj)
+ {
+ $this->hosts = $obj->memCacheHost;
+ $this->port = $obj->memCachePort;
+ $this->compress = $obj->memCacheCompress;
}
- $rs = $memcache->get($key);
- if (!$rs) {
- $err = 'Item with such key doesn\'t exists on the memcached server.';
- return $false;
+ // implement as lazy connection. The connection only occurs on CacheExecute call
+ function connect(&$err)
+ {
+ // do we have memcache or memcached?
+ if (class_exists('Memcache')) {
+ $this->library='Memcache';
+ $memcache = new MemCache;
+ } elseif (class_exists('Memcached')) {
+ $this->library='Memcached';
+ $memcache = new MemCached;
+ } else {
+ $err = 'Neither the Memcache nor Memcached PECL extensions were found!';
+ return false;
+ }
+
+ if (!is_array($this->hosts)) $this->hosts = array($this->hosts);
+
+ $failcnt = 0;
+ foreach($this->hosts as $host) {
+ if (!@$memcache->addServer($host,$this->port)) {
+ $failcnt += 1;
+ }
+ }
+ if ($failcnt == sizeof($this->hosts)) {
+ $err = 'Can\'t connect to any memcache server';
+ return false;
+ }
+ $this->_connected = true;
+ $this->_memcache = $memcache;
+ return true;
}
- $tdiff = intval($rs->timeCreated+$timeout - time());
- if ($tdiff <= 2) {
- switch($tdiff) {
- case 2:
- if ((rand() & 15) == 0) {
- $err = "Timeout 2";
- return $false;
+ // returns true or false. true if successful save
+ function writecache($filename, $contents, $debug, $secs2cache)
+ {
+ if (!$this->_connected) {
+ $err = '';
+ if (!$this->connect($err) && $debug) ADOConnection::outp($err);
+ }
+ if (!$this->_memcache) return false;
+
+ $failed=false;
+ switch ($this->library) {
+ case 'Memcache':
+ if (!$this->_memcache->set($filename, $contents, $this->compress ? MEMCACHE_COMPRESSED : 0, $secs2cache)) {
+ $failed=true;
}
break;
- case 1:
- if ((rand() & 3) == 0) {
- $err = "Timeout 1";
- return $false;
+ case 'Memcached':
+ if (!$this->_memcache->set($filename, $contents, $secs2cache)) {
+ $failed=true;
}
break;
- default:
- $err = "Timeout 0";
- return $false;
+ default:
+ $failed=true;
+ break;
}
- }
- return $rs;
- }
- function putmemcache($key, $rs, $host, $port, $compress, $debug=false)
- {
- $false = false;
- $true = true;
+ if($failed) {
+ if ($debug) ADOConnection::outp(" Failed to save data at the memcache server! \n");
+ return false;
+ }
- if (!function_exists('memcache_pconnect')) {
- if ($debug) ADOConnection::outp(" Memcache module PECL extension not found! \n");
- return $false;
+ return true;
}
- $memcache = new Memcache;
- if (!@$memcache->pconnect($host, $port)) {
- if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port \n");
- return $false;
- }
+ // returns a recordset
+ function readcache($filename, &$err, $secs2cache, $rsClass)
+ {
+ $false = false;
+ if (!$this->_connected) $this->connect($err);
+ if (!$this->_memcache) return $false;
+
+ $rs = $this->_memcache->get($filename);
+ if (!$rs) {
+ $err = 'Item with such key doesn\'t exist on the memcache server.';
+ return $false;
+ }
- $rs->timeCreated = time();
- if (!$memcache->set($key, $rs, $compress, 0)) {
- if ($debug) ADOConnection::outp(" Failed to save data at the memcached server! \n");
- return $false;
+ // hack, should actually use _csv2rs
+ $rs = explode("\n", $rs);
+ unset($rs[0]);
+ $rs = join("\n", $rs);
+ $rs = unserialize($rs);
+ if (! is_object($rs)) {
+ $err = 'Unable to unserialize $rs';
+ return $false;
+ }
+ if ($rs->timeCreated == 0) return $rs; // apparently have been reports that timeCreated was set to 0 somewhere
+
+ $tdiff = intval($rs->timeCreated+$secs2cache - time());
+ if ($tdiff <= 2) {
+ switch($tdiff) {
+ case 2:
+ if ((rand() & 15) == 0) {
+ $err = "Timeout 2";
+ return $false;
+ }
+ break;
+ case 1:
+ if ((rand() & 3) == 0) {
+ $err = "Timeout 1";
+ return $false;
+ }
+ break;
+ default:
+ $err = "Timeout 0";
+ return $false;
+ }
+ }
+ return $rs;
}
- return $true;
- }
- function flushmemcache($key=false, $host, $port, $debug=false)
- {
- if (!function_exists('memcache_pconnect')) {
- if ($debug) ADOConnection::outp(" Memcache module PECL extension not found! \n");
- return;
- }
+ function flushall($debug=false)
+ {
+ if (!$this->_connected) {
+ $err = '';
+ if (!$this->connect($err) && $debug) ADOConnection::outp($err);
+ }
+ if (!$this->_memcache) return false;
+
+ $del = $this->_memcache->flush();
- $memcache = new Memcache;
- if (!@$memcache->pconnect($host, $port)) {
- if ($debug) ADOConnection::outp(" Can't connect to memcache server on: $host:$port \n");
- return;
+ if ($debug)
+ if (!$del) ADOConnection::outp("flushall: failed! \n");
+ else ADOConnection::outp("flushall: succeeded! \n");
+
+ return $del;
}
- if ($key) {
- if (!$memcache->delete($key)) {
- if ($debug) ADOConnection::outp("CacheFlush: $key entery doesn't exist on memcached server! \n");
- } else {
- if ($debug) ADOConnection::outp("CacheFlush: $key entery flushed from memcached server! \n");
- }
- } else {
- if (!$memcache->flush()) {
- if ($debug) ADOConnection::outp("CacheFlush: Failure flushing all enteries from memcached server! \n");
- } else {
- if ($debug) ADOConnection::outp("CacheFlush: All enteries flushed from memcached server! \n");
+ function flushcache($filename, $debug=false)
+ {
+ if (!$this->_connected) {
+ $err = '';
+ if (!$this->connect($err) && $debug) ADOConnection::outp($err);
}
+ if (!$this->_memcache) return false;
+
+ $del = $this->_memcache->delete($filename);
+
+ if ($debug)
+ if (!$del) ADOConnection::outp("flushcache: $key entry doesn't exist on memcache server! \n");
+ else ADOConnection::outp("flushcache: $key entry flushed from memcache server! \n");
+
+ return $del;
+ }
+
+ // not used for memcache
+ function createdir($dir, $hash)
+ {
+ return true;
}
- return;
}
-?>
diff --git a/adodb/adodb-pager.inc.php b/adodb/adodb-pager.inc.php
index c302d8e..cfe981d 100644
--- a/adodb/adodb-pager.inc.php
+++ b/adodb/adodb-pager.inc.php
@@ -1,26 +1,24 @@
implemented Render_PageLinks().
-
- Please note, this class is entirely unsupported,
- and no free support requests except for bug reports
- will be entertained by the author.
-
-*/
class ADODB_Pager {
var $id; // unique id for pager (defaults to 'adodb')
var $db; // ADODB connection object
@@ -29,10 +27,10 @@ class ADODB_Pager {
var $curr_page; // current page number before Render() called, calculated in constructor
var $rows; // number of rows per page
var $linksPerPage=10; // number of links per page in navigation bar
- var $showPageLinks;
+ var $showPageLinks;
var $gridAttributes = 'width=100% border=1 bgcolor=white';
-
+
// Localize text strings here
var $first = '|<';
var $prev = '<<';
@@ -45,39 +43,39 @@ class ADODB_Pager {
var $page = 'Page';
var $linkSelectedColor = 'red';
var $cache = 0; #secs to cache with CachePageExecute()
-
+
//----------------------------------------------
// constructor
//
// $db adodb connection object
// $sql sql statement
- // $id optional id to identify which pager,
- // if you have multiple on 1 page.
+ // $id optional id to identify which pager,
+ // if you have multiple on 1 page.
// $id should be only be [a-z0-9]*
//
- function ADODB_Pager(&$db,$sql,$id = 'adodb', $showPageLinks = false)
+ function __construct(&$db,$sql,$id = 'adodb', $showPageLinks = false)
{
global $PHP_SELF;
-
+
$curr_page = $id.'_curr_page';
- if (empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
-
+ if (!empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
+
$this->sql = $sql;
$this->id = $id;
$this->db = $db;
$this->showPageLinks = $showPageLinks;
-
- $next_page = $id.'_next_page';
-
+
+ $next_page = $id.'_next_page';
+
if (isset($_GET[$next_page])) {
$_SESSION[$curr_page] = (integer) $_GET[$next_page];
}
if (empty($_SESSION[$curr_page])) $_SESSION[$curr_page] = 1; ## at first page
-
+
$this->curr_page = $_SESSION[$curr_page];
-
+
}
-
+
//---------------------------
// Display link to first page
function Render_First($anchor=true)
@@ -85,51 +83,51 @@ function Render_First($anchor=true)
global $PHP_SELF;
if ($anchor) {
?>
- first;?>
+ first;?>
first ";
}
}
-
+
//--------------------------
// Display link to next page
function render_next($anchor=true)
{
global $PHP_SELF;
-
+
if ($anchor) {
?>
- next;?>
+ next;?>
next ";
}
}
-
+
//------------------
// Link to last page
- //
+ //
// for better performance with large recordsets, you can set
// $this->db->pageExecuteCountRows = false, which disables
// last page counting.
function render_last($anchor=true)
{
global $PHP_SELF;
-
+
if (!$this->db->pageExecuteCountRows) return;
-
+
if ($anchor) {
?>
- last;?>
+ last;?>
last ";
}
}
-
+
//---------------------------------------------------
- // original code by "Pablo Costa"
+ // original code by "Pablo Costa"
function render_pagelinks()
{
global $PHP_SELF;
@@ -146,21 +144,21 @@ function render_pagelinks()
$end = $start+$linksperpage-1;
$link = $this->id . "_next_page";
if($end > $pages) $end = $pages;
-
-
+
+
if ($this->startLinks && $start > 1) {
$pos = $start - 1;
$numbers .= "$this->startLinks ";
- }
-
+ }
+
for($i=$start; $i <= $end; $i++) {
if ($this->rs->AbsolutePage() == $i)
$numbers .= "linkSelectedColor>$i ";
- else
+ else
$numbers .= "$i ";
-
+
}
- if ($this->moreLinks && $end < $pages)
+ if ($this->moreLinks && $end < $pages)
$numbers .= "$this->moreLinks ";
print $numbers . ' ';
}
@@ -170,13 +168,13 @@ function render_prev($anchor=true)
global $PHP_SELF;
if ($anchor) {
?>
- prev;?>
- id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>">prev;?>
+ prev ";
}
}
-
+
//--------------------------------------------------------
// Simply rendering of grid. You should override this for
// better control over the format of the grid
@@ -193,7 +191,7 @@ function RenderGrid()
ob_end_clean();
return $s;
}
-
+
//-------------------------------------------------------
// Navigation bar
//
@@ -222,7 +220,7 @@ function RenderNav()
ob_end_clean();
return $s;
}
-
+
//-------------------
// This is the footer
function RenderPageCount()
@@ -233,47 +231,47 @@ function RenderPageCount()
if ($this->curr_page > $lastPage) $this->curr_page = 1;
return "$this->page ".$this->curr_page."/".$lastPage." ";
}
-
+
//-----------------------------------
// Call this class to draw everything.
function Render($rows=10)
{
global $ADODB_COUNTRECS;
-
+
$this->rows = $rows;
-
+
if ($this->db->dataProvider == 'informix') $this->db->cursorType = IFX_SCROLL;
-
+
$savec = $ADODB_COUNTRECS;
if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
if ($this->cache)
- $rs = &$this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
+ $rs = $this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
else
- $rs = &$this->db->PageExecute($this->sql,$rows,$this->curr_page);
+ $rs = $this->db->PageExecute($this->sql,$rows,$this->curr_page);
$ADODB_COUNTRECS = $savec;
-
- $this->rs = &$rs;
+
+ $this->rs = $rs;
if (!$rs) {
print "Query failed: $this->sql ";
return;
}
-
- if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage()))
+
+ if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage()))
$header = $this->RenderNav();
else
$header = " ";
-
+
$grid = $this->RenderGrid();
$footer = $this->RenderPageCount();
-
+
$this->RenderLayout($header,$grid,$footer);
-
+
$rs->Close();
$this->rs = false;
}
-
+
//------------------------------------------------------
- // override this to control overall layout and formating
+ // override this to control overall layout and formatting
function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige')
{
echo "",
@@ -285,6 +283,3 @@ function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige'
"
";
}
}
-
-
-?>
\ No newline at end of file
diff --git a/adodb/adodb-pear.inc.php b/adodb/adodb-pear.inc.php
index 5d16708..c48ef13 100644
--- a/adodb/adodb-pear.inc.php
+++ b/adodb/adodb-pear.inc.php
@@ -1,21 +1,30 @@
+ * and Tomas V.V.Cox . Portions (c)1997-2002 The PHP Group.
+ *
+ * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
+ *
+ * @package ADOdb
+ * @link https://adodb.org Project's web site and documentation
+ * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
*
- * Set tabs to 4 for best viewing.
- *
- * PEAR DB Emulation Layer for ADODB.
+ * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
+ * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
+ * any later version. This means you can use it in proprietary products.
+ * See the LICENSE.md file distributed with this source code for details.
+ * @license BSD-3-Clause
+ * @license LGPL-2.1-or-later
*
- * The following code is modelled on PEAR DB code by Stig Bakken |
- * and Tomas V.V.Cox . Portions (c)1997-2002 The PHP Group.
+ * @copyright 2000-2013 John Lim
+ * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
*/
/*
We support:
-
+
DB_Common
---------
query - returns PEAR_Error on error
@@ -27,13 +36,13 @@
quote
nextID
disconnect
-
+
getOne
getAssoc
getRow
getCol
getAll
-
+
DB_Result
---------
numRows - returns -1 if not supported
@@ -42,7 +51,7 @@
fetchRows - does not support passing of fetchmode
free
*/
-
+
define('ADODB_PEAR',dirname(__FILE__));
include_once "PEAR.php";
include_once ADODB_PEAR."/adodb-errorpear.inc.php";
@@ -52,10 +61,6 @@
define("DB_OK", 1);
define("DB_ERROR",-1);
-// autoExecute constants
-define('DB_AUTOQUERY_INSERT', 1);
-define('DB_AUTOQUERY_UPDATE', 2);
-
/**
* This is a special constant that tells DB the user hasn't specified
* any particular get mode, so the default should be used.
@@ -109,11 +114,11 @@ class DB
* error
*/
- function &factory($type)
+ function factory($type)
{
include_once(ADODB_DIR."/drivers/adodb-$type.inc.php");
- $obj = &NewADOConnection($type);
- if (!is_object($obj)) $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+ $obj = NewADOConnection($type);
+ if (!is_object($obj)) $obj = new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
return $obj;
}
@@ -136,7 +141,7 @@ function &factory($type)
* @see DB::parseDSN
* @see DB::isError
*/
- function &connect($dsn, $options = false)
+ function connect($dsn, $options = false)
{
if (is_array($dsn)) {
$dsninfo = $dsn;
@@ -157,9 +162,9 @@ function &connect($dsn, $options = false)
@include_once("adodb-$type.inc.php");
}
- @$obj =& NewADOConnection($type);
+ @$obj = NewADOConnection($type);
if (!is_object($obj)) {
- $obj =& new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
+ $obj = new PEAR_Error('Unknown Database Driver: '.$dsninfo['phptype'],-1);
return $obj;
}
if (is_array($options)) {
@@ -183,10 +188,10 @@ function &connect($dsn, $options = false)
if (isset($dsninfo['socket'])) $dsninfo['hostspec'] .= ':'.$dsninfo['socket'];
else if (isset($dsninfo['port'])) $dsninfo['hostspec'] .= ':'.$dsninfo['port'];
-
+
if($persist) $ok = $obj->PConnect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
else $ok = $obj->Connect($dsninfo['hostspec'], $dsninfo['username'],$dsninfo['password'],$dsninfo['database']);
-
+
if (!$ok) $obj = ADODB_PEAR_Error();
return $obj;
}
@@ -211,8 +216,8 @@ function apiVersion()
function isError($value)
{
if (!is_object($value)) return false;
- $class = get_class($value);
- return $class == 'pear_error' || is_subclass_of($value, 'pear_error') ||
+ $class = strtolower(get_class($value));
+ return $class == 'pear_error' || is_subclass_of($value, 'pear_error') ||
$class == 'db_error' || is_subclass_of($value, 'db_error');
}
@@ -338,7 +343,7 @@ function parseDSN($dsn)
$parsed['hostspec'] = urldecode($str);
}
- // Get dabase if any
+ // Get database if any
// $dsn => database
if (!empty($dsn)) {
$parsed['database'] = $dsn;
@@ -360,7 +365,7 @@ function parseDSN($dsn)
*/
function assertExtension($name)
{
- if (!extension_loaded($name)) {
+ if (function_exists('dl') && !extension_loaded($name)) {
$dlext = (strncmp(PHP_OS,'WIN',3) === 0) ? '.dll' : '.so';
@dl($name . $dlext);
}
@@ -370,5 +375,3 @@ function assertExtension($name)
return true;
}
}
-
-?>
\ No newline at end of file
diff --git a/adodb/adodb-perf.inc.php b/adodb/adodb-perf.inc.php
index 0c8d38c..d9d8a99 100644
--- a/adodb/adodb-perf.inc.php
+++ b/adodb/adodb-perf.inc.php
@@ -1,20 +1,23 @@
= minimum number of secs to run
+
+
// returns in K the memory of current process, or 0 if not known
function adodb_getmem()
{
if (function_exists('memory_get_usage'))
return (integer) ((memory_get_usage()+512)/1024);
-
+
$pid = getmypid();
-
+
if ( strncmp(strtoupper(PHP_OS),'WIN',3)==0) {
$output = array();
-
- exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output);
+
+ exec('tasklist /FI "PID eq ' . $pid. '" /FO LIST', $output);
return substr($output[5], strpos($output[5], ':') + 1);
- }
-
+ }
+
/* Hopefully UNIX */
exec("ps --pid $pid --no-headers -o%mem,size", $output);
if (sizeof($output) == 0) return 0;
-
+
$memarr = explode(' ',$output[0]);
if (sizeof($memarr)>=2) return (integer) $memarr[1];
-
+
return 0;
}
@@ -53,39 +60,43 @@ function adodb_round($n,$prec)
return number_format($n, $prec, '.', '');
}
-/* return microtime value as a float */
+/* obsolete: return microtime value as a float. Retained for backward compat */
function adodb_microtime()
{
- $t = microtime();
- $t = explode(' ',$t);
- return (float)$t[1]+ (float)$t[0];
+ return microtime(true);
}
/* sql code timing */
-function& adodb_log_sql(&$conn,$sql,$inputarr)
+function adodb_log_sql(&$connx,$sql,$inputarr)
{
-
$perf_table = adodb_perf::table();
- $conn->fnExecute = false;
- $t0 = microtime();
- $rs =& $conn->Execute($sql,$inputarr);
- $t1 = microtime();
+ $connx->fnExecute = false;
+ $a0 = microtime(true);
+ $rs = $connx->Execute($sql,$inputarr);
+ $a1 = microtime(true);
+
+ if (!empty($connx->_logsql) && (empty($connx->_logsqlErrors) || !$rs)) {
+ global $ADODB_LOG_CONN;
+
+ if (!empty($ADODB_LOG_CONN)) {
+ $conn = $ADODB_LOG_CONN;
+ if ($conn->databaseType != $connx->databaseType)
+ $prefix = '/*dbx='.$connx->databaseType .'*/ ';
+ else
+ $prefix = '';
+ } else {
+ $conn = $connx;
+ $prefix = '';
+ }
- if (!empty($conn->_logsql) && (empty($conn->_logsqlErrors) || !$rs)) {
$conn->_logsql = false; // disable logsql error simulation
$dbT = $conn->databaseType;
-
- $a0 = split(' ',$t0);
- $a0 = (float)$a0[1]+(float)$a0[0];
-
- $a1 = split(' ',$t1);
- $a1 = (float)$a1[1]+(float)$a1[0];
-
+
$time = $a1 - $a0;
-
+
if (!$rs) {
- $errM = $conn->ErrorMsg();
- $errN = $conn->ErrorNo();
+ $errM = $connx->ErrorMsg();
+ $errN = $connx->ErrorNo();
$conn->lastInsID = 0;
$tracer = substr('ERROR: '.htmlspecialchars($errM),0,250);
} else {
@@ -94,20 +105,20 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
$errN = 0;
$dbg = $conn->debug;
$conn->debug = false;
- if (!is_object($rs) || $rs->dataProvider == 'empty')
+ if (!is_object($rs) || $rs->dataProvider == 'empty')
$conn->_affected = $conn->affected_rows(true);
$conn->lastInsID = @$conn->Insert_ID();
$conn->debug = $dbg;
}
if (isset($_SERVER['HTTP_HOST'])) {
$tracer .= ' '.$_SERVER['HTTP_HOST'];
- if (isset($_SERVER['PHP_SELF'])) $tracer .= $_SERVER['PHP_SELF'];
- } else
- if (isset($_SERVER['PHP_SELF'])) $tracer .= ' '.$_SERVER['PHP_SELF'];
+ if (isset($_SERVER['PHP_SELF'])) $tracer .= htmlspecialchars($_SERVER['PHP_SELF']);
+ } else
+ if (isset($_SERVER['PHP_SELF'])) $tracer .= ' '.htmlspecialchars($_SERVER['PHP_SELF']);
//$tracer .= (string) adodb_backtrace(false);
-
+
$tracer = (string) substr($tracer,0,500);
-
+
if (is_array($inputarr)) {
if (is_array(reset($inputarr))) $params = 'Array sizeof='.sizeof($inputarr);
else {
@@ -124,19 +135,20 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
} else {
$params = '';
}
-
+
if (is_array($sql)) $sql = $sql[0];
+ if ($prefix) $sql = $prefix.$sql;
$arr = array('b'=>strlen($sql).'.'.crc32($sql),
'c'=>substr($sql,0,3900), 'd'=>$params,'e'=>$tracer,'f'=>adodb_round($time,6));
//var_dump($arr);
$saved = $conn->debug;
$conn->debug = 0;
-
+
$d = $conn->sysTimeStamp;
if (empty($d)) $d = date("'Y-m-d H:i:s'");
if ($conn->dataProvider == 'oci8' && $dbT != 'oci8po') {
$isql = "insert into $perf_table values($d,:b,:c,:d,:e,:f)";
- } else if ($dbT == 'odbc_mssql' || $dbT == 'informix' || $dbT == 'odbtp') {
+ } else if ($dbT == 'mssqlnative' || $dbT == 'odbc_mssql' || $dbT == 'informix' || strncmp($dbT,'odbtp',4)==0) {
$timer = $arr['f'];
if ($dbT == 'informix') $sql2 = substr($sql2,0,230);
@@ -144,7 +156,7 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
$sql2 = $conn->qstr($arr['c']);
$params = $conn->qstr($arr['d']);
$tracer = $conn->qstr($arr['e']);
-
+
$isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values($d,$sql1,$sql2,$params,$tracer,$timer)";
if ($dbT == 'informix') $isql = str_replace(chr(10),' ',$isql);
$arr = false;
@@ -153,21 +165,32 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
$isql = "insert into $perf_table (created,sql0,sql1,params,tracer,timer) values( $d,?,?,?,?,?)";
}
- $ok = $conn->Execute($isql,$arr);
+ global $ADODB_PERF_MIN;
+ if ($errN != 0 || $time >= $ADODB_PERF_MIN) {
+ if($conn instanceof ADODB_mysqli && $conn->_queryID) {
+ mysqli_free_result($conn->_queryID);
+ }
+ $ok = $conn->Execute($isql,$arr);
+ if($conn instanceof ADODB_mysqli && $conn->_queryID){
+ mysqli_free_result($conn->_queryID);
+ }
+ } else
+ $ok = true;
+
$conn->debug = $saved;
-
+
if ($ok) {
- $conn->_logsql = true;
+ $conn->_logsql = true;
} else {
$err2 = $conn->ErrorMsg();
$conn->_logsql = true; // enable logsql error simulation
- $perf =& NewPerfMonitor($conn);
+ $perf = NewPerfMonitor($conn);
if ($perf) {
if ($perf->CreateLogTable()) $ok = $conn->Execute($isql,$arr);
} else {
$ok = $conn->Execute("create table $perf_table (
created varchar(50),
- sql0 varchar(250),
+ sql0 varchar(250),
sql1 varchar(4000),
params varchar(3000),
tracer varchar(500),
@@ -178,14 +201,14 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
$conn->_logsql = false;
}
}
- $conn->_errorMsg = $errM;
- $conn->_errorCode = $errN;
- }
- $conn->fnExecute = 'adodb_log_sql';
+ $connx->_errorMsg = $errM;
+ $connx->_errorCode = $errN;
+ }
+ $connx->fnExecute = 'adodb_log_sql';
return $rs;
}
-
+
/*
The settings data structure is an associative array that database parameter per element.
@@ -193,9 +216,9 @@ function& adodb_log_sql(&$conn,$sql,$inputarr)
0: category code, used to group related db parameters
1: either
- a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'",
+ a. sql string to retrieve value, eg. "select value from v\$parameter where name='db_block_size'",
b. array holding sql string and field to look for, e.g. array('show variables','table_cache'),
- c. a string prefixed by =, then a PHP method of the class is invoked,
+ c. a string prefixed by =, then a PHP method of the class is invoked,
e.g. to invoke $this->GetIndexValue(), set this array element to '=GetIndexValue',
2: description of the database parameter
*/
@@ -210,12 +233,12 @@ class adodb_perf {
var $cliFormat = "%32s => %s \r\n";
var $sql1 = 'sql1'; // used for casting sql1 to text for mssql
var $explain = true;
- var $helpurl = "LogSQL help ";
+ var $helpurl = 'LogSQL help ';
var $createTableSQL = false;
var $maxLength = 2000;
-
- // Sets the tablename to be used
- function table($newtable = false)
+
+ // Sets the tablename to be used
+ static function table($newtable = false)
{
static $_table;
@@ -242,32 +265,45 @@ function _CPULoad()
*/
// Algorithm is taken from
- // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/example__obtaining_raw_performance_data.asp
+ // http://social.technet.microsoft.com/Forums/en-US/winservergen/thread/414b0e1b-499c-411e-8a02-6a12e339c0f1/
if (strncmp(PHP_OS,'WIN',3)==0) {
- if (PHP_VERSION == '5.0.0') return false;
- if (PHP_VERSION == '5.0.1') return false;
- if (PHP_VERSION == '5.0.2') return false;
- if (PHP_VERSION == '5.0.3') return false;
- if (PHP_VERSION == '4.3.10') return false; # see http://bugs.php.net/bug.php?id=31737
-
- @$c = new COM("WinMgmts:{impersonationLevel=impersonate}!Win32_PerfRawData_PerfOS_Processor.Name='_Total'");
- if (!$c) return false;
-
- $info[0] = $c->PercentProcessorTime;
- $info[1] = 0;
- $info[2] = 0;
- $info[3] = $c->TimeStamp_Sys100NS;
- //print_r($info);
+ static $FAIL = false;
+ if ($FAIL) return false;
+
+ $objName = "winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\CIMV2";
+ $myQuery = "SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name = '_Total'";
+
+ try {
+ @$objWMIService = new COM($objName);
+ if (!$objWMIService) {
+ $FAIL = true;
+ return false;
+ }
+
+ $info[0] = -1;
+ $info[1] = 0;
+ $info[2] = 0;
+ $info[3] = 0;
+ foreach($objWMIService->ExecQuery($myQuery) as $objItem) {
+ $info[0] = $objItem->PercentProcessorTime();
+ }
+
+ } catch(Exception $e) {
+ $FAIL = true;
+ echo $e->getMessage();
+ return false;
+ }
+
return $info;
}
-
+
// Algorithm - Steve Blinch (BlitzAffe Online, http://www.blitzaffe.com)
$statfile = '/proc/stat';
if (!file_exists($statfile)) return false;
-
+
$fd = fopen($statfile,"r");
if (!$fd) return false;
-
+
$statinfo = explode("\n",fgets($fd, 1024));
fclose($fd);
foreach($statinfo as $line) {
@@ -278,11 +314,11 @@ function _CPULoad()
return $info;
}
}
-
+
return false;
-
+
}
-
+
/* NOT IMPLEMENTED */
function MemInfo()
{
@@ -310,8 +346,8 @@ function MemInfo()
Committed_AS: 348732 kB
*/
}
-
-
+
+
/*
Remember that this is client load, not db server load!
*/
@@ -320,48 +356,47 @@ function CPULoad()
{
$info = $this->_CPULoad();
if (!$info) return false;
-
- if (empty($this->_lastLoad)) {
- sleep(1);
- $this->_lastLoad = $info;
- $info = $this->_CPULoad();
- }
-
- $last = $this->_lastLoad;
- $this->_lastLoad = $info;
-
- $d_user = $info[0] - $last[0];
- $d_nice = $info[1] - $last[1];
- $d_system = $info[2] - $last[2];
- $d_idle = $info[3] - $last[3];
-
- //printf("Delta - User: %f Nice: %f System: %f Idle: %f ",$d_user,$d_nice,$d_system,$d_idle);
if (strncmp(PHP_OS,'WIN',3)==0) {
- if ($d_idle < 1) $d_idle = 1;
- return 100*(1-$d_user/$d_idle);
+ return (integer) $info[0];
}else {
+ if (empty($this->_lastLoad)) {
+ sleep(1);
+ $this->_lastLoad = $info;
+ $info = $this->_CPULoad();
+ }
+
+ $last = $this->_lastLoad;
+ $this->_lastLoad = $info;
+
+ $d_user = $info[0] - $last[0];
+ $d_nice = $info[1] - $last[1];
+ $d_system = $info[2] - $last[2];
+ $d_idle = $info[3] - $last[3];
+
+ //printf("Delta - User: %f Nice: %f System: %f Idle: %f ",$d_user,$d_nice,$d_system,$d_idle);
+
$total=$d_user+$d_nice+$d_system+$d_idle;
if ($total<1) $total=1;
- return 100*($d_user+$d_nice+$d_system)/$total;
+ return 100*($d_user+$d_nice+$d_system)/$total;
}
}
-
+
function Tracer($sql)
{
$perf_table = adodb_perf::table();
$saveE = $this->conn->fnExecute;
$this->conn->fnExecute = false;
-
+
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
-
+
$sqlq = $this->conn->qstr($sql);
$arr = $this->conn->GetArray(
-"select count(*),tracer
- from $perf_table where sql1=$sqlq
+"select count(*),tracer
+ from $perf_table where sql1=$sqlq
group by tracer
order by 1 desc");
$s = '';
@@ -371,66 +406,66 @@ function Tracer($sql)
$s .= sprintf("%4d",$k[0]).' '.strip_tags($k[1]).' ';
}
}
-
+
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_CACHE_MODE = $save;
$this->conn->fnExecute = $saveE;
return $s;
}
- /*
+ /*
Explain Plan for $sql.
- If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the
+ If only a snippet of the $sql is passed in, then $partial will hold the crc32 of the
actual sql.
*/
function Explain($sql,$partial=false)
- {
+ {
return false;
}
-
+
function InvalidSQL($numsql = 10)
{
-
+
if (isset($_GET['sql'])) return;
$s = 'Invalid SQL ';
$saveE = $this->conn->fnExecute;
$this->conn->fnExecute = false;
$perf_table = adodb_perf::table();
- $rs =& $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
+ $rs = $this->conn->SelectLimit("select distinct count(*),sql1,tracer as error_msg from $perf_table where tracer like 'ERROR:%' group by sql1,tracer order by 1 desc",$numsql);//,$numsql);
$this->conn->fnExecute = $saveE;
if ($rs) {
$s .= rs2html($rs,false,false,false,false);
} else
return "$this->helpurl. ".$this->conn->ErrorMsg()."
";
-
+
return $s;
}
-
+
/*
This script identifies the longest running SQL
- */
+ */
function _SuspiciousSQL($numsql = 10)
{
global $ADODB_FETCH_MODE;
-
+
$perf_table = adodb_perf::table();
$saveE = $this->conn->fnExecute;
$this->conn->fnExecute = false;
-
+
if (isset($_GET['exps']) && isset($_GET['sql'])) {
$partial = !empty($_GET['part']);
echo " ".$this->Explain($_GET['sql'],$partial)."\n";
}
-
+
if (isset($_GET['sql'])) return;
$sql1 = $this->sql1;
-
+
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
//$this->conn->debug=1;
- $rs =& $this->conn->SelectLimit(
+ $rs = $this->conn->SelectLimit(
"select avg(timer) as avg_timer,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
from $perf_table
where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
@@ -440,7 +475,7 @@ function _SuspiciousSQL($numsql = 10)
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
$this->conn->fnExecute = $saveE;
-
+
if (!$rs) return "$this->helpurl. ".$this->conn->ErrorMsg()."
";
$s = "Suspicious SQL
The following SQL have high average execution times
@@ -464,15 +499,15 @@ function _SuspiciousSQL($numsql = 10)
$rs->MoveNext();
}
return $s."";
-
+
}
-
+
function CheckMemory()
{
return '';
}
-
-
+
+
function SuspiciousSQL($numsql=10)
{
return adodb_perf::_SuspiciousSQL($numsql);
@@ -483,33 +518,33 @@ function ExpensiveSQL($numsql=10)
return adodb_perf::_ExpensiveSQL($numsql);
}
-
+
/*
- This reports the percentage of load on the instance due to the most
- expensive few SQL statements. Tuning these statements can often
- make huge improvements in overall system performance.
+ This reports the percentage of load on the instance due to the most
+ expensive few SQL statements. Tuning these statements can often
+ make huge improvements in overall system performance.
*/
function _ExpensiveSQL($numsql = 10)
{
global $ADODB_FETCH_MODE;
-
+
$perf_table = adodb_perf::table();
$saveE = $this->conn->fnExecute;
$this->conn->fnExecute = false;
-
+
if (isset($_GET['expe']) && isset($_GET['sql'])) {
$partial = !empty($_GET['part']);
echo " ".$this->Explain($_GET['sql'],$partial)."\n";
}
-
+
if (isset($_GET['sql'])) return;
-
+
$sql1 = $this->sql1;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
-
- $rs =& $this->conn->SelectLimit(
+
+ $rs = $this->conn->SelectLimit(
"select sum(timer) as total,$sql1,count(*),max(timer) as max_timer,min(timer) as min_timer
from $perf_table
where {$this->conn->upperCase}({$this->conn->substr}(sql0,1,5)) not in ('DROP ','INSER','COMMI','CREAT')
@@ -544,7 +579,7 @@ function _ExpensiveSQL($numsql = 10)
}
return $s."";
}
-
+
/*
Raw function to return parameter value from $settings.
*/
@@ -554,11 +589,11 @@ function DBParameter($param)
$sql = $this->settings[$param][1];
return $this->_DBParameter($sql);
}
-
+
/*
- Raw function returning array of poll paramters
+ Raw function returning array of poll parameters
*/
- function &PollParameters()
+ function PollParameters()
{
$arr[0] = (float)$this->DBParameter('data cache hit ratio');
$arr[1] = (float)$this->DBParameter('data reads');
@@ -566,7 +601,7 @@ function &PollParameters()
$arr[3] = (integer) $this->DBParameter('current connections');
return $arr;
}
-
+
/*
Low-level Get Database Parameter
*/
@@ -575,7 +610,7 @@ function _DBParameter($sql)
$savelog = $this->conn->LogSQL(false);
if (is_array($sql)) {
global $ADODB_FETCH_MODE;
-
+
$sql1 = $sql[0];
$key = $sql[1];
if (sizeof($sql)>2) $pos = $sql[2];
@@ -586,9 +621,9 @@ function _DBParameter($sql)
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
-
+
$rs = $this->conn->Execute($sql1);
-
+
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if ($rs) {
@@ -613,99 +648,104 @@ function _DBParameter($sql)
$sql = str_replace('$DATABASE',$this->conn->database,$sql);
$ret = $this->conn->GetOne($sql);
$this->conn->LogSQL($savelog);
-
+
return $ret;
}
}
-
+
/*
Warn if cache ratio falls below threshold. Displayed in "Description" column.
*/
function WarnCacheRatio($val)
{
- if ($val < $this->warnRatio)
+ if ($val < $this->warnRatio)
return 'Cache ratio should be at least '.$this->warnRatio.'% ';
else return '';
}
-
+
+ function clearsql()
+ {
+ $perf_table = adodb_perf::table();
+ $this->conn->Execute("delete from $perf_table where created<".$this->conn->sysTimeStamp);
+ }
/***********************************************************************************************/
// HIGH LEVEL UI FUNCTIONS
/***********************************************************************************************/
-
+
function UI($pollsecs=5)
{
-
+ global $ADODB_LOG_CONN;
+
$perf_table = adodb_perf::table();
$conn = $this->conn;
-
+
$app = $conn->host;
if ($conn->host && $conn->database) $app .= ', db=';
$app .= $conn->database;
-
+
if ($app) $app .= ', ';
- $savelog = $this->conn->LogSQL(false);
+ $savelog = $this->conn->LogSQL(false);
$info = $conn->ServerInfo();
if (isset($_GET['clearsql'])) {
- $this->conn->Execute("delete from $perf_table");
+ $this->clearsql();
}
$this->conn->LogSQL($savelog);
-
- // magic quotes
-
- if (isset($_GET['sql']) && get_magic_quotes_gpc()) {
- $_GET['sql'] = $_GET['sql'] = str_replace(array("\\'",'\"'),array("'",'"'),$_GET['sql']);
- }
-
+
if (!isset($_SESSION['ADODB_PERF_SQL'])) $nsql = $_SESSION['ADODB_PERF_SQL'] = 10;
else $nsql = $_SESSION['ADODB_PERF_SQL'];
-
+
$app .= $info['description'];
-
-
+
+
if (isset($_GET['do'])) $do = $_GET['do'];
else if (isset($_POST['do'])) $do = $_POST['do'];
else if (isset($_GET['sql'])) $do = 'viewsql';
else $do = 'stats';
-
+
if (isset($_GET['nsql'])) {
if ($_GET['nsql'] > 0) $nsql = $_SESSION['ADODB_PERF_SQL'] = (integer) $_GET['nsql'];
}
echo "ADOdb Performance Monitor on $app ";
if ($do == 'viewsql') $form = " ";
else $form = " ";
-
+
$allowsql = !defined('ADODB_PERF_NO_RUN_SQL');
-
+ global $ADODB_PERF_MIN;
+ $app .= " (Min sql timing \$ADODB_PERF_MIN=$ADODB_PERF_MIN secs)";
+
if (empty($_GET['hidem']))
echo "";
-
+
switch ($do) {
default:
case 'stats':
+ if (empty($ADODB_LOG_CONN))
+ echo " Clear SQL Log ";
echo $this->HealthCheck();
//$this->conn->debug=1;
echo $this->CheckMemory();
break;
case 'poll':
- echo "";
+ $self = htmlspecialchars($_SERVER['PHP_SELF']);
+ echo "";
break;
case 'poll2':
echo "
";
$this->Poll($pollsecs);
break;
-
+
case 'dosql':
if (!$allowsql) break;
-
+
$this->DoSQLForm();
break;
case 'viewsql':
@@ -715,13 +755,12 @@ function UI($pollsecs=5)
echo($this->ExpensiveSQL($nsql));
echo($this->InvalidSQL($nsql));
break;
- case 'tables':
+ case 'tables':
echo $this->Tables(); break;
}
global $ADODB_vers;
- echo "
";
}
-
+
/*
Runs in infinite loop, returning real-time statistics
*/
@@ -731,19 +770,19 @@ function Poll($secs=5)
//$this->conn->debug=1;
if ($secs <= 1) $secs = 1;
echo "Accumulating statistics, every $secs seconds...\n";flush();
- $arro =& $this->PollParameters();
+ $arro = $this->PollParameters();
$cnt = 0;
set_time_limit(0);
sleep($secs);
while (1) {
- $arr =& $this->PollParameters();
-
+ $arr = $this->PollParameters();
+
$hits = sprintf('%2.2f',$arr[0]);
$reads = sprintf('%12.4f',($arr[1]-$arro[1])/$secs);
$writes = sprintf('%12.4f',($arr[2]-$arro[2])/$secs);
$sess = sprintf('%5d',$arr[3]);
-
+
$load = $this->CPULoad();
if ($load !== false) {
$oslabel = 'WS-CPU%';
@@ -752,18 +791,18 @@ function Poll($secs=5)
$oslabel = '';
$osval = '';
}
- if ($cnt % 10 == 0) echo " Time ".$oslabel." Hit% Sess Reads/s Writes/s\n";
+ if ($cnt % 10 == 0) echo " Time ".$oslabel." Hit% Sess Reads/s Writes/s\n";
$cnt += 1;
echo date('H:i:s').' '.$osval."$hits $sess $reads $writes\n";
flush();
-
+
if (connection_aborted()) return;
-
+
sleep($secs);
$arro = $arr;
}
}
-
+
/*
Returns basic health check in a command line interface
*/
@@ -771,48 +810,48 @@ function HealthCheckCLI()
{
return $this->HealthCheck(true);
}
-
-
+
+
/*
Returns basic health check as HTML
*/
function HealthCheck($cli=false)
{
$saveE = $this->conn->fnExecute;
- $this->conn->fnExecute = false;
+ $this->conn->fnExecute = false;
if ($cli) $html = '';
else $html = $this->table.''.$this->conn->databaseType.' '.$this->titles;
-
+
$oldc = false;
$bgc = '';
foreach($this->settings as $name => $arr) {
if ($arr === false) break;
-
+
if (!is_string($name)) {
if ($cli) $html .= " -- $arr -- \n";
else $html .= "color>$arr ";
continue;
}
-
+
if (!is_array($arr)) break;
$category = $arr[0];
$how = $arr[1];
if (sizeof($arr)>2) $desc = $arr[2];
else $desc = ' ';
-
-
+
+
if ($category == 'HIDE') continue;
-
+
$val = $this->_DBParameter($how);
-
+
if ($desc && strncmp($desc,"=",1) === 0) {
$fn = substr($desc,1);
$desc = $this->$fn($val);
}
-
+
if ($val === false) {
$m = $this->conn->ErrorMsg();
- $val = "Error: $m";
+ $val = "Error: $m";
} else {
if (is_numeric($val) && $val >= 256*1024) {
if ($val % (1024*1024) == 0) {
@@ -833,34 +872,34 @@ function HealthCheck($cli=false)
if (strlen($val)==0) $val = ' ';
if ($cli) {
$html .= str_replace(' ','',sprintf($this->cliFormat,strip_tags($name),strip_tags($val),strip_tags($desc)));
-
+
}else {
$html .= "".$name.' '.$val.' '.$desc." \n";
}
}
-
+
if (!$cli) $html .= "\n";
$this->conn->fnExecute = $saveE;
-
- return $html;
+
+ return $html;
}
-
+
function Tables($orderby='1')
{
if (!$this->tablesSQL) return false;
-
+
$savelog = $this->conn->LogSQL(false);
$rs = $this->conn->Execute($this->tablesSQL.' order by '.$orderby);
$this->conn->LogSQL($savelog);
$html = rs2html($rs,false,false,false,false);
return $html;
}
-
+
function CreateLogTable()
{
if (!$this->createTableSQL) return false;
-
+
$table = $this->table();
$sql = str_replace('adodb_logsql',$table,$this->createTableSQL);
$savelog = $this->conn->LogSQL(false);
@@ -868,17 +907,17 @@ function CreateLogTable()
$this->conn->LogSQL($savelog);
return ($ok) ? true : false;
}
-
+
function DoSQLForm()
{
-
-
- $PHP_SELF = $_SERVER['PHP_SELF'];
+
+
+ $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']);
$sql = isset($_REQUEST['sql']) ? $_REQUEST['sql'] : '';
if (isset($_SESSION['phplens_sqlrows'])) $rows = $_SESSION['phplens_sqlrows'];
else $rows = 3;
-
+
if (isset($_REQUEST['SMALLER'])) {
$rows /= 2;
if ($rows < 3) $rows = 3;
@@ -888,7 +927,7 @@ function DoSQLForm()
$rows *= 2;
$_SESSION['phplens_sqlrows'] = $rows;
}
-
+
?>
',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not committed
+ // properly unless select statement executed in Win2000
+
+ if ($ADODB_SESS_CONN->databaseType == 'access') $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return isset($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+
+function adodb_sess_gc($maxlifetime) {
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY,$ADODB_SESS_DEBUG;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ //$del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();
+ $ADODB_SESS_CONN->Execute($qry);
+ }
+
+ // suggested by Cameron, "GaM3R"
+ if (defined('ADODB_SESSION_OPTIMIZE'))
+ {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ }
+
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs = $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg");
+ }
+ }
+
+ return true;
+}
+
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+/*
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}";
+}
+*/
diff --git a/adodb/session/old/adodb-session-clob.php b/adodb/session/old/adodb-session-clob.php
new file mode 100644
index 0000000..864fdfd
--- /dev/null
+++ b/adodb/session/old/adodb-session-clob.php
@@ -0,0 +1,457 @@
+";
+
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ adodb_session_open(false,false,false);
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}";
+
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA CLOB,
+ primary key (sesskey)
+ );
+
+
+ 2. Then define the following parameters in this file:
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+ $ADODB_SESSION_USE_LOBS = false; (or, if you wanna use CLOBS (= 'CLOB') or ( = 'BLOB')
+
+ 3. Recommended is PHP 4.1.0 or later. There are documented
+ session bugs in earlier versions of PHP.
+
+ 4. If you want to receive notifications when a session expires, then
+ you can tag a session with an EXPIREREF, and before the session
+ record is deleted, we can call a function that will pass the EXPIREREF
+ as the first parameter, and the session key as the second parameter.
+
+ To do this, define a notification function, say NotifyFn:
+
+ function NotifyFn($expireref, $sesskey)
+ {
+ }
+
+ Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+ This is an array with 2 elements, the first being the name of the variable
+ you would like to store in the EXPIREREF field, and the 2nd is the
+ notification function's name.
+
+ In this example, we want to be notified when a user's session
+ has expired, so we store the user id in the global variable $USERID,
+ store this value in the EXPIREREF field:
+
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+
+ Then when the NotifyFn is called, we are passed the $USERID as the first
+ parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60);
+
+/****************************************************************************************\
+ Global definitions
+\****************************************************************************************/
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_USE_LOBS,
+ $ADODB_SESSION_TBL;
+
+ if (!isset($ADODB_SESSION_USE_LOBS)) $ADODB_SESSION_USE_LOBS = 'CLOB';
+
+ $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+ if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "Session Error: PHP.INI setting session.gc_maxlifetime not set: $ADODB_SESS_LIFE ";
+ $ADODB_SESS_LIFE=1440;
+ }
+ $ADODB_SESSION_CRC = false;
+ //$ADODB_SESS_DEBUG = true;
+
+ //////////////////////////////////
+ /* SET THE FOLLOWING PARAMETERS */
+ //////////////////////////////////
+
+ if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+ }
+
+ if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+ $ADODB_SESSION_EXPIRE_NOTIFY = false;
+ }
+ // Made table name configurable - by David Johnson djohnson@inpro.net
+ if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+ }
+
+
+ // defaulting $ADODB_SESSION_USE_LOBS
+ if (!isset($ADODB_SESSION_USE_LOBS) || empty($ADODB_SESSION_USE_LOBS)) {
+ $ADODB_SESSION_USE_LOBS = false;
+ }
+
+ /*
+ $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+ $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+ $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+ $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+ $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+ $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+ $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+ */
+
+/****************************************************************************************\
+ Create the connection to the database.
+
+ If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true)
+{
+GLOBAL $ADODB_SESS_CONN;
+ if (isset($ADODB_SESS_CONN)) return true;
+
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_DEBUG;
+
+ // cannot use & below - do not know why...
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+ }
+ if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+ else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+ if (!$ok) ADOConnection::outp( "
+-- Session: connection failed",false);
+}
+
+/****************************************************************************************\
+ Close the connection
+\****************************************************************************************/
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+/****************************************************************************************\
+ Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key)
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else
+ $v = rawurldecode(reset($rs->fields));
+
+ $rs->Close();
+
+ // new optimization adodb 2.1
+ $ADODB_SESSION_CRC = strlen($v).crc32($v);
+
+ return $v;
+ }
+
+ return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+ Write the serialized data to a database.
+
+ If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val)
+{
+ global
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESSION_TBL,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_DRIVER, // added
+ $ADODB_SESSION_USE_LOBS; // added
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+ if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed";
+ $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ return true;
+ }
+ $val = rawurlencode($val);
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+
+
+ if ($ADODB_SESSION_USE_LOBS === false) { // no lobs, simply use replace()
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr, 'sesskey',$autoQuote = true);
+ if (!$rs) {
+ $err = $ADODB_SESS_CONN->ErrorMsg();
+ }
+ } else {
+ // what value shall we insert/update for lob row?
+ switch ($ADODB_SESSION_DRIVER) {
+ // empty_clob or empty_lob for oracle dbs
+ case "oracle":
+ case "oci8":
+ case "oci8po":
+ case "oci805":
+ $lob_value = sprintf("empty_%s()", strtolower($ADODB_SESSION_USE_LOBS));
+ break;
+
+ // null for all other
+ default:
+ $lob_value = "null";
+ break;
+ }
+
+ // do we insert or update? => as for sesskey
+ $res = $ADODB_SESS_CONN->Execute("select count(*) as cnt from $ADODB_SESSION_TBL where sesskey = '$key'");
+ if ($res && reset($res->fields) > 0) {
+ $qry = sprintf("update %s set expiry = %d, data = %s where sesskey = '%s'", $ADODB_SESSION_TBL, $expiry, $lob_value, $key);
+ } else {
+ // insert
+ $qry = sprintf("insert into %s (sesskey, expiry, data) values ('%s', %d, %s)", $ADODB_SESSION_TBL, $key, $expiry, $lob_value);
+ }
+
+ $err = "";
+ $rs1 = $ADODB_SESS_CONN->Execute($qry);
+ if (!$rs1) {
+ $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+ }
+ $rs2 = $ADODB_SESS_CONN->UpdateBlob($ADODB_SESSION_TBL, 'data', $val, "sesskey='$key'", strtoupper($ADODB_SESSION_USE_LOBS));
+ if (!$rs2) {
+ $err .= $ADODB_SESS_CONN->ErrorMsg()."\n";
+ }
+ $rs = ($rs1 && $rs2) ? true : false;
+ }
+
+ if (!$rs) {
+ ADOConnection::outp( '
+-- Session Replace: '.nl2br($err).'',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not committed
+ // properly unless select statement executed in Win2000
+ if ($ADODB_SESS_CONN->databaseType == 'access')
+ $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return !empty($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime)
+{
+ global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ //$ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->CommitTrans();
+
+ }
+ } else {
+ $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time());
+
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- Garbage Collection : $qry");
+ }
+ // suggested by Cameron, "GaM3R"
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ if (!empty($opt_qry)) {
+ $ADODB_SESS_CONN->Execute($opt_qry);
+ }
+ }
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs = $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg");
+ }
+ }
+
+ return true;
+}
+
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}",false);
+}
diff --git a/adodb/session/old/adodb-session.php b/adodb/session/old/adodb-session.php
new file mode 100644
index 0000000..5fd43ab
--- /dev/null
+++ b/adodb/session/old/adodb-session.php
@@ -0,0 +1,449 @@
+";
+
+To force non-persistent connections, call adodb_session_open first before session_start():
+
+ include('adodb.inc.php');
+ include('adodb-session.php');
+ adodb_sess_open(false,false,false);
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ print "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}";
+
+
+ Installation
+ ============
+ 1. Create this table in your database (syntax might vary depending on your db):
+
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY int(11) unsigned not null,
+ EXPIREREF varchar(64),
+ DATA text not null,
+ primary key (sesskey)
+ );
+
+ For oracle:
+ create table sessions (
+ SESSKEY char(32) not null,
+ EXPIRY DECIMAL(16) not null,
+ EXPIREREF varchar(64),
+ DATA varchar(4000) not null,
+ primary key (sesskey)
+ );
+
+
+ 2. Then define the following parameters. You can either modify
+ this file, or define them before this file is included:
+
+ $ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
+ $ADODB_SESSION_CONNECT='server to connect to';
+ $ADODB_SESSION_USER ='user';
+ $ADODB_SESSION_PWD ='password';
+ $ADODB_SESSION_DB ='database';
+ $ADODB_SESSION_TBL = 'sessions'
+
+ 3. Recommended is PHP 4.1.0 or later. There are documented
+ session bugs in earlier versions of PHP.
+
+ 4. If you want to receive notifications when a session expires, then
+ you can tag a session with an EXPIREREF, and before the session
+ record is deleted, we can call a function that will pass the EXPIREREF
+ as the first parameter, and the session key as the second parameter.
+
+ To do this, define a notification function, say NotifyFn:
+
+ function NotifyFn($expireref, $sesskey)
+ {
+ }
+
+ Then you need to define a global variable $ADODB_SESSION_EXPIRE_NOTIFY.
+ This is an array with 2 elements, the first being the name of the variable
+ you would like to store in the EXPIREREF field, and the 2nd is the
+ notification function's name.
+
+ In this example, we want to be notified when a user's session
+ has expired, so we store the user id in the global variable $USERID,
+ store this value in the EXPIREREF field:
+
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USERID','NotifyFn');
+
+ Then when the NotifyFn is called, we are passed the $USERID as the first
+ parameter, eg. NotifyFn($userid, $sesskey).
+*/
+
+if (!defined('_ADODB_LAYER')) {
+ include (dirname(__FILE__).'/adodb.inc.php');
+}
+
+if (!defined('ADODB_SESSION')) {
+
+ define('ADODB_SESSION',1);
+
+ /* if database time and system time is difference is greater than this, then give warning */
+ define('ADODB_SESSION_SYNCH_SECS',60);
+
+ /*
+ Thanks Joe Li. See PHPLens Issue No: 11487&x=1
+*/
+function adodb_session_regenerate_id()
+{
+ $conn = ADODB_Session::_conn();
+ if (!$conn) return false;
+
+ $old_id = session_id();
+ if (function_exists('session_regenerate_id')) {
+ session_regenerate_id();
+ } else {
+ session_id(md5(uniqid(rand(), true)));
+ $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ //@session_start();
+ }
+ $new_id = session_id();
+ $ok = $conn->Execute('UPDATE '. ADODB_Session::table(). ' SET sesskey='. $conn->qstr($new_id). ' WHERE sesskey='.$conn->qstr($old_id));
+
+ /* it is possible that the update statement fails due to a collision */
+ if (!$ok) {
+ session_id($old_id);
+ if (empty($ck)) $ck = session_get_cookie_params();
+ setcookie(session_name(), session_id(), false, $ck['path'], $ck['domain'], $ck['secure']);
+ return false;
+ }
+
+ return true;
+}
+
+/****************************************************************************************\
+ Global definitions
+\****************************************************************************************/
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_EXPIRE_NOTIFY,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_TBL;
+
+
+ $ADODB_SESS_LIFE = ini_get('session.gc_maxlifetime');
+ if ($ADODB_SESS_LIFE <= 1) {
+ // bug in PHP 4.0.3 pl 1 -- how about other versions?
+ //print "Session Error: PHP.INI setting session.gc_maxlifetime not set: $ADODB_SESS_LIFE ";
+ $ADODB_SESS_LIFE=1440;
+ }
+ $ADODB_SESSION_CRC = false;
+ //$ADODB_SESS_DEBUG = true;
+
+ //////////////////////////////////
+ /* SET THE FOLLOWING PARAMETERS */
+ //////////////////////////////////
+
+ if (empty($ADODB_SESSION_DRIVER)) {
+ $ADODB_SESSION_DRIVER='mysql';
+ $ADODB_SESSION_CONNECT='localhost';
+ $ADODB_SESSION_USER ='root';
+ $ADODB_SESSION_PWD ='';
+ $ADODB_SESSION_DB ='xphplens_2';
+ }
+
+ if (empty($ADODB_SESSION_EXPIRE_NOTIFY)) {
+ $ADODB_SESSION_EXPIRE_NOTIFY = false;
+ }
+ // Made table name configurable - by David Johnson djohnson@inpro.net
+ if (empty($ADODB_SESSION_TBL)){
+ $ADODB_SESSION_TBL = 'sessions';
+ }
+
+ /*
+ $ADODB_SESS['driver'] = $ADODB_SESSION_DRIVER;
+ $ADODB_SESS['connect'] = $ADODB_SESSION_CONNECT;
+ $ADODB_SESS['user'] = $ADODB_SESSION_USER;
+ $ADODB_SESS['pwd'] = $ADODB_SESSION_PWD;
+ $ADODB_SESS['db'] = $ADODB_SESSION_DB;
+ $ADODB_SESS['life'] = $ADODB_SESS_LIFE;
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+
+ $ADODB_SESS['debug'] = $ADODB_SESS_DEBUG;
+ $ADODB_SESS['table'] = $ADODB_SESS_TBL;
+ */
+
+/****************************************************************************************\
+ Create the connection to the database.
+
+ If $ADODB_SESS_CONN already exists, reuse that connection
+\****************************************************************************************/
+function adodb_sess_open($save_path, $session_name,$persist=true)
+{
+GLOBAL $ADODB_SESS_CONN;
+ if (isset($ADODB_SESS_CONN)) return true;
+
+GLOBAL $ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_DRIVER,
+ $ADODB_SESSION_USER,
+ $ADODB_SESSION_PWD,
+ $ADODB_SESSION_DB,
+ $ADODB_SESS_DEBUG;
+
+ // cannot use & below - do not know why...
+ $ADODB_SESS_CONN = ADONewConnection($ADODB_SESSION_DRIVER);
+ if (!empty($ADODB_SESS_DEBUG)) {
+ $ADODB_SESS_CONN->debug = true;
+ ADOConnection::outp( " conn=$ADODB_SESSION_CONNECT user=$ADODB_SESSION_USER pwd=$ADODB_SESSION_PWD db=$ADODB_SESSION_DB ");
+ }
+ if ($persist) $ok = $ADODB_SESS_CONN->PConnect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+ else $ok = $ADODB_SESS_CONN->Connect($ADODB_SESSION_CONNECT,
+ $ADODB_SESSION_USER,$ADODB_SESSION_PWD,$ADODB_SESSION_DB);
+
+ if (!$ok) ADOConnection::outp( "
+-- Session: connection failed",false);
+}
+
+/****************************************************************************************\
+ Close the connection
+\****************************************************************************************/
+function adodb_sess_close()
+{
+global $ADODB_SESS_CONN;
+
+ if ($ADODB_SESS_CONN) $ADODB_SESS_CONN->Close();
+ return true;
+}
+
+/****************************************************************************************\
+ Slurp in the session variables and return the serialized string
+\****************************************************************************************/
+function adodb_sess_read($key)
+{
+global $ADODB_SESS_CONN,$ADODB_SESSION_TBL,$ADODB_SESSION_CRC;
+
+ $rs = $ADODB_SESS_CONN->Execute("SELECT data FROM $ADODB_SESSION_TBL WHERE sesskey = '$key' AND expiry >= " . time());
+ if ($rs) {
+ if ($rs->EOF) {
+ $v = '';
+ } else
+ $v = rawurldecode(reset($rs->fields));
+
+ $rs->Close();
+
+ // new optimization adodb 2.1
+ $ADODB_SESSION_CRC = strlen($v).crc32($v);
+
+ return $v;
+ }
+
+ return ''; // thx to Jorma Tuomainen, webmaster#wizactive.com
+}
+
+/****************************************************************************************\
+ Write the serialized data to a database.
+
+ If the data has not been modified since adodb_sess_read(), we do not write.
+\****************************************************************************************/
+function adodb_sess_write($key, $val)
+{
+ global
+ $ADODB_SESS_CONN,
+ $ADODB_SESS_LIFE,
+ $ADODB_SESSION_TBL,
+ $ADODB_SESS_DEBUG,
+ $ADODB_SESSION_CRC,
+ $ADODB_SESSION_EXPIRE_NOTIFY;
+
+ $expiry = time() + $ADODB_SESS_LIFE;
+
+ // crc32 optimization since adodb 2.1
+ // now we only update expiry date, thx to sebastian thom in adodb 2.32
+ if ($ADODB_SESSION_CRC !== false && $ADODB_SESSION_CRC == strlen($val).crc32($val)) {
+ if ($ADODB_SESS_DEBUG) echo "
+-- Session: Only updating date - crc32 not changed";
+ $qry = "UPDATE $ADODB_SESSION_TBL SET expiry=$expiry WHERE sesskey='$key' AND expiry >= " . time();
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ return true;
+ }
+ $val = rawurlencode($val);
+
+ $arr = array('sesskey' => $key, 'expiry' => $expiry, 'data' => $val);
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ $var = reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ global $$var;
+ $arr['expireref'] = $$var;
+ }
+ $rs = $ADODB_SESS_CONN->Replace($ADODB_SESSION_TBL,$arr,
+ 'sesskey',$autoQuote = true);
+
+ if (!$rs) {
+ ADOConnection::outp( '
+-- Session Replace: '.$ADODB_SESS_CONN->ErrorMsg().'',false);
+ } else {
+ // bug in access driver (could be odbc?) means that info is not committed
+ // properly unless select statement executed in Win2000
+ if ($ADODB_SESS_CONN->databaseType == 'access')
+ $rs = $ADODB_SESS_CONN->Execute("select sesskey from $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ }
+ return !empty($rs);
+}
+
+function adodb_sess_destroy($key)
+{
+ global $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $ADODB_SESS_CONN->CommitTrans();
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE sesskey = '$key'";
+ $rs = $ADODB_SESS_CONN->Execute($qry);
+ }
+ return $rs ? true : false;
+}
+
+function adodb_sess_gc($maxlifetime)
+{
+ global $ADODB_SESS_DEBUG, $ADODB_SESS_CONN, $ADODB_SESSION_TBL,$ADODB_SESSION_EXPIRE_NOTIFY;
+
+ if ($ADODB_SESSION_EXPIRE_NOTIFY) {
+ reset($ADODB_SESSION_EXPIRE_NOTIFY);
+ $fn = next($ADODB_SESSION_EXPIRE_NOTIFY);
+ $savem = $ADODB_SESS_CONN->SetFetchMode(ADODB_FETCH_NUM);
+ $t = time();
+ $rs = $ADODB_SESS_CONN->Execute("SELECT expireref,sesskey FROM $ADODB_SESSION_TBL WHERE expiry < $t");
+ $ADODB_SESS_CONN->SetFetchMode($savem);
+ if ($rs) {
+ $ADODB_SESS_CONN->BeginTrans();
+ while (!$rs->EOF) {
+ $ref = $rs->fields[0];
+ $key = $rs->fields[1];
+ $fn($ref,$key);
+ $del = $ADODB_SESS_CONN->Execute("DELETE FROM $ADODB_SESSION_TBL WHERE sesskey='$key'");
+ $rs->MoveNext();
+ }
+ $rs->Close();
+
+ $ADODB_SESS_CONN->CommitTrans();
+
+ }
+ } else {
+ $qry = "DELETE FROM $ADODB_SESSION_TBL WHERE expiry < " . time();
+ $ADODB_SESS_CONN->Execute($qry);
+
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- Garbage Collection : $qry");
+ }
+ // suggested by Cameron, "GaM3R"
+ if (defined('ADODB_SESSION_OPTIMIZE')) {
+ global $ADODB_SESSION_DRIVER;
+
+ switch( $ADODB_SESSION_DRIVER ) {
+ case 'mysql':
+ case 'mysqlt':
+ $opt_qry = 'OPTIMIZE TABLE '.$ADODB_SESSION_TBL;
+ break;
+ case 'postgresql':
+ case 'postgresql7':
+ $opt_qry = 'VACUUM '.$ADODB_SESSION_TBL;
+ break;
+ }
+ if (!empty($opt_qry)) {
+ $ADODB_SESS_CONN->Execute($opt_qry);
+ }
+ }
+ if ($ADODB_SESS_CONN->dataProvider === 'oci8') $sql = 'select TO_CHAR('.($ADODB_SESS_CONN->sysTimeStamp).', \'RRRR-MM-DD HH24:MI:SS\') from '. $ADODB_SESSION_TBL;
+ else $sql = 'select '.$ADODB_SESS_CONN->sysTimeStamp.' from '. $ADODB_SESSION_TBL;
+
+ $rs = $ADODB_SESS_CONN->SelectLimit($sql,1);
+ if ($rs && !$rs->EOF) {
+
+ $dbts = reset($rs->fields);
+ $rs->Close();
+ $dbt = $ADODB_SESS_CONN->UnixTimeStamp($dbts);
+ $t = time();
+
+ if (abs($dbt - $t) >= ADODB_SESSION_SYNCH_SECS) {
+
+ $msg =
+ __FILE__.": Server time for webserver {$_SERVER['HTTP_HOST']} not in synch with database: database=$dbt ($dbts), webserver=$t (diff=".(abs($dbt-$t)/3600)." hrs)";
+ error_log($msg);
+ if ($ADODB_SESS_DEBUG) ADOConnection::outp("
+-- $msg");
+ }
+ }
+
+ return true;
+}
+
+session_set_save_handler(
+ "adodb_sess_open",
+ "adodb_sess_close",
+ "adodb_sess_read",
+ "adodb_sess_write",
+ "adodb_sess_destroy",
+ "adodb_sess_gc");
+}
+
+/* TEST SCRIPT -- UNCOMMENT */
+
+if (0) {
+
+ session_start();
+ session_register('AVAR');
+ $_SESSION['AVAR'] += 1;
+ ADOConnection::outp( "
+-- \$_SESSION['AVAR']={$_SESSION['AVAR']}",false);
+}
diff --git a/adodb/session/old/crypt.inc.php b/adodb/session/old/crypt.inc.php
new file mode 100644
index 0000000..089e24a
--- /dev/null
+++ b/adodb/session/old/crypt.inc.php
@@ -0,0 +1,83 @@
+
+ */
+
+class MD5Crypt{
+ function keyED($txt,$encrypt_key)
+ {
+ $encrypt_key = md5($encrypt_key);
+ $ctr=0;
+ $tmp = "";
+ for ($i=0;$ikeyED($tmp,$key));
+ }
+
+ function Decrypt($txt,$key)
+ {
+ $txt = $this->keyED(base64_decode($txt),$key);
+ $tmp = "";
+ for ($i=0;$i= 58 && $randnumber <= 64) || ($randnumber >= 91 && $randnumber <= 96))
+ {
+ $randnumber = rand(48,120);
+ }
+
+ $randomPassword .= chr($randnumber);
+ }
+ return $randomPassword;
+ }
+
+}
diff --git a/adodb/session/session_schema.xml b/adodb/session/session_schema.xml
index 3c61ff6..c1f7531 100644
--- a/adodb/session/session_schema.xml
+++ b/adodb/session/session_schema.xml
@@ -1,14 +1,14 @@
- table for ADOdb session-management
+ table for ADOdb session-management
session key
-
+
diff --git a/adodb/session/session_schema2.xml b/adodb/session/session_schema2.xml
index c2804ed..89cb4f2 100644
--- a/adodb/session/session_schema2.xml
+++ b/adodb/session/session_schema2.xml
@@ -1,26 +1,26 @@
- table for ADOdb session-management
+ table for ADOdb session-management
session key
-
-
+
+
-
+
-
+
@@ -30,7 +30,7 @@
-
+
diff --git a/adodb/tests/LibTest.php b/adodb/tests/LibTest.php
new file mode 100644
index 0000000..2f02e00
--- /dev/null
+++ b/adodb/tests/LibTest.php
@@ -0,0 +1,72 @@
+db = ADONewConnection('mysqli');
+ }
+
+ /**
+ * Test for {@see _adodb_quote_fieldname()}
+ *
+ * @dataProvider quoteProvider
+ */
+ public function testQuoteFieldNames($method, $field, $expected)
+ {
+ global $ADODB_QUOTE_FIELDNAMES;
+ $ADODB_QUOTE_FIELDNAMES = $method;
+ $this->assertSame($expected, _adodb_quote_fieldname($this->db, $field));
+ }
+
+ /**
+ * Data provider for {@see testQuoteFieldNames()}
+ * @return array
+ */
+ public function quoteProvider()
+ {
+ return [
+ 'No quoting, single-word field name' => [false, 'Field', 'FIELD'],
+ 'No quoting, field name with space' => [false, 'Field Name', '`FIELD NAME`'],
+ 'Quoting `true`' => [true, 'Field', '`FIELD`'],
+ 'Quoting `UPPER`' => ['UPPER', 'Field', '`FIELD`'],
+ 'Quoting `LOWER`' => ['LOWER', 'Field', '`field`'],
+ 'Quoting `NATIVE`' => ['NATIVE', 'Field', '`Field`'],
+ 'Quoting `BRACKETS`' => ['BRACKETS', 'Field', '[FIELD]'],
+ 'Unknown value defaults to UPPER' => ['XXX', 'Field', '`FIELD`'],
+ ];
+ }
+
+}
diff --git a/adodb/tests/benchmark.php b/adodb/tests/benchmark.php
new file mode 100644
index 0000000..5799031
--- /dev/null
+++ b/adodb/tests/benchmark.php
@@ -0,0 +1,95 @@
+
+
+ ADODB Benchmarks
+
+
+
+ADODB Version: $ADODB_version Host: $db->host Database: $db->database ";
+
+ // perform query once to cache results so we are only testing throughput
+ $rs = $db->Execute($sql);
+ if (!$rs){
+ print "Error in recordset";
+ return;
+ }
+ $arr = $rs->GetArray();
+ //$db->debug = true;
+ global $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = false;
+ $start = microtime();
+ for ($i=0; $i < $max; $i++) {
+ $rs = $db->Execute($sql);
+ $arr = $rs->GetArray();
+ // print $arr[0][1];
+ }
+ $end = microtime();
+ $start = explode(' ',$start);
+ $end = explode(' ',$end);
+
+ //print_r($start);
+ //print_r($end);
+
+ // print_r($arr);
+ $total = $end[0]+trim($end[1]) - $start[0]-trim($start[1]);
+ printf ("
seconds = %8.2f for %d iterations each with %d records
",$total,$max, sizeof($arr));
+ flush();
+
+
+ //$db->Close();
+}
+include("testdatabases.inc.php");
+
+?>
+
+
+
+
diff --git a/adodb/tests/client.php b/adodb/tests/client.php
new file mode 100644
index 0000000..8452da4
--- /dev/null
+++ b/adodb/tests/client.php
@@ -0,0 +1,208 @@
+
+
+';
+ var_dump(parse_url('odbc_mssql://userserver/'));
+ die();
+
+include('../adodb.inc.php');
+include('../tohtml.inc.php');
+
+ function send2server($url,$sql)
+ {
+ $url .= '?sql='.urlencode($sql);
+ print "$url
";
+ $rs = csv2rs($url,$err);
+ if ($err) print $err;
+ return $rs;
+ }
+
+ function print_pre($s)
+ {
+ print "";print_r($s);print " ";
+ }
+
+
+$serverURL = 'http://localhost/php/phplens/adodb/server.php';
+$testhttp = false;
+
+$sql1 = "insertz into products (productname) values ('testprod 1')";
+$sql2 = "insert into products (productname) values ('testprod 1')";
+$sql3 = "insert into products (productname) values ('testprod 2')";
+$sql4 = "delete from products where productid>80";
+$sql5 = 'select * from products';
+
+if ($testhttp) {
+ print "Client Driver Tests ";
+ print "
Test Error ";
+ $rs = send2server($serverURL,$sql1);
+ print_pre($rs);
+ print " ";
+
+ print "Test Insert ";
+
+ $rs = send2server($serverURL,$sql2);
+ print_pre($rs);
+ print " ";
+
+ print "Test Insert2 ";
+
+ $rs = send2server($serverURL,$sql3);
+ print_pre($rs);
+ print " ";
+
+ print "Test Delete ";
+
+ $rs = send2server($serverURL,$sql4);
+ print_pre($rs);
+ print " ";
+
+
+ print "Test Select ";
+ $rs = send2server($serverURL,$sql5);
+ if ($rs) rs2html($rs);
+
+ print " ";
+}
+
+
+print "CLIENT Driver Tests ";
+$conn = ADONewConnection('csv');
+$conn->Connect($serverURL);
+$conn->debug = true;
+
+print "Bad SQL ";
+
+$rs = $conn->Execute($sql1);
+
+print "Insert SQL 1 ";
+$rs = $conn->Execute($sql2);
+
+print "Insert SQL 2 ";
+$rs = $conn->Execute($sql3);
+
+print "Select SQL ";
+$rs = $conn->Execute($sql5);
+if ($rs) rs2html($rs);
+
+print "Delete SQL ";
+$rs = $conn->Execute($sql4);
+
+print "Select SQL ";
+$rs = $conn->Execute($sql5);
+if ($rs) rs2html($rs);
+
+
+/* EXPECTED RESULTS FOR HTTP TEST:
+
+Test Insert
+http://localhost/php/adodb/server.php?sql=insert+into+products+%28productname%29+values+%28%27testprod%27%29
+
+adorecordset Object
+(
+ [dataProvider] => native
+ [fields] =>
+ [blobSize] => 64
+ [canSeek] =>
+ [EOF] => 1
+ [emptyTimeStamp] =>
+ [emptyDate] =>
+ [debug] =>
+ [timeToLive] => 0
+ [bind] =>
+ [_numOfRows] => -1
+ [_numOfFields] => 0
+ [_queryID] => 1
+ [_currentRow] => -1
+ [_closed] =>
+ [_inited] =>
+ [sql] => insert into products (productname) values ('testprod')
+ [affectedrows] => 1
+ [insertid] => 81
+)
+
+
+--------------------------------------------------------------------------------
+
+Test Insert2
+http://localhost/php/adodb/server.php?sql=insert+into+products+%28productname%29+values+%28%27testprod%27%29
+
+adorecordset Object
+(
+ [dataProvider] => native
+ [fields] =>
+ [blobSize] => 64
+ [canSeek] =>
+ [EOF] => 1
+ [emptyTimeStamp] =>
+ [emptyDate] =>
+ [debug] =>
+ [timeToLive] => 0
+ [bind] =>
+ [_numOfRows] => -1
+ [_numOfFields] => 0
+ [_queryID] => 1
+ [_currentRow] => -1
+ [_closed] =>
+ [_inited] =>
+ [sql] => insert into products (productname) values ('testprod')
+ [affectedrows] => 1
+ [insertid] => 82
+)
+
+
+--------------------------------------------------------------------------------
+
+Test Delete
+http://localhost/php/adodb/server.php?sql=delete+from+products+where+productid%3E80
+
+adorecordset Object
+(
+ [dataProvider] => native
+ [fields] =>
+ [blobSize] => 64
+ [canSeek] =>
+ [EOF] => 1
+ [emptyTimeStamp] =>
+ [emptyDate] =>
+ [debug] =>
+ [timeToLive] => 0
+ [bind] =>
+ [_numOfRows] => -1
+ [_numOfFields] => 0
+ [_queryID] => 1
+ [_currentRow] => -1
+ [_closed] =>
+ [_inited] =>
+ [sql] => delete from products where productid>80
+ [affectedrows] => 2
+ [insertid] => 0
+)
+
+[more stuff deleted]
+ .
+ .
+ .
+*/
diff --git a/adodb/tests/pdo.php b/adodb/tests/pdo.php
new file mode 100644
index 0000000..b1b5452
--- /dev/null
+++ b/adodb/tests/pdo.php
@@ -0,0 +1,111 @@
+";
+try {
+ echo "New Connection\n";
+
+
+ $dsn = 'pdo_mysql://root:@localhost/northwind?persist';
+
+ if (!empty($dsn)) {
+ $DB = NewADOConnection($dsn) || die("CONNECT FAILED");
+ $connstr = $dsn;
+ } else {
+
+ $DB = NewADOConnection('pdo');
+
+ echo "Connect\n";
+
+ $u = ''; $p = '';
+ /*
+ $connstr = 'odbc:nwind';
+
+ $connstr = 'oci:';
+ $u = 'scott';
+ $p = 'natsoft';
+
+
+ $connstr ="sqlite:d:\inetpub\adodb\sqlite.db";
+ */
+
+ $connstr = "mysql:dbname=northwind";
+ $u = 'root';
+
+ $connstr = "pgsql:dbname=test";
+ $u = 'tester';
+ $p = 'test';
+
+ $DB->Connect($connstr,$u,$p) || die("CONNECT FAILED");
+
+ }
+
+ echo "connection string=$connstr\n Execute\n";
+
+ //$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $rs = $DB->Execute("select * from ADOXYZ where id<3");
+ if ($DB->ErrorNo()) echo "*** errno=".$DB->ErrorNo() . " ".($DB->ErrorMsg())."\n";
+
+
+ //print_r(get_class_methods($DB->_stmt));
+
+ if (!$rs) die("NO RS");
+
+ echo "Meta\n";
+ for ($i=0; $i < $rs->NumCols(); $i++) {
+ var_dump($rs->FetchField($i));
+ echo " ";
+ }
+
+ echo "FETCH\n";
+ $cnt = 0;
+ while (!$rs->EOF) {
+ adodb_pr($rs->fields);
+ $rs->MoveNext();
+ if ($cnt++ > 1000) break;
+ }
+
+ echo " -------------------------------------------------------- \n\n\n";
+
+ $stmt = $DB->PrepareStmt("select * from ADOXYZ");
+
+ $rs = $stmt->Execute();
+ $cols = $stmt->NumCols(); // execute required
+
+ echo "COLS = $cols";
+ for($i=1;$i<=$cols;$i++) {
+ $v = $stmt->_stmt->getColumnMeta($i);
+ var_dump($v);
+ }
+
+ echo "e=".$stmt->ErrorNo() . " ".($stmt->ErrorMsg())."\n";
+ while ($arr = $rs->FetchRow()) {
+ adodb_pr($arr);
+ }
+ die("DONE\n");
+
+} catch (exception $e) {
+ echo "";
+ echo $e;
+ echo " ";
+}
diff --git a/adodb/tests/test-active-record.php b/adodb/tests/test-active-record.php
new file mode 100644
index 0000000..081527e
--- /dev/null
+++ b/adodb/tests/test-active-record.php
@@ -0,0 +1,156 @@
+debug=1;
+ ADOdb_Active_Record::SetDatabaseAdapter($db);
+
+
+ $db->Execute("CREATE TEMPORARY TABLE `persons` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `name_first` varchar(100) NOT NULL default '',
+ `name_last` varchar(100) NOT NULL default '',
+ `favorite_color` varchar(100) NOT NULL default '',
+ PRIMARY KEY (`id`)
+ ) ENGINE=MyISAM;
+ ");
+
+ $db->Execute("CREATE TEMPORARY TABLE `children` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `person_id` int(10) unsigned NOT NULL,
+ `name_first` varchar(100) NOT NULL default '',
+ `name_last` varchar(100) NOT NULL default '',
+ `favorite_pet` varchar(100) NOT NULL default '',
+ PRIMARY KEY (`id`)
+ ) ENGINE=MyISAM;
+ ");
+
+ class Person extends ADOdb_Active_Record{ function ret($v) {return $v;} }
+ $person = new Person();
+ ADOdb_Active_Record::$_quoteNames = '111';
+
+ echo "Output of getAttributeNames: ";
+ var_dump($person->getAttributeNames());
+
+ /**
+ * Outputs the following:
+ * array(4) {
+ * [0]=>
+ * string(2) "id"
+ * [1]=>
+ * string(9) "name_first"
+ * [2]=>
+ * string(8) "name_last"
+ * [3]=>
+ * string(13) "favorite_color"
+ * }
+ */
+
+ $person = new Person();
+ $person->name_first = 'Andi';
+ $person->name_last = 'Gutmans';
+ $person->save(); // this save() will fail on INSERT as favorite_color is a must fill...
+
+
+ $person = new Person();
+ $person->name_first = 'Andi';
+ $person->name_last = 'Gutmans';
+ $person->favorite_color = 'blue';
+ $person->save(); // this save will perform an INSERT successfully
+
+ echo "
The Insert ID generated:"; print_r($person->id);
+
+ $person->favorite_color = 'red';
+ $person->save(); // this save() will perform an UPDATE
+
+ $person = new Person();
+ $person->name_first = 'John';
+ $person->name_last = 'Lim';
+ $person->favorite_color = 'lavender';
+ $person->save(); // this save will perform an INSERT successfully
+
+ // load record where id=2 into a new ADOdb_Active_Record
+ $person2 = new Person();
+ $person2->Load('id=2');
+
+ $activeArr = $db->GetActiveRecordsClass($class = "Person",$table = "Persons","id=".$db->Param(0),array(2));
+ $person2 = $activeArr[0];
+ echo "
Name (should be John): ",$person->name_first, " Class (should be Person): ",get_class($person2)," ";
+
+ $db->Execute("insert into children (person_id,name_first,name_last) values (2,'Jill','Lim')");
+ $db->Execute("insert into children (person_id,name_first,name_last) values (2,'Joan','Lim')");
+ $db->Execute("insert into children (person_id,name_first,name_last) values (2,'JAMIE','Lim')");
+
+ $newperson2 = new Person();
+ $person2->HasMany('children','person_id');
+ $person2->Load('id=2');
+ $person2->name_last='green';
+ $c = $person2->children;
+ $person2->save();
+
+ if (is_array($c) && sizeof($c) == 3 && $c[0]->name_first=='Jill' && $c[1]->name_first=='Joan'
+ && $c[2]->name_first == 'JAMIE') echo "OK Loaded HasMany";
+ else {
+ var_dump($c);
+ echo "error loading hasMany should have 3 array elements Jill Joan Jamie ";
+ }
+
+ class Child extends ADOdb_Active_Record{};
+ $ch = new Child('children',array('id'));
+ $ch->BelongsTo('person','person_id','id');
+ $ch->Load('id=1');
+ if ($ch->name_first !== 'Jill') echo "error in Loading Child ";
+
+ $p = $ch->person;
+ if ($p->name_first != 'John') echo "Error loading belongsTo ";
+ else echo "OK loading BelongTo ";
+
+ $p->hasMany('children','person_id');
+ $p->LoadRelations('children', " Name_first like 'J%' order by id",1,2);
+ if (sizeof($p->children) == 2 && $p->children[1]->name_first == 'JAMIE') echo "OK LoadRelations ";
+ else echo "error LoadRelations ";
+
+ $db->Execute("CREATE TEMPORARY TABLE `persons2` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `name_first` varchar(100) NOT NULL default '',
+ `name_last` varchar(100) NOT NULL default '',
+ `favorite_color` varchar(100) default '',
+ PRIMARY KEY (`id`)
+ ) ENGINE=MyISAM;
+ ");
+
+ $p = new adodb_active_record('persons2');
+ $p->name_first = 'James';
+
+ $p->name_last = 'James';
+
+ $p->HasMany('children','person_id');
+ $p->children;
+ var_dump($p);
+ $p->Save();
diff --git a/adodb/tests/test-active-recs2.php b/adodb/tests/test-active-recs2.php
new file mode 100644
index 0000000..a9fcbc0
--- /dev/null
+++ b/adodb/tests/test-active-recs2.php
@@ -0,0 +1,96 @@
+Connect("localhost","tester","test","test");
+} else
+ $db = NewADOConnection('oci8://scott:natsoft@/');
+
+
+$arr = $db->ServerInfo();
+echo "
$db->dataProvider: {$arr['description']} ";
+
+$arr = $db->GetActiveRecords('products',' productid<10');
+adodb_pr($arr);
+
+ADOdb_Active_Record::SetDatabaseAdapter($db);
+if (!$db) die('failed');
+
+
+
+
+$rec = new ADODB_Active_Record('photos');
+
+$rec = new ADODB_Active_Record('products');
+
+
+adodb_pr($rec->getAttributeNames());
+
+echo " ";
+
+
+$rec->load('productid=2');
+adodb_pr($rec);
+
+$db->debug=1;
+
+
+$rec->productname = 'Changie Chan'.rand();
+
+$rec->insert();
+$rec->update();
+
+$rec->productname = 'Changie Chan 99';
+$rec->replace();
+
+
+$rec2 = new ADODB_Active_Record('products');
+$rec->load('productid=3');
+$rec->save();
+
+$rec = new ADODB_Active_record('products');
+$rec->productname = 'John ActiveRec';
+$rec->notes = 22;
+#$rec->productid=0;
+$rec->discontinued=1;
+$rec->Save();
+$rec->supplierid=33;
+$rec->Save();
+$rec->discontinued=0;
+$rec->Save();
+$rec->Delete();
+
+echo "Affected Rows after delete=".$db->Affected_Rows()."
";
diff --git a/adodb/tests/test-active-relations.php b/adodb/tests/test-active-relations.php
new file mode 100644
index 0000000..bb01375
--- /dev/null
+++ b/adodb/tests/test-active-relations.php
@@ -0,0 +1,104 @@
+debug=1;
+ ADOdb_Active_Record::SetDatabaseAdapter($db);
+
+ $db->Execute("CREATE TEMPORARY TABLE `persons` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `name_first` varchar(100) NOT NULL default '',
+ `name_last` varchar(100) NOT NULL default '',
+ `favorite_color` varchar(100) NOT NULL default '',
+ PRIMARY KEY (`id`)
+ ) ENGINE=MyISAM;
+ ");
+
+ $db->Execute("CREATE TEMPORARY TABLE `children` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `person_id` int(10) unsigned NOT NULL,
+ `name_first` varchar(100) NOT NULL default '',
+ `name_last` varchar(100) NOT NULL default '',
+ `favorite_pet` varchar(100) NOT NULL default '',
+ PRIMARY KEY (`id`)
+ ) ENGINE=MyISAM;
+ ");
+
+
+ $db->Execute("insert into children (person_id,name_first,name_last) values (1,'Jill','Lim')");
+ $db->Execute("insert into children (person_id,name_first,name_last) values (1,'Joan','Lim')");
+ $db->Execute("insert into children (person_id,name_first,name_last) values (1,'JAMIE','Lim')");
+
+ ADODB_Active_Record::TableHasMany('persons', 'children','person_id');
+ class person extends ADOdb_Active_Record{}
+
+ $person = new person();
+# $person->HasMany('children','person_id'); ## this is affects all other instances of Person
+
+ $person->name_first = 'John';
+ $person->name_last = 'Lim';
+ $person->favorite_color = 'lavender';
+ $person->save(); // this save will perform an INSERT successfully
+
+ $person2 = new person();
+ $person2->Load('id=1');
+
+ $c = $person2->children;
+ if (is_array($c) && sizeof($c) == 3 && $c[0]->name_first=='Jill' && $c[1]->name_first=='Joan'
+ && $c[2]->name_first == 'JAMIE') echo "OK Loaded HasMany";
+ else {
+ var_dump($c);
+ echo "error loading hasMany should have 3 array elements Jill Joan Jamie ";
+ }
+
+ class child extends ADOdb_Active_Record{};
+ ADODB_Active_Record::TableBelongsTo('children','person','person_id','id');
+ $ch = new Child('children',array('id'));
+
+ $ch->Load('id=1');
+ if ($ch->name_first !== 'Jill') echo "error in Loading Child ";
+
+ $p = $ch->person;
+ if (!$p || $p->name_first != 'John') echo "Error loading belongsTo ";
+ else echo "OK loading BelongTo ";
+
+ if ($p) {
+ #$p->HasMany('children','person_id'); ## this is affects all other instances of Person
+ $p->LoadRelations('children', 'order by id',1,2);
+ if (sizeof($p->children) == 2 && $p->children[1]->name_first == 'JAMIE') echo "OK LoadRelations ";
+ else {
+ var_dump($p->children);
+ echo "error LoadRelations ";
+ }
+
+ unset($p->children);
+ $p->LoadRelations('children', " name_first like 'J%' order by id",1,2);
+ }
+ if ($p)
+ foreach($p->children as $c) {
+ echo " Saving $c->name_first ";
+ $c->name_first .= ' K.';
+ $c->Save();
+ }
diff --git a/adodb/tests/test-active-relationsx.php b/adodb/tests/test-active-relationsx.php
new file mode 100644
index 0000000..4d3a80d
--- /dev/null
+++ b/adodb/tests/test-active-relationsx.php
@@ -0,0 +1,438 @@
+\n", $txt);
+ echo $txt;
+ }
+
+ include_once('../adodb.inc.php');
+ include_once('../adodb-active-recordx.inc.php');
+
+
+ $db = NewADOConnection('mysql://root@localhost/test');
+ $db->debug=0;
+ ADOdb_Active_Record::SetDatabaseAdapter($db);
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("Preparing database using SQL queries (creating 'people', 'children')\n");
+
+ $db->Execute("DROP TABLE `people`");
+ $db->Execute("DROP TABLE `children`");
+ $db->Execute("DROP TABLE `artists`");
+ $db->Execute("DROP TABLE `songs`");
+
+ $db->Execute("CREATE TABLE `people` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `name_first` varchar(100) NOT NULL default '',
+ `name_last` varchar(100) NOT NULL default '',
+ `favorite_color` varchar(100) NOT NULL default '',
+ PRIMARY KEY (`id`)
+ ) ENGINE=MyISAM;
+ ");
+ $db->Execute("CREATE TABLE `children` (
+ `person_id` int(10) unsigned NOT NULL,
+ `name_first` varchar(100) NOT NULL default '',
+ `name_last` varchar(100) NOT NULL default '',
+ `favorite_pet` varchar(100) NOT NULL default '',
+ `id` int(10) unsigned NOT NULL auto_increment,
+ PRIMARY KEY (`id`)
+ ) ENGINE=MyISAM;
+ ");
+
+ $db->Execute("CREATE TABLE `artists` (
+ `name` varchar(100) NOT NULL default '',
+ `artistuniqueid` int(10) unsigned NOT NULL auto_increment,
+ PRIMARY KEY (`artistuniqueid`)
+ ) ENGINE=MyISAM;
+ ");
+
+ $db->Execute("CREATE TABLE `songs` (
+ `name` varchar(100) NOT NULL default '',
+ `artistid` int(10) NOT NULL,
+ `recordid` int(10) unsigned NOT NULL auto_increment,
+ PRIMARY KEY (`recordid`)
+ ) ENGINE=MyISAM;
+ ");
+
+ $db->Execute("insert into children (person_id,name_first,name_last,favorite_pet) values (1,'Jill','Lim','tortoise')");
+ $db->Execute("insert into children (person_id,name_first,name_last) values (1,'Joan','Lim')");
+ $db->Execute("insert into children (person_id,name_first,name_last) values (1,'JAMIE','Lim')");
+
+ $db->Execute("insert into artists (artistuniqueid, name) values(1,'Elvis Costello')");
+ $db->Execute("insert into songs (recordid, name, artistid) values(1,'No Hiding Place', 1)");
+ $db->Execute("insert into songs (recordid, name, artistid) values(2,'American Gangster Time', 1)");
+
+ // This class _implicitely_ relies on the 'people' table (pluralized form of 'person')
+ class Person extends ADOdb_Active_Record
+ {
+ function __construct()
+ {
+ parent::__construct();
+ $this->hasMany('children');
+ }
+ }
+ // This class _implicitely_ relies on the 'children' table
+ class Child extends ADOdb_Active_Record
+ {
+ function __construct()
+ {
+ parent::__construct();
+ $this->belongsTo('person');
+ }
+ }
+ // This class _explicitely_ relies on the 'children' table and shares its metadata with Child
+ class Kid extends ADOdb_Active_Record
+ {
+ function __construct()
+ {
+ parent::__construct('children');
+ $this->belongsTo('person');
+ }
+ }
+ // This class _explicitely_ relies on the 'children' table but does not share its metadata
+ class Rugrat extends ADOdb_Active_Record
+ {
+ function __construct()
+ {
+ parent::__construct('children', false, false, array('new' => true));
+ }
+ }
+
+ class Artist extends ADOdb_Active_Record
+ {
+ function __construct()
+ {
+ parent::__construct('artists', array('artistuniqueid'));
+ $this->hasMany('songs', 'artistid');
+ }
+ }
+ class Song extends ADOdb_Active_Record
+ {
+ function __construct()
+ {
+ parent::__construct('songs', array('recordid'));
+ $this->belongsTo('artist', 'artistid');
+ }
+ }
+
+ ar_echo("Inserting person in 'people' table ('John Lim, he likes lavender')\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $person = new Person();
+ $person->name_first = 'John';
+ $person->name_last = 'Lim';
+ $person->favorite_color = 'lavender';
+ $person->save(); // this save will perform an INSERT successfully
+
+ $person = new Person();
+ $person->name_first = 'Lady';
+ $person->name_last = 'Cat';
+ $person->favorite_color = 'green';
+ $person->save();
+
+ $child = new Child();
+ $child->name_first = 'Fluffy';
+ $child->name_last = 'Cat';
+ $child->favorite_pet = 'Cat Lady';
+ $child->person_id = $person->id;
+ $child->save();
+
+ $child = new Child();
+ $child->name_first = 'Sun';
+ $child->name_last = 'Cat';
+ $child->favorite_pet = 'Cat Lady';
+ $child->person_id = $person->id;
+ $child->save();
+
+ $err_count = 0;
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("person->Find('id=1') [Lazy Method]\n");
+ ar_echo("person is loaded but its children will be loaded on-demand later on\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $person = new Person();
+ $people = $person->Find('id=1');
+ ar_echo((ar_assert(found($people, "'name_first' => 'John'"))) ? "[OK] Found John\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($people, "'favorite_pet' => 'tortoise'"))) ? "[OK] No relation yet\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo("\n-- Lazily Loading Children:\n\n");
+ foreach($people as $aperson)
+ {
+ foreach($aperson->children as $achild)
+ {
+ if($achild->name_first);
+ }
+ }
+ ar_echo((ar_assert(found($people, "'favorite_pet' => 'tortoise'"))) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'Joan'"))) ? "[OK] Found Joan\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'JAMIE'"))) ? "[OK] Found JAMIE\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("person->Find('id=1' ... ADODB_WORK_AR) [Worker Method]\n");
+ ar_echo("person is loaded, and so are its children\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $person = new Person();
+ $people = $person->Find('id=1', false, false, array('loading' => ADODB_WORK_AR));
+ ar_echo((ar_assert(found($people, "'name_first' => 'John'"))) ? "[OK] Found John\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'favorite_pet' => 'tortoise'"))) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'Joan'"))) ? "[OK] Found Joan\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'JAMIE'"))) ? "[OK] Found JAMIE\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("person->Find('id=1' ... ADODB_JOIN_AR) [Join Method]\n");
+ ar_echo("person and its children are loaded using a single query\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $person = new Person();
+ // When I specifically ask for a join, I have to specify which table id I am looking up
+ // otherwise the SQL parser will wonder which table's id that would be.
+ $people = $person->Find('people.id=1', false, false, array('loading' => ADODB_JOIN_AR));
+ ar_echo((ar_assert(found($people, "'name_first' => 'John'"))) ? "[OK] Found John\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'favorite_pet' => 'tortoise'"))) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'Joan'"))) ? "[OK] Found Joan\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'JAMIE'"))) ? "[OK] Found JAMIE\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("person->Load('people.id=1') [Join Method]\n");
+ ar_echo("Load() always uses the join method since it returns only one row\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $person = new Person();
+ // Under the hood, Load(), since it returns only one row, always perform a join
+ // Therefore we need to clarify which id we are talking about.
+ $person->Load('people.id=1');
+ ar_echo((ar_assert(found($person, "'name_first' => 'John'"))) ? "[OK] Found John\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($person, "'favorite_pet' => 'tortoise'"))) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n");
+ ar_echo((ar_assert(found($person, "'name_first' => 'Joan'"))) ? "[OK] Found Joan\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($person, "'name_first' => 'JAMIE'"))) ? "[OK] Found JAMIE\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("child->Load('children.id=1') [Join Method]\n");
+ ar_echo("We are now loading from the 'children' table, not from 'people'\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $child = new Child();
+ $child->Load('children.id=1');
+ ar_echo((ar_assert(found($child, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($child, "'favorite_color' => 'lavender'"))) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("child->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $child = new Child();
+ $children = $child->Find('id=1', false, false, array('loading' => ADODB_WORK_AR));
+ ar_echo((ar_assert(found($children, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($children, "'favorite_color' => 'lavender'"))) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n");
+ ar_echo((ar_assert(notfound($children, "'name_first' => 'Joan'"))) ? "[OK] No Joan relation\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($children, "'name_first' => 'JAMIE'"))) ? "[OK] No JAMIE relation\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("kid->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n");
+ ar_echo("Where we see that kid shares relationships with child because they are stored\n");
+ ar_echo("in the common table's metadata structure.\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $kid = new Kid('children');
+ $kids = $kid->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR));
+ ar_echo((ar_assert(found($kids, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($kids, "'favorite_color' => 'lavender'"))) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n");
+ ar_echo((ar_assert(notfound($kids, "'name_first' => 'Joan'"))) ? "[OK] No Joan relation\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($kids, "'name_first' => 'JAMIE'"))) ? "[OK] No JAMIE relation\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("kid->Find('children.id=1' ... ADODB_LAZY_AR) [Lazy Method]\n");
+ ar_echo("Of course, lazy loading also retrieve medata information...\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $kid = new Kid('children');
+ $kids = $kid->Find('children.id=1', false, false, array('loading' => ADODB_LAZY_AR));
+ ar_echo((ar_assert(found($kids, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($kids, "'favorite_color' => 'lavender'"))) ? "[OK] No relation yet\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo("\n-- Lazily Loading People:\n\n");
+ foreach($kids as $akid)
+ {
+ if($akid->person);
+ }
+ ar_echo((ar_assert(found($kids, "'favorite_color' => 'lavender'"))) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n");
+ ar_echo((ar_assert(notfound($kids, "'name_first' => 'Joan'"))) ? "[OK] No Joan relation\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo((ar_assert(notfound($kids, "'name_first' => 'JAMIE'"))) ? "[OK] No JAMIE relation\n" : "[!!] Found relation when I shouldn't\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("rugrat->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n");
+ ar_echo("In rugrat's constructor it is specified that\nit must forget any existing relation\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $rugrat = new Rugrat('children');
+ $rugrats = $rugrat->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR));
+ ar_echo((ar_assert(found($rugrats, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($rugrats, "'favorite_color' => 'lavender'"))) ? "[OK] No relation found\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo((ar_assert(notfound($rugrats, "'name_first' => 'Joan'"))) ? "[OK] No Joan relation\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo((ar_assert(notfound($rugrats, "'name_first' => 'JAMIE'"))) ? "[OK] No JAMIE relation\n" : "[!!] Found relation when I shouldn't\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("kid->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n");
+ ar_echo("Note how only rugrat forgot its relations - kid is fine.\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $kid = new Kid('children');
+ $kids = $kid->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR));
+ ar_echo((ar_assert(found($kids, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($kids, "'favorite_color' => 'lavender'"))) ? "[OK] I did not forget relation: person\n" : "[!!] I should not have forgotten relation: person\n");
+ ar_echo((ar_assert(notfound($kids, "'name_first' => 'Joan'"))) ? "[OK] No Joan relation\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo((ar_assert(notfound($kids, "'name_first' => 'JAMIE'"))) ? "[OK] No JAMIE relation\n" : "[!!] Found relation when I shouldn't\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("rugrat->Find('children.id=1' ... ADODB_WORK_AR) [Worker Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $rugrat = new Rugrat('children');
+ $rugrats = $rugrat->Find('children.id=1', false, false, array('loading' => ADODB_WORK_AR));
+ $arugrat = $rugrats[0];
+ ar_echo((ar_assert(found($arugrat, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($arugrat, "'favorite_color' => 'lavender'"))) ? "[OK] No relation yet\n" : "[!!] Found relation when I shouldn't\n");
+
+ ar_echo("\n-- Loading relations:\n\n");
+ $arugrat->belongsTo('person');
+ $arugrat->LoadRelations('person', 'order by id', 0, 2);
+ ar_echo((ar_assert(found($arugrat, "'favorite_color' => 'lavender'"))) ? "[OK] Found relation: person\n" : "[!!] Missing relation: person\n");
+ ar_echo((ar_assert(found($arugrat, "'name_first' => 'Jill'"))) ? "[OK] Found Jill\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($arugrat, "'name_first' => 'Joan'"))) ? "[OK] No Joan relation\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo((ar_assert(notfound($arugrat, "'name_first' => 'JAMIE'"))) ? "[OK] No Joan relation\n" : "[!!] Found relation when I shouldn't\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("person->Find('1=1') [Lazy Method]\n");
+ ar_echo("And now for our finale...\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $person = new Person();
+ $people = $person->Find('1=1', false, false, array('loading' => ADODB_LAZY_AR));
+ ar_echo((ar_assert(found($people, "'name_first' => 'John'"))) ? "[OK] Found John\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($people, "'favorite_pet' => 'tortoise'"))) ? "[OK] No relation yet\n" : "[!!] Found relation when I shouldn't\n");
+ ar_echo((ar_assert(notfound($people, "'name_first' => 'Fluffy'"))) ? "[OK] No Fluffy yet\n" : "[!!] Found Fluffy relation when I shouldn't\n");
+ ar_echo("\n-- Lazily Loading Everybody:\n\n");
+ foreach($people as $aperson)
+ {
+ foreach($aperson->children as $achild)
+ {
+ if($achild->name_first);
+ }
+ }
+ ar_echo((ar_assert(found($people, "'favorite_pet' => 'tortoise'"))) ? "[OK] Found relation: child\n" : "[!!] Missing relation: child\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'Joan'"))) ? "[OK] Found Joan\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'JAMIE'"))) ? "[OK] Found JAMIE\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'Lady'"))) ? "[OK] Found Cat Lady\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'Fluffy'"))) ? "[OK] Found Fluffy\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($people, "'name_first' => 'Sun'"))) ? "[OK] Found Sun\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("artist->Load('artistuniqueid=1') [Join Method]\n");
+ ar_echo("Yes, we are dabbling in the musical field now..\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $artist = new Artist();
+ $artist->Load('artistuniqueid=1');
+ ar_echo((ar_assert(found($artist, "'name' => 'Elvis Costello'"))) ? "[OK] Found Elvis Costello\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($artist, "'name' => 'No Hiding Place'"))) ? "[OK] Found relation: song\n" : "[!!] Missing relation: song\n");
+
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("song->Load('recordid=1') [Join Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $song = new Song();
+ $song->Load('recordid=1');
+ ar_echo((ar_assert(found($song, "'name' => 'No Hiding Place'"))) ? "[OK] Found song\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("artist->Find('artistuniqueid=1' ... ADODB_JOIN_AR) [Join Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $artist = new Artist();
+ $artists = $artist->Find('artistuniqueid=1', false, false, array('loading' => ADODB_JOIN_AR));
+ ar_echo((ar_assert(found($artists, "'name' => 'Elvis Costello'"))) ? "[OK] Found Elvis Costello\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($artists, "'name' => 'No Hiding Place'"))) ? "[OK] Found relation: song\n" : "[!!] Missing relation: song\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("song->Find('recordid=1' ... ADODB_JOIN_AR) [Join Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $song = new Song();
+ $songs = $song->Find('recordid=1', false, false, array('loading' => ADODB_JOIN_AR));
+ ar_echo((ar_assert(found($songs, "'name' => 'No Hiding Place'"))) ? "[OK] Found song\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("artist->Find('artistuniqueid=1' ... ADODB_WORK_AR) [Work Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $artist = new Artist();
+ $artists = $artist->Find('artistuniqueid=1', false, false, array('loading' => ADODB_WORK_AR));
+ ar_echo((ar_assert(found($artists, "'name' => 'Elvis Costello'"))) ? "[OK] Found Elvis Costello\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(found($artists, "'name' => 'No Hiding Place'"))) ? "[OK] Found relation: song\n" : "[!!] Missing relation: song\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("song->Find('recordid=1' ... ADODB_JOIN_AR) [Join Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $song = new Song();
+ $songs = $song->Find('recordid=1', false, false, array('loading' => ADODB_WORK_AR));
+ ar_echo((ar_assert(found($songs, "'name' => 'No Hiding Place'"))) ? "[OK] Found song\n" : "[!!] Find failed\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("artist->Find('artistuniqueid=1' ... ADODB_LAZY_AR) [Lazy Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $artist = new Artist();
+ $artists = $artist->Find('artistuniqueid=1', false, false, array('loading' => ADODB_LAZY_AR));
+ ar_echo((ar_assert(found($artists, "'name' => 'Elvis Costello'"))) ? "[OK] Found Elvis Costello\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($artists, "'name' => 'No Hiding Place'"))) ? "[OK] No relation yet\n" : "[!!] Found relation when I shouldn't\n");
+ foreach($artists as $anartist)
+ {
+ foreach($anartist->songs as $asong)
+ {
+ if($asong->name);
+ }
+ }
+ ar_echo((ar_assert(found($artists, "'name' => 'No Hiding Place'"))) ? "[OK] Found relation: song\n" : "[!!] Missing relation: song\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("song->Find('recordid=1' ... ADODB_LAZY_AR) [Lazy Method]\n");
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
+ $song = new Song();
+ $songs = $song->Find('recordid=1', false, false, array('loading' => ADODB_LAZY_AR));
+ ar_echo((ar_assert(found($songs, "'name' => 'No Hiding Place'"))) ? "[OK] Found song\n" : "[!!] Find failed\n");
+ ar_echo((ar_assert(notfound($songs, "'name' => 'Elvis Costello'"))) ? "[OK] No relation yet\n" : "[!!] Found relation when I shouldn't\n");
+ foreach($songs as $asong)
+ {
+ if($asong->artist);
+ }
+ ar_echo((ar_assert(found($songs, "'name' => 'Elvis Costello'"))) ? "[OK] Found relation: artist\n" : "[!!] Missing relation: artist\n");
+
+ ar_echo("\n\n-------------------------------------------------------------------------------------------------------------------\n");
+ ar_echo("Test suite complete. " . (($err_count > 0) ? "$err_count errors found.\n" : "Success.\n"));
+ ar_echo("-------------------------------------------------------------------------------------------------------------------\n");
diff --git a/adodb/tests/test-datadict.php b/adodb/tests/test-datadict.php
new file mode 100644
index 0000000..5caea25
--- /dev/null
+++ b/adodb/tests/test-datadict.php
@@ -0,0 +1,258 @@
+$dbType";
+ $db = NewADOConnection($dbType);
+ $dict = newDataDictionary($db);
+
+ if (!$dict) continue;
+ $dict->debug = 1;
+
+ $opts = array('REPLACE','mysql' => 'ENGINE=INNODB', 'oci8' => 'TABLESPACE USERS');
+
+/* $flds = array(
+ array('id', 'I',
+ 'AUTO','KEY'),
+
+ array('name' => 'firstname', 'type' => 'varchar','size' => 30,
+ 'DEFAULT'=>'Joan'),
+
+ array('lastname','varchar',28,
+ 'DEFAULT'=>'Chen','key'),
+
+ array('averylonglongfieldname','X',1024,
+ 'NOTNULL','default' => 'test'),
+
+ array('price','N','7.2',
+ 'NOTNULL','default' => '0.00'),
+
+ array('MYDATE', 'D',
+ 'DEFDATE'),
+ array('TS','T',
+ 'DEFTIMESTAMP')
+ );*/
+
+ $flds = "
+ID I AUTO KEY,
+FIRSTNAME VARCHAR(30) DEFAULT 'Joan' INDEX idx_name,
+LASTNAME VARCHAR(28) DEFAULT 'Chen' key INDEX idx_name INDEX idx_lastname,
+averylonglongfieldname X(1024) DEFAULT 'test',
+price N(7.2) DEFAULT '0.00',
+MYDATE D DEFDATE INDEX idx_date,
+BIGFELLOW X NOTNULL,
+TS_SECS T DEFTIMESTAMP,
+TS_SUBSEC TS DEFTIMESTAMP
+";
+
+
+ $sqla = $dict->CreateDatabase('KUTU',array('postgres'=>"LOCATION='/u01/postdata'"));
+ $dict->SetSchema('KUTU');
+
+ $sqli = ($dict->CreateTableSQL('testtable',$flds, $opts));
+ $sqla = array_merge($sqla,$sqli);
+
+ $sqli = $dict->CreateIndexSQL('idx','testtable','price,firstname,lastname',array('BITMAP','FULLTEXT','CLUSTERED','HASH'));
+ $sqla = array_merge($sqla,$sqli);
+ $sqli = $dict->CreateIndexSQL('idx2','testtable','price,lastname');//,array('BITMAP','FULLTEXT','CLUSTERED'));
+ $sqla = array_merge($sqla,$sqli);
+
+ $addflds = array(array('height', 'F'),array('weight','F'));
+ $sqli = $dict->AddColumnSQL('testtable',$addflds);
+ $sqla = array_merge($sqla,$sqli);
+ $addflds = array(array('height', 'F','NOTNULL'),array('weight','F','NOTNULL'));
+ $sqli = $dict->AlterColumnSQL('testtable',$addflds);
+ $sqla = array_merge($sqla,$sqli);
+
+
+ printsqla($dbType,$sqla);
+
+ if (file_exists('d:\inetpub\wwwroot\php\phplens\adodb\adodb.inc.php'))
+ if ($dbType == 'mysqlt') {
+ $db->Connect('localhost', "root", "", "test");
+ $dict->SetSchema('');
+ $sqla2 = $dict->ChangeTableSQL('adoxyz',$flds);
+ if ($sqla2) printsqla($dbType,$sqla2);
+ }
+ if ($dbType == 'postgres') {
+ if (@$db->Connect('localhost', "tester", "test", "test"));
+ $dict->SetSchema('');
+ $sqla2 = $dict->ChangeTableSQL('adoxyz',$flds);
+ if ($sqla2) printsqla($dbType,$sqla2);
+ }
+
+ if ($dbType == 'odbc_mssql') {
+ $dsn = $dsn = "PROVIDER=MSDASQL;Driver={SQL Server};Server=localhost;Database=northwind;";
+ if (@$db->Connect($dsn, "sa", "natsoft", "test"));
+ $dict->SetSchema('');
+ $sqla2 = $dict->ChangeTableSQL('adoxyz',$flds);
+ if ($sqla2) printsqla($dbType,$sqla2);
+ }
+
+
+
+ adodb_pr($dict->databaseType);
+ printsqla($dbType, $dict->DropColumnSQL('table',array('my col','`col2_with_Quotes`','A_col3','col3(10)')));
+ printsqla($dbType, $dict->ChangeTableSQL('adoxyz','LASTNAME varchar(32)'));
+
+}
+
+function printsqla($dbType,$sqla)
+{
+ print "
";
+ //print_r($dict->MetaTables());
+ foreach($sqla as $s) {
+ $s = htmlspecialchars($s);
+ print "$s;\n";
+ if ($dbType == 'oci8') print "/\n";
+ }
+ print " ";
+}
+
+/***
+
+Generated SQL:
+
+mysql
+
+CREATE DATABASE KUTU;
+DROP TABLE KUTU.testtable;
+CREATE TABLE KUTU.testtable (
+id INTEGER NOT NULL AUTO_INCREMENT,
+firstname VARCHAR(30) DEFAULT 'Joan',
+lastname VARCHAR(28) NOT NULL DEFAULT 'Chen',
+averylonglongfieldname LONGTEXT NOT NULL,
+price NUMERIC(7,2) NOT NULL DEFAULT 0.00,
+MYDATE DATE DEFAULT CURDATE(),
+ PRIMARY KEY (id, lastname)
+)TYPE=ISAM;
+CREATE FULLTEXT INDEX idx ON KUTU.testtable (firstname,lastname);
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+ALTER TABLE KUTU.testtable ADD height DOUBLE;
+ALTER TABLE KUTU.testtable ADD weight DOUBLE;
+ALTER TABLE KUTU.testtable MODIFY COLUMN height DOUBLE NOT NULL;
+ALTER TABLE KUTU.testtable MODIFY COLUMN weight DOUBLE NOT NULL;
+
+
+--------------------------------------------------------------------------------
+
+oci8
+
+CREATE USER KUTU IDENTIFIED BY tiger;
+/
+GRANT CREATE SESSION, CREATE TABLE,UNLIMITED TABLESPACE,CREATE SEQUENCE TO KUTU;
+/
+DROP TABLE KUTU.testtable CASCADE CONSTRAINTS;
+/
+CREATE TABLE KUTU.testtable (
+id NUMBER(16) NOT NULL,
+firstname VARCHAR(30) DEFAULT 'Joan',
+lastname VARCHAR(28) DEFAULT 'Chen' NOT NULL,
+averylonglongfieldname CLOB NOT NULL,
+price NUMBER(7,2) DEFAULT 0.00 NOT NULL,
+MYDATE DATE DEFAULT TRUNC(SYSDATE),
+ PRIMARY KEY (id, lastname)
+)TABLESPACE USERS;
+/
+DROP SEQUENCE KUTU.SEQ_testtable;
+/
+CREATE SEQUENCE KUTU.SEQ_testtable;
+/
+CREATE OR REPLACE TRIGGER KUTU.TRIG_SEQ_testtable BEFORE insert ON KUTU.testtable
+ FOR EACH ROW
+ BEGIN
+ select KUTU.SEQ_testtable.nextval into :new.id from dual;
+ END;
+/
+CREATE BITMAP INDEX idx ON KUTU.testtable (firstname,lastname);
+/
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+/
+ALTER TABLE testtable ADD (
+ height NUMBER,
+ weight NUMBER);
+/
+ALTER TABLE testtable MODIFY(
+ height NUMBER NOT NULL,
+ weight NUMBER NOT NULL);
+/
+
+
+--------------------------------------------------------------------------------
+
+postgres
+AlterColumnSQL not supported for PostgreSQL
+
+
+CREATE DATABASE KUTU LOCATION='/u01/postdata';
+DROP TABLE KUTU.testtable;
+CREATE TABLE KUTU.testtable (
+id SERIAL,
+firstname VARCHAR(30) DEFAULT 'Joan',
+lastname VARCHAR(28) DEFAULT 'Chen' NOT NULL,
+averylonglongfieldname TEXT NOT NULL,
+price NUMERIC(7,2) DEFAULT 0.00 NOT NULL,
+MYDATE DATE DEFAULT CURRENT_DATE,
+ PRIMARY KEY (id, lastname)
+);
+CREATE INDEX idx ON KUTU.testtable USING HASH (firstname,lastname);
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+ALTER TABLE KUTU.testtable ADD height FLOAT8;
+ALTER TABLE KUTU.testtable ADD weight FLOAT8;
+
+
+--------------------------------------------------------------------------------
+
+odbc_mssql
+
+CREATE DATABASE KUTU;
+DROP TABLE KUTU.testtable;
+CREATE TABLE KUTU.testtable (
+id INT IDENTITY(1,1) NOT NULL,
+firstname VARCHAR(30) DEFAULT 'Joan',
+lastname VARCHAR(28) DEFAULT 'Chen' NOT NULL,
+averylonglongfieldname TEXT NOT NULL,
+price NUMERIC(7,2) DEFAULT 0.00 NOT NULL,
+MYDATE DATETIME DEFAULT GetDate(),
+ PRIMARY KEY (id, lastname)
+);
+CREATE CLUSTERED INDEX idx ON KUTU.testtable (firstname,lastname);
+CREATE INDEX idx2 ON KUTU.testtable (price,lastname);
+ALTER TABLE KUTU.testtable ADD
+ height REAL,
+ weight REAL;
+ALTER TABLE KUTU.testtable ALTER COLUMN height REAL NOT NULL;
+ALTER TABLE KUTU.testtable ALTER COLUMN weight REAL NOT NULL;
+
+
+--------------------------------------------------------------------------------
+*/
+
+
+echo "Test XML Schema ";
+$ff = file('xmlschema.xml');
+echo "";
+foreach($ff as $xml) echo htmlspecialchars($xml);
+echo " ";
+include_once('test-xmlschema.php');
diff --git a/adodb/tests/test-perf.php b/adodb/tests/test-perf.php
new file mode 100644
index 0000000..4c83c17
--- /dev/null
+++ b/adodb/tests/test-perf.php
@@ -0,0 +1,67 @@
+ $v) {
+ if (strncmp($k,'test',4) == 0) $_SESSION['_db'] = $k;
+ }
+}
+
+if (isset($_SESSION['_db'])) {
+ $_db = $_SESSION['_db'];
+ $_GET[$_db] = 1;
+ $$_db = 1;
+}
+
+echo "Performance Monitoring ";
+include_once('testdatabases.inc.php');
+
+
+function testdb($db)
+{
+ if (!$db) return;
+ echo "";print_r($db->ServerInfo()); echo " user=".$db->user." ";
+
+ $perf = NewPerfMonitor($db);
+
+ # unit tests
+ if (0) {
+ //$DB->debug=1;
+ echo "Data Cache Size=".$perf->DBParameter('data cache size').'';
+ echo $perf->HealthCheck();
+ echo($perf->SuspiciousSQL());
+ echo($perf->ExpensiveSQL());
+ echo($perf->InvalidSQL());
+ echo $perf->Tables();
+
+ echo "
";
+ echo $perf->HealthCheckCLI();
+ $perf->Poll(3);
+ die();
+ }
+
+ if ($perf) $perf->UI(3);
+}
diff --git a/adodb/tests/test-pgblob.php b/adodb/tests/test-pgblob.php
new file mode 100644
index 0000000..4c8bd16
--- /dev/null
+++ b/adodb/tests/test-pgblob.php
@@ -0,0 +1,105 @@
+Param(false);
+ $x = (rand() % 10) + 1;
+ $db->debug= ($i==1);
+ $id = $db->GetOne($sql,
+ array('Z%','Z%',$x));
+ if($id != $offset+$x) {
+ print "Error at $x";
+ break;
+ }
+ }
+}
+
+include_once('../adodb.inc.php');
+$db = NewADOConnection('postgres7');
+$db->PConnect('localhost','tester','test','test') || die("failed connection");
+
+$enc = "GIF89a%01%00%01%00%80%FF%00%C0%C0%C0%00%00%00%21%F9%04%01%00%00%00%00%2C%00%00%00%00%01%00%01%00%00%01%012%00%3Bt_clear.gif%0D";
+$val = rawurldecode($enc);
+
+$MAX = 1000;
+
+adodb_pr($db->ServerInfo());
+
+echo "
Testing PREPARE/EXECUTE PLAN ";
+
+
+$db->_bindInputArray = true; // requires postgresql 7.3+ and ability to modify database
+$t = getmicrotime();
+doloop();
+echo '',$MAX,' times, with plan=',getmicrotime() - $t,'
';
+
+
+$db->_bindInputArray = false;
+$t = getmicrotime();
+doloop();
+echo '',$MAX,' times, no plan=',getmicrotime() - $t,'
';
+
+
+
+echo "Testing UPDATEBLOB ";
+$db->debug=1;
+
+### TEST BEGINS
+
+$db->Execute("insert into photos (id,name) values(9999,'dot.gif')");
+$db->UpdateBlob('photos','photo',$val,'id=9999');
+$v = $db->GetOne('select photo from photos where id=9999');
+
+
+### CLEANUP
+
+$db->Execute("delete from photos where id=9999");
+
+### VALIDATION
+
+if ($v !== $val) echo "*** ERROR: Inserted value does not match downloaded val";
+else echo "*** OK: Passed ";
+
+echo "";
+echo "INSERTED: ", $enc;
+echo " ";
+echo"RETURNED: ", rawurlencode($v);
+echo "";
+echo "INSERTED: ", $val;
+echo "
";
+echo "RETURNED: ", $v;
diff --git a/adodb/tests/test-php5.php b/adodb/tests/test-php5.php
new file mode 100644
index 0000000..6d8758b
--- /dev/null
+++ b/adodb/tests/test-php5.php
@@ -0,0 +1,125 @@
+PHP ".PHP_VERSION."\n";
+try {
+
+$dbt = 'oci8po';
+
+try {
+switch($dbt) {
+case 'oci8po':
+ $db = NewADOConnection("oci8po");
+
+ $db->Connect('localhost','scott','natsoft','sherkhan');
+ break;
+default:
+case 'mysql':
+ $db = NewADOConnection("mysql");
+ $db->Connect('localhost','root','','northwind');
+ break;
+
+case 'mysqli':
+ $db = NewADOConnection("mysqli://root:@localhost/northwind");
+ //$db->Connect('localhost','root','','test');
+ break;
+}
+} catch (exception $e){
+ echo "Connect Failed";
+ adodb_pr($e);
+ die();
+}
+
+$db->debug=1;
+
+$cnt = $db->GetOne("select count(*) from adoxyz where ?Prepare("select * from adoxyz where ?ErrorMsg(),"\n";
+$rs = $db->Execute($stmt,array(10,20));
+
+echo " Foreach Iterator Test (rand=".rand().") ";
+$i = 0;
+foreach($rs as $v) {
+ $i += 1;
+ echo "rec $i: "; $s1 = adodb_pr($v,true); $s2 = adodb_pr($rs->fields,true);
+ if ($s1 != $s2 && !empty($v)) {adodb_pr($s1); adodb_pr($s2);}
+ else echo "passed ";
+ flush();
+}
+
+$rs = new ADORecordSet_empty();
+foreach($rs as $v) {
+ echo "empty ";var_dump($v);
+}
+
+
+if ($i != $cnt) die("actual cnt is $i, cnt should be $cnt\n");
+else echo "Count $i is correct ";
+
+$rs = $db->Execute("select bad from badder");
+
+} catch (exception $e) {
+ adodb_pr($e);
+ echo "
adodb_backtrace: \n";
+ $e = adodb_backtrace($e->gettrace());
+}
+
+$rs = $db->Execute("select distinct id, firstname,lastname from adoxyz order by id");
+echo "Result=\n",$rs,"";
+
+echo "Active Record ";
+
+ include_once("../adodb-active-record.inc.php");
+ ADOdb_Active_Record::SetDatabaseAdapter($db);
+
+try {
+ class City extends ADOdb_Active_Record{};
+ $a = new City();
+
+} catch(exception $e){
+ echo $e->getMessage();
+}
+
+try {
+
+ $a = new City();
+
+ echo "Successfully created City() ";
+ #var_dump($a->GetPrimaryKeys());
+ $a->city = 'Kuala Lumpur';
+ $a->Save();
+ $a->Update();
+ #$a->SetPrimaryKeys(array('city'));
+ $a->country = "M'sia";
+ $a->save();
+ $a->Delete();
+} catch(exception $e){
+ echo $e->getMessage();
+}
+
+//include_once("test-active-record.php");
diff --git a/adodb/tests/test-xmlschema.php b/adodb/tests/test-xmlschema.php
new file mode 100644
index 0000000..e2d6dba
--- /dev/null
+++ b/adodb/tests/test-xmlschema.php
@@ -0,0 +1,70 @@
+Connect( 'localhost', 'root', '', 'test' ) || die('fail connect1');
+
+// To create a schema object and build the query array.
+$schema = new adoSchema( $db );
+
+// To upgrade an existing schema object, use the following
+// To upgrade an existing database to the provided schema,
+// uncomment the following line:
+#$schema->upgradeSchema();
+
+print "SQL to build xmlschema.xml :\n
";
+// Build the SQL array
+$sql = $schema->ParseSchema( "xmlschema.xml" );
+
+var_dump( $sql );
+print " \n";
+
+// Execute the SQL on the database
+//$result = $schema->ExecuteSchema( $sql );
+
+// Finally, clean up after the XML parser
+// (PHP won't do this for you!)
+//$schema->Destroy();
+
+
+
+print "SQL to build xmlschema-mssql.xml :\n";
+
+$db2 = ADONewConnection('mssql');
+$db2->Connect('','adodb','natsoft','northwind') || die("Fail 2");
+
+$db2->Execute("drop table simple_table");
+
+$schema = new adoSchema( $db2 );
+$sql = $schema->ParseSchema( "xmlschema-mssql.xml" );
+
+print_r( $sql );
+print " \n";
+
+$db2->debug=1;
+
+foreach ($sql as $s)
+$db2->Execute($s);
diff --git a/adodb/tests/test.php b/adodb/tests/test.php
new file mode 100644
index 0000000..fb23980
--- /dev/null
+++ b/adodb/tests/test.php
@@ -0,0 +1,1781 @@
+$msg ";
+ flush();
+}
+
+function CheckWS($conn)
+{
+ include_once('../session/adodb-session.php');
+ if (defined('CHECKWSFAIL')){ echo " TESTING $conn ";flush();}
+ $db = ADONewConnection($conn);
+ if (headers_sent()) {
+ print " White space detected in adodb-$conn.inc.php or include file...
";
+ //die();
+ }
+}
+
+function do_strtolower(&$arr)
+{
+ foreach($arr as $k => $v) {
+ if (is_object($v)) $arr[$k] = adodb_pr($v,true);
+ else $arr[$k] = strtolower($v);
+ }
+}
+
+
+function CountExecs($db, $sql, $inputarray)
+{
+global $EXECS; $EXECS++;
+}
+
+function CountCachedExecs($db, $secs2cache, $sql, $inputarray)
+{
+global $CACHED; $CACHED++;
+}
+
+// the table creation code is specific to the database, so we allow the user
+// to define their own table creation stuff
+
+function testdb(&$db,$createtab="create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)")
+{
+GLOBAL $ADODB_vers,$ADODB_CACHE_DIR,$ADODB_FETCH_MODE,$ADODB_COUNTRECS;
+
+ //adodb_pr($db);
+
+?>
+
+
+
+Execute('select lastname,firstname,lastname,id from ADOXYZ');
+ $arr = $rs->GetAssoc();
+ echo "";print_r($arr);
+ die();*/
+
+ if (!$db) die("testdb: database not inited");
+ GLOBAL $EXECS, $CACHED;
+
+ $EXECS = 0;
+ $CACHED = 0;
+ //$db->Execute("drop table adodb_logsql");
+ if ((rand()%3) == 0) @$db->Execute("delete from adodb_logsql");
+ $db->debug=1;
+
+ $db->fnExecute = 'CountExecs';
+ $db->fnCacheExecute = 'CountCachedExecs';
+
+ if (empty($_GET['nolog'])) {
+ echo "SQL Logging enabled ";
+ $db->LogSQL();/*
+ $sql =
+"SELECT t1.sid, t1.sid, t1.title, t1.hometext, t1.notes, t1.aid, t1.informant,
+t2.url, t2.email, t1.catid, t3.title, t1.topic, t4.topicname, t4.topicimage,
+t4.topictext, t1.score, t1.ratings, t1.counter, t1.comments, t1.acomm
+FROM `nuke_stories` `t1`, `nuke_authors` `t2`, `nuke_stories_cat` `t3`, `nuke_topics` `t4`
+ WHERE ((t2.aid=t1.aid) AND (t3.catid=t1.catid) AND (t4.topicid=t1.topic)
+ AND ((t1.alanguage='german') OR (t1.alanguage='')) AND (t1.ihome='0'))
+ ORDER BY t1.time DESC";
+ $db->SelectLimit($sql);
+ echo $db->ErrorMsg();*/
+ }
+ $ADODB_CACHE_DIR = dirname(TempNam('/tmp','testadodb'));
+ $db->debug = false;
+ //print $db->UnixTimeStamp('2003-7-22 23:00:00');
+
+ $phpv = phpversion();
+ print "ADODB Version: $ADODB_vers";
+ print " Host: $db->host ";
+ print " Database: $db->database ";
+ print " PHP: $phpv ";
+
+ flush();
+
+ print "Current timezone: " . date_default_timezone_get() . "
";
+
+ $arr = $db->ServerInfo();
+ print_r($arr);
+ echo E_ALL,' ',E_STRICT, " ";
+ $e = error_reporting(E_ALL | E_STRICT);
+ echo error_reporting(),'
';
+ flush();
+ #$db->debug=1;
+ $tt = $db->Time();
+ if ($tt == 0) echo '$db->Time failed ';
+ else echo " db->Time: ".date('d-m-Y H:i:s',$tt);
+ echo ' ';
+
+ echo "Date=",$db->UserDate('2002-04-07'),' ';
+ print "date1 (1969-02-20) = ".$db->DBDate('1969-2-20');
+ print "date1 (1999-02-20) = ".$db->DBDate('1999-2-20');
+ print "date1.1 1999 injection attack= ".$db->DBDate("'1999', ' injection attack '");
+ print "date2 (1970-1-2) = ".$db->DBDate(24*3600)."
";
+ print "ts1 (1999-02-20 13:40:50) = ".$db->DBTimeStamp('1999-2-20 1:40:50 pm');
+ print "ts1.1 (1999-02-20 13:40:00) = ".$db->DBTimeStamp('1999-2-20 13:40');
+ print "ts2 (1999-02-20) = ".$db->DBTimeStamp('1999-2-20');
+ print "ts2 (1999-02-20) = ".$db->DBTimeStamp("'1999-2-20', 'injection attack'");
+ print "ts3 (1970-1-2 +/- timezone) = ".$db->DBTimeStamp(24*3600);
+ print " Fractional TS (1999-2-20 13:40:50.91): ".$db->DBTimeStamp($db->UnixTimeStamp('1999-2-20 13:40:50.91+1'));
+ $dd = $db->UnixDate('1999-02-20');
+ print " unixdate 1999-02-20 = ".date('Y-m-d',$dd)."
";
+ print "ts4 =".($db->UnixTimeStamp("19700101000101")+8*3600);
+ print "ts5 =".$db->DBTimeStamp($db->UnixTimeStamp("20040110092123"));
+ print "ts6 =".$db->UserTimeStamp("20040110092123");
+ print "ts7 =".$db->DBTimeStamp("20040110092123");
+ flush();
+ // mssql too slow in failing bad connection
+ if (false && $db->databaseType != 'mssql') {
+ print "
Testing bad connection. Ignore following error msgs: ";
+ $db2 = ADONewConnection();
+ $rez = $db2->Connect("bad connection");
+ $err = $db2->ErrorMsg();
+ print "Error='$err'
";
+ if ($rez) print "Cannot check if connection failed. The Connect() function returned true.";
+ }
+ #error_reporting($e);
+ flush();
+
+ //$ADODB_COUNTRECS=false;
+ $rs=$db->Execute('select * from ADOXYZ order by id');
+ if($rs === false) $create = true;
+ else $rs->Close();
+
+ //if ($db->databaseType !='vfp') $db->Execute("drop table ADOXYZ");
+
+ if ($create) {
+ if (false && $db->databaseType == 'ibase') {
+ print "Please create the following table for testing: $createtab";
+ return;
+ } else {
+ $db->debug = 99;
+ # $e = error_reporting(E_ALL-E_WARNING);
+ $db->Execute($createtab);
+ # error_reporting($e);
+ }
+ }
+ #error_reporting(E_ALL);
+ echo "Testing Metatypes
";
+ $t = $db->MetaType('varchar');
+ if ($t != 'C') Err("Bad Metatype for varchar");
+
+ $rs = $db->Execute("delete from ADOXYZ"); // some ODBC drivers will fail the drop so we delete
+ if ($rs) {
+ if(! $rs->EOF) print "Error: RecordSet returned by Execute('delete...') should show EOF";
+ $rs->Close();
+ } else print "err=".$db->ErrorMsg();
+
+ print "Test select on empty table, FetchField when EOF, and GetInsertSQL
";
+ $rs = $db->Execute("select id,firstname from ADOXYZ where id=9999");
+ if ($rs && !$rs->EOF) print "Error: RecordSet returned by Execute(select...') on empty table should show EOF";
+ if ($rs->EOF && (($ox = $rs->FetchField(0)) && !empty($ox->name))) {
+ $record['id'] = 99;
+ $record['firstname'] = 'John';
+ $sql = $db->GetInsertSQL($rs, $record);
+ if (strtoupper($sql) != strtoupper("INSERT INTO ADOXYZ ( id, firstname ) VALUES ( 99, 'John' )")) Err("GetInsertSQL does not work on empty table: $sql");
+ } else {
+ Err("FetchField does not work on empty recordset, meaning GetInsertSQL will fail...");
+ }
+ if ($rs) $rs->Close();
+ flush();
+ //$db->debug=true;
+ print "Testing Commit: ";
+ $time = $db->DBDate(time());
+ if (!$db->BeginTrans()) {
+ print 'Transactions not supported
';
+ if ($db->hasTransactions) Err("hasTransactions should be false");
+ } else { /* COMMIT */
+ if (!$db->hasTransactions) Err("hasTransactions should be true");
+ if ($db->transCnt != 1) Err("Invalid transCnt = $db->transCnt (should be 1)");
+ $rs = $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values (99,'Should Not','Exist (Commit)',$time)");
+ if ($rs && $db->CommitTrans()) {
+ $rs->Close();
+ $rs = $db->Execute("select * from ADOXYZ where id=99");
+ if ($rs === false || $rs->EOF) {
+ print 'Data not saved ';
+ $rs = $db->Execute("select * from ADOXYZ where id=99");
+ print_r($rs);
+ die();
+ } else print 'OK';
+ if ($rs) $rs->Close();
+ } else {
+ if (!$rs) {
+ print "Insert failed ";
+ $db->RollbackTrans();
+ } else print "Commit failed ";
+ }
+ if ($db->transCnt != 0) Err("Invalid transCnt = $db->transCnt (should be 0)");
+
+ /* ROLLBACK */
+ if (!$db->BeginTrans()) print "Error in BeginTrans ()
";
+ print "Testing Rollback: ";
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values (100,'Should Not','Exist (Rollback)',$time)");
+ if ($db->RollbackTrans()) {
+ $rs = $db->Execute("select * from ADOXYZ where id=100");
+ if ($rs && !$rs->EOF) print 'Fail: Data should rollback
';
+ else print 'OK';
+ if ($rs) $rs->Close();
+ } else
+ print "Commit failed ";
+
+ $rs = $db->Execute('delete from ADOXYZ where id>50');
+ if ($rs) $rs->Close();
+
+ if ($db->transCnt != 0) Err("Invalid transCnt = $db->transCnt (should be 0)");
+ }
+
+ if (1) {
+ print "Testing MetaDatabases()
";
+ print_r( $db->MetaDatabases());
+
+ print "Testing MetaTables() and MetaColumns()
";
+ $a = $db->MetaTables();
+ if ($a===false) print "MetaTables not supported ";
+ else {
+ print "Array of tables and views: ";
+ foreach($a as $v) print " ($v) ";
+ print '';
+ }
+
+ $a = $db->MetaTables('VIEW');
+ if ($a===false) print "MetaTables not supported (views) ";
+ else {
+ print "Array of views: ";
+ foreach($a as $v) print " ($v) ";
+ print '';
+ }
+
+ $a = $db->MetaTables(false,false,'aDo%');
+ if ($a===false) print "MetaTables not supported (mask) ";
+ else {
+ print "Array of ado%: ";
+ foreach($a as $v) print " ($v) ";
+ print '';
+ }
+
+ $a = $db->MetaTables('TABLE');
+ if ($a===false) print "MetaTables not supported ";
+ else {
+ print "Array of tables: ";
+ foreach($a as $v) print " ($v) ";
+ print '';
+ }
+
+ $db->debug=0;
+ $rez = $db->MetaColumns("NOSUCHTABLEHERE");
+ if ($rez !== false) {
+ Err("MetaColumns error handling failed");
+ var_dump($rez);
+ }
+ $db->debug=1;
+ $a = $db->MetaColumns('ADOXYZ');
+ if ($a===false) print "MetaColumns not supported ";
+ else {
+ print "Columns of ADOXYZ: ";
+ foreach($a as $v) {print_r($v); echo " ";}
+ echo " ";
+ }
+
+ print "
Testing MetaIndexes
";
+
+ $a = $db->MetaIndexes(('ADOXYZ'),true);
+ if ($a===false) print "MetaIndexes not supported ";
+ else {
+ print "Indexes of ADOXYZ: ";
+ adodb_pr($a);
+ echo " ";
+ }
+ print "
Testing MetaPrimaryKeys
";
+ $a = $db->MetaPrimaryKeys('ADOXYZ');
+ var_dump($a);
+ }
+ $rs = $db->Execute('delete from ADOXYZ');
+ if ($rs) $rs->Close();
+
+ $db->debug = false;
+
+
+ switch ($db->databaseType) {
+ case 'vfp':
+
+ if (0) {
+ // memo test
+ $rs = $db->Execute("select data from memo");
+ rs2html($rs);
+ }
+ break;
+
+ case 'postgres7':
+ case 'postgres64':
+ case 'postgres':
+ case 'ibase':
+ print "Encode=".$db->BlobEncode("abc\0d\"'
+ef")."
";//'
+
+ print "Testing Foreign Keys
";
+ $arr = $db->MetaForeignKeys('ADOXYZ',false,true);
+ print_r($arr);
+ if (!$arr) Err("No MetaForeignKeys");
+ break;
+
+ case 'odbc_mssql':
+ case 'mssqlpo':
+ print "Testing Foreign Keys
";
+ $arr = $db->MetaForeignKeys('Orders',false,true);
+ print_r($arr);
+ if (!$arr) Err("Bad MetaForeignKeys");
+ if ($db->databaseType == 'odbc_mssql') break;
+
+ case 'mssql':
+
+
+/*
+ASSUME Northwind available...
+
+CREATE PROCEDURE SalesByCategory
+ @CategoryName nvarchar(15), @OrdYear nvarchar(4) = '1998'
+AS
+IF @OrdYear != '1996' AND @OrdYear != '1997' AND @OrdYear != '1998'
+BEGIN
+ SELECT @OrdYear = '1998'
+END
+
+SELECT ProductName,
+ TotalPurchase=ROUND(SUM(CONVERT(decimal(14,2), OD.Quantity * (1-OD.Discount) * OD.UnitPrice)), 0)
+FROM [Order Details] OD, Orders O, Products P, Categories C
+WHERE OD.OrderID = O.OrderID
+ AND OD.ProductID = P.ProductID
+ AND P.CategoryID = C.CategoryID
+ AND C.CategoryName = @CategoryName
+ AND SUBSTRING(CONVERT(nvarchar(22), O.OrderDate, 111), 1, 4) = @OrdYear
+GROUP BY ProductName
+ORDER BY ProductName
+GO
+
+
+CREATE PROCEDURE ADODBTestSP
+@a nvarchar(25)
+AS
+SELECT GETDATE() AS T, @a AS A
+GO
+*/
+ print "Testing Stored Procedures for mssql ";
+ $saved = $db->debug;
+ $db->debug=true;
+ $assoc = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $cmd = $db->PrepareSP('ADODBTestSP');
+ $ss = "You should see me in the output.";
+ $db->InParameter($cmd,$ss,'a');
+ $rs = $db->Execute($cmd);
+ #var_dump($rs->fields);
+ echo $rs->fields['T']." --- ".$rs->fields['A']."--- ";
+
+ $cat = 'Dairy Products';
+ $yr = '1998';
+
+ $stmt = $db->PrepareSP('SalesByCategory');
+ $db->InParameter($stmt,$cat,'CategoryName');
+ $db->InParameter($stmt,$yr,'OrdYear');
+ $rs = $db->Execute($stmt);
+ rs2html($rs);
+
+ $cat = 'Grains/Cereals';
+ $yr = 1998;
+
+ $stmt = $db->PrepareSP('SalesByCategory');
+ $db->InParameter($stmt,$cat,'CategoryName');
+ $db->InParameter($stmt,$yr,'OrdYear');
+ $rs = $db->Execute($stmt);
+ rs2html($rs);
+
+ $ADODB_FETCH_MODE = $assoc;
+
+ /*
+ Test out params - works in PHP 4.2.3 and 4.3.3 and 4.3.8 but not 4.3.0:
+
+ CREATE PROCEDURE at_date_interval
+ @days INTEGER,
+ @start VARCHAR(20) OUT,
+ @end VARCHAR(20) OUT
+ AS
+ BEGIN
+ set @start = CONVERT(VARCHAR(20), getdate(), 101)
+ set @end =CONVERT(VARCHAR(20), dateadd(day, @days, getdate()), 101 )
+ END
+ GO
+ */
+ $db->debug=1;
+ $stmt = $db->PrepareSP('at_date_interval');
+ $days = 10;
+ $begin_date = '';
+ $end_date = '';
+ $db->InParameter($stmt,$days,'days', 4, SQLINT4);
+ $db->OutParameter($stmt,$begin_date,'start', 20, SQLVARCHAR );
+ $db->OutParameter($stmt,$end_date,'end', 20, SQLVARCHAR );
+ $db->Execute($stmt);
+ if (empty($begin_date) or empty($end_date) or $begin_date == $end_date) {
+ Err("MSSQL SP Test for OUT Failed");
+ print "begin=$begin_date end=$end_date";
+ } else print "(Today +10days) = (begin=$begin_date end=$end_date)
";
+
+ $db->debug = $saved;
+ break;
+ case 'oci8':
+ case 'oci8po':
+
+ if (0) {
+ $t = getmicrotime();
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $arr = $db->GetArray('select * from abalone_tree');
+ $arr = $db->GetArray('select * from abalone_tree');
+ $arr = $db->GetArray('select * from abalone_tree');
+ echo "
t = ",getmicrotime() - $t,"
";
+ die();
+ }
+
+ # cleanup
+ $db->Execute("delete from photos where id=99 or id=1");
+ $db->Execute("insert into photos (id) values(1)");
+ $db->Execute("update photos set photo=null,descclob=null where id=1");
+
+ $saved = $db->debug;
+ $db->debug=true;
+
+
+
+ /*
+ CREATE TABLE PHOTOS
+ (
+ ID NUMBER(16) primary key,
+ PHOTO BLOB,
+ DESCRIPTION VARCHAR2(4000 BYTE),
+ DESCCLOB CLOB
+ );
+
+ INSERT INTO PHOTOS (ID) VALUES(1);
+ */
+ $s = '';
+ for ($i = 0; $i <= 500; $i++) {
+ $s .= '1234567890';
+ }
+
+ $sql = "INSERT INTO photos ( ID, photo) ".
+ "VALUES ( :id, empty_blob() )".
+ " RETURNING photo INTO :xx";
+
+
+ $blob_data = $s;
+ $id = 99;
+
+ $stmt = $db->PrepareSP($sql);
+ $db->InParameter($stmt, $id, 'id');
+ $blob = $db->InParameter($stmt, $s, 'xx',-1, OCI_B_BLOB);
+ $db->StartTrans();
+ $result = $db->Execute($stmt);
+ $db->CompleteTrans();
+
+ $s2= $db->GetOne("select photo from photos where id=99");
+ echo " ---$s2";
+ if ($s !== $s2) Err("insert blob does not match");
+
+ print "Testing Blob: size=".strlen($s)." ";
+ $ok = $db->Updateblob('photos','photo',$s,'id=1');
+ if (!$ok) Err("Blob failed 1");
+ else {
+ $s2= $db->GetOne("select photo from photos where id=1");
+ if ($s !== $s2) Err("updateblob does not match");
+ }
+
+ print "Testing Clob: size=".strlen($s)." ";
+ $ok = $db->UpdateClob('photos','descclob',$s,'id=1');
+ if (!$ok) Err("Clob failed 1");
+ else {
+ $s2= $db->GetOne("select descclob from photos where id=1");
+ if ($s !== $s2) Err("updateclob does not match");
+ }
+
+
+ $s = '';
+ $s2 = '';
+ print "Testing Foreign Keys ";
+ $arr = $db->MetaForeignKeys('emp','scott');
+ print_r($arr);
+ if (!$arr) Err("Bad MetaForeignKeys");
+/*
+-- TEST PACKAGE
+-- "Set scan off" turns off substitution variables.
+Set scan off;
+
+CREATE OR REPLACE PACKAGE Adodb AS
+TYPE TabType IS REF CURSOR RETURN TAB%ROWTYPE;
+PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames IN VARCHAR);
+PROCEDURE open_tab2 (tabcursor IN OUT TabType,tablenames IN OUT VARCHAR) ;
+PROCEDURE data_out(input IN VARCHAR, output OUT VARCHAR);
+PROCEDURE data_in(input IN VARCHAR);
+PROCEDURE myproc (p1 IN NUMBER, p2 OUT NUMBER);
+END Adodb;
+/
+
+
+CREATE OR REPLACE PACKAGE BODY Adodb AS
+PROCEDURE open_tab (tabcursor IN OUT TabType,tablenames IN VARCHAR) IS
+ BEGIN
+ OPEN tabcursor FOR SELECT * FROM TAB WHERE tname LIKE tablenames;
+ END open_tab;
+
+ PROCEDURE open_tab2 (tabcursor IN OUT TabType,tablenames IN OUT VARCHAR) IS
+ BEGIN
+ OPEN tabcursor FOR SELECT * FROM TAB WHERE tname LIKE tablenames;
+ tablenames := 'TEST';
+ END open_tab2;
+
+PROCEDURE data_out(input IN VARCHAR, output OUT VARCHAR) IS
+ BEGIN
+ output := 'Cinta Hati '||input;
+ END;
+
+PROCEDURE data_in(input IN VARCHAR) IS
+ ignore varchar(1000);
+ BEGIN
+ ignore := input;
+ END;
+
+PROCEDURE myproc (p1 IN NUMBER, p2 OUT NUMBER) AS
+BEGIN
+p2 := p1;
+END;
+END Adodb;
+/
+
+*/
+
+ print "Testing Cursor Variables ";
+ $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:zz,'A%'); END;",'zz');
+
+ if ($rs && !$rs->EOF) {
+ $v = $db->GetOne("SELECT count(*) FROM tab where tname like 'A%'");
+ if ($v == $rs->RecordCount()) print "Test 1 RowCount: OK";
+ else Err("Test 1 RowCount ".$rs->RecordCount().", actual = $v");
+ } else {
+ print "Error in using Cursor Variables 1
";
+ }
+ if ($rs) $rs->Close();
+
+ print "
Testing Stored Procedures for oci8 ";
+
+ $stmt = $db->PrepareSP("BEGIN adodb.data_out(:a1, :a2); END;");
+ $a1 = 'Malaysia';
+ //$a2 = ''; # a2 doesn't even need to be defined!
+ $db->InParameter($stmt,$a1,'a1');
+ $db->OutParameter($stmt,$a2,'a2');
+ $rs = $db->Execute($stmt);
+ if ($rs) {
+ if ($a2 !== 'Cinta Hati Malaysia') print "Stored Procedure Error: a2 = $a2 ";
+ else echo "OK: a2=$a2
";
+ } else {
+ print "Error in using Stored Procedure IN/Out Variables
";
+ }
+
+ $tname = 'A%';
+
+ $stmt = $db->PrepareSP('select * from tab where tname like :tablename');
+ $db->Parameter($stmt,$tname,'tablename');
+ $rs = $db->Execute($stmt);
+ rs2html($rs);
+
+ $stmt = $db->PrepareSP("begin adodb.data_in(:a1); end;");
+ $db->InParameter($stmt,$a1,'a1');
+ $db->Execute($stmt);
+
+ $db->debug = $saved;
+ break;
+
+ default:
+ break;
+ }
+ $arr = array(
+ array(1,'Caroline','Miranda'),
+ array(2,'John','Lim'),
+ array(3,'Wai Hun','See')
+ );
+ //$db->debug=1;
+ print "
Testing Bulk Insert of 3 rows
";
+
+// $db->debug=1;
+// $db->Execute('select * from table where val=? AND value=?', array('val'=>'http ://www.whatever.com/test?=21', 'value'=>'blabl'));
+
+
+ $sql = "insert into ADOXYZ (id,firstname,lastname) values (".$db->Param('0').",".$db->Param('1').",".$db->Param('2').")";
+ $db->bulkBind = true;
+ $db->StartTrans();
+ $db->debug=99;
+ $db->Execute($sql,$arr);
+ $db->CompleteTrans();
+ $db->bulkBind = false;
+ $rs = $db->Execute('select * from ADOXYZ order by id');
+ if (!$rs || $rs->RecordCount() != 3) Err("Bad bulk insert");
+
+ rs2html($rs);
+
+ $db->Execute('delete from ADOXYZ');
+
+ print "Inserting 50 rows
";
+
+ for ($i = 0; $i < 5; $i++) {
+
+ $time = $db->DBDate(time());
+ if (empty($_GET['hide'])) $db->debug = true;
+ switch($db->databaseType){
+ case 'mssqlpo':
+ case 'mssql':
+ $sqlt = "CREATE TABLE mytable (
+ row1 INT IDENTITY(1,1) NOT NULL,
+ row2 varchar(16),
+ PRIMARY KEY (row1))";
+ //$db->debug=1;
+ if (!$db->Execute("delete from mytable"))
+ $db->Execute($sqlt);
+
+ $ok = $db->Execute("insert into mytable (row2) values ('test')");
+ $ins_id=$db->Insert_ID();
+ echo "Insert ID=";var_dump($ins_id);
+ if ($ins_id == 0) Err("Bad Insert_ID()");
+ $ins_id2 = $db->GetOne("select row1 from mytable");
+ if ($ins_id != $ins_id2) Err("Bad Insert_ID() 2");
+
+ $arr = array(0=>'Caroline',1=>'Miranda');
+ $sql = "insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+0,?,?,$time)";
+ break;
+ case 'mysqli':
+ case 'mysqlt':
+ case 'mysql':
+ $sqlt = "CREATE TABLE `mytable` (
+ `row1` int(11) NOT NULL auto_increment,
+ `row2` varchar(16) NOT NULL default '',
+ PRIMARY KEY (`row1`),
+ KEY `myindex` (`row1`,`row2`)
+) ";
+ if (!$db->Execute("delete from mytable"))
+ $db->Execute($sqlt);
+
+ $ok = $db->Execute("insert into mytable (row2) values ('test')");
+ $ins_id=$db->Insert_ID();
+ echo "Insert ID=";var_dump($ins_id);
+ if ($ins_id == 0) Err("Bad Insert_ID()");
+ $ins_id2 = $db->GetOne("select row1 from mytable");
+ if ($ins_id != $ins_id2) Err("Bad Insert_ID() 2");
+
+ default:
+ $arr = array(0=>'Caroline',1=>'Miranda');
+ $sql = "insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+0,?,?,$time)";
+ break;
+
+ case 'oci8':
+ case 'oci805':
+ $arr = array('first'=>'Caroline','last'=>'Miranda');
+ $amt = rand() % 100;
+ $sql = "insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+0,:first,:last,$time)";
+ break;
+ }
+ if ($i & 1) {
+ $sql = $db->Prepare($sql);
+ }
+ $rs = $db->Execute($sql,$arr);
+
+ if ($rs === false) Err( 'Error inserting with parameters');
+ else $rs->Close();
+ $db->debug = false;
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+1,'John','Lim',$time)");
+ /*$ins_id=$db->Insert_ID();
+ echo "Insert ID=";var_dump($ins_id);*/
+ if ($db->databaseType == 'mysql') if ($ins_id == 0) Err('Bad Insert_ID');
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+2,'Mary','Lamb',$time )");
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+3,'George','Washington',$time )");
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+4,'Mr. Alan','Tam',$time )");
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+5,'Alan',".$db->quote("Turing'ton").",$time )");
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created)values ($i*10+6,'Serena','Williams',$time )");
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+7,'Yat Sun','Sun',$time )");
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+8,'Wai Hun','See',$time )");
+ $db->Execute("insert into ADOXYZ (id,firstname,lastname,created) values ($i*10+9,'Steven','Oey',$time )");
+ } // for
+ if (1) {
+ $db->debug=1;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $cnt = $db->GetOne("select count(*) from ADOXYZ");
+ $rs = $db->Execute('update ADOXYZ set id=id+1');
+ if (!is_object($rs)) {
+ print_r($rs);
+ err("Update should return object");
+ }
+ if (!$rs) err("Update generated error");
+
+ $nrows = $db->Affected_Rows();
+ if ($nrows === false) print "Affected_Rows() not supported
";
+ else if ($nrows != $cnt) print "Affected_Rows() Error: $nrows returned (should be 50)
";
+ else print "Affected_Rows() passed
";
+ }
+
+ if ($db->dataProvider == 'oci8') $array = array('zid'=>1,'zdate'=>date('Y-m-d',time()));
+ else $array=array(1,date('Y-m-d',time()));
+
+
+ #$array = array(1,date('Y-m-d',time()));
+ $id = $db->GetOne("select id from ADOXYZ
+ where id=".$db->Param('zid')." and created>=".$db->Param('ZDATE')."",
+ $array);
+ if ($id != 1) Err("Bad bind; id=$id");
+ else echo " Bind date/integer 1 passed";
+
+ $array =array(1,$db->BindDate(time()));
+ $id = $db->GetOne("select id from ADOXYZ
+ where id=".$db->Param('0')." and created>=".$db->Param('1')."",
+ $array);
+ if ($id != 1) Err("Bad bind; id=$id");
+ else echo " Bind date/integer 2 passed";
+
+ $db->debug = false;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ $rs = $db->Execute("select * from ADOXYZ where firstname = 'not known'");
+ if (!$rs || !$rs->EOF) print "Error on empty recordset
";
+ else if ($rs->RecordCount() != 0) {
+ print "Error on RecordCount. Should be 0. Was ".$rs->RecordCount()."
";
+ print_r($rs->fields);
+ }
+ if ($db->databaseType !== 'odbc') {
+ $rs = $db->Execute("select id,firstname,lastname,created,".$db->random." from ADOXYZ order by id");
+ if ($rs) {
+ if ($rs->RecordCount() != 50) {
+ print "RecordCount returns ".$rs->RecordCount().", should be 50
";
+ adodb_pr($rs->GetArray());
+ $poc = $rs->PO_RecordCount('ADOXYZ');
+ if ($poc == 50) print " PO_RecordCount passed
";
+ else print "PO_RecordCount returns wrong value: $poc
";
+ } else print "RecordCount() passed
";
+ if (isset($rs->fields['firstname'])) print 'The fields columns can be indexed by column name.
';
+ else {
+ Err( 'The fields columns cannot be indexed by column name.
');
+ print_r($rs->fields);
+ }
+ if (empty($_GET['hide'])) rs2html($rs);
+ }
+ else print "Error in Execute of SELECT with random
";
+ }
+ $val = $db->GetOne("select count(*) from ADOXYZ");
+ if ($val == 50) print "GetOne returns ok
";
+ else print "Fail: GetOne returns $val
";
+
+ echo "GetRow Test ";
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $val1 = $db->GetRow("select count(*) from ADOXYZ");
+ $val2 = $db->GetRow("select count(*) from ADOXYZ");
+ if ($val1[0] == 50 and sizeof($val1) == 1 and $val2[0] == 50 and sizeof($val2) == 1) print "GetRow returns ok
";
+ else {
+ print_r($val);
+ print "Fail: GetRow returns {$val2[0]}
";
+ }
+
+ print "FetchObject/FetchNextObject Test
";
+ $rs = $db->Execute('select * from ADOXYZ');
+ if ($rs) {
+ if (empty($rs->connection)) print "Connection object missing from recordset ";
+
+ while ($o = $rs->FetchNextObject()) { // calls FetchObject internally
+ if (!is_string($o->FIRSTNAME) || !is_string($o->LASTNAME)) {
+ print_r($o);
+ print "Firstname is not string
";
+ break;
+ }
+ }
+ } else {
+ print "Failed rs
";
+ die("ADOXYZ table cannot be read - die()");
+ }
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ print "
FetchObject/FetchNextObject Test 2
";
+ #$db->debug=99;
+ $rs = $db->Execute('select * from ADOXYZ');
+ if (empty($rs->connection)) print "Connection object missing from recordset ";
+ print_r($rs->fields);
+ while ($o = $rs->FetchNextObject()) { // calls FetchObject internally
+ if (!is_string($o->FIRSTNAME) || !is_string($o->LASTNAME)) {
+ print_r($o);
+ print "Firstname is not string
";
+ break;
+ }
+ }
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ $savefetch = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+
+ print "CacheSelectLimit Test...
";
+ $rs = $db->CacheSelectLimit('select id, firstname from ADOXYZ order by id',2);
+
+ if (ADODB_ASSOC_CASE == 2 || $db->dataProvider == 'oci8') {
+ $id = 'ID';
+ $fname = 'FIRSTNAME';
+ }else {
+ $id = 'id';
+ $fname = 'firstname';
+ }
+
+
+ if ($rs && !$rs->EOF) {
+ if (isset($rs->fields[0])) {
+ Err("ASSOC has numeric fields");
+ print_r($rs->fields);
+ }
+ if ($rs->fields[$id] != 1) {Err("Error"); print_r($rs->fields);};
+ if (trim($rs->fields[$fname]) != 'Caroline') {print Err("Error 2"); print_r($rs->fields);};
+
+ $rs->MoveNext();
+ if ($rs->fields[$id] != 2) {Err("Error 3"); print_r($rs->fields);};
+ $rs->MoveNext();
+ if (!$rs->EOF) {
+ Err("Error EOF");
+ print_r($rs);
+ }
+ }
+
+ print "FETCH_MODE = ASSOC: Should get 1, Caroline ASSOC_CASE=".ADODB_ASSOC_CASE."
";
+ $rs = $db->SelectLimit('select id,firstname from ADOXYZ order by id',2);
+ if ($rs && !$rs->EOF) {
+
+ if ($rs->fields[$id] != 1) {Err("Error 1"); print_r($rs->fields);};
+ if (trim($rs->fields[$fname]) != 'Caroline') {Err("Error 2"); print_r($rs->fields);};
+ $rs->MoveNext();
+ if ($rs->fields[$id] != 2) {Err("Error 3"); print_r($rs->fields);};
+ $rs->MoveNext();
+ if (!$rs->EOF) Err("Error EOF");
+ else if (is_array($rs->fields) || $rs->fields) {
+ Err("Error: ## fields should be set to false on EOF");
+ print_r($rs->fields);
+ }
+ }
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ print "FETCH_MODE = NUM: Should get 1, Caroline
";
+ $rs = $db->SelectLimit('select id,firstname from ADOXYZ order by id',1);
+ if ($rs && !$rs->EOF) {
+ if (isset($rs->fields[$id])) Err("FETCH_NUM has ASSOC fields");
+ if ($rs->fields[0] != 1) {Err("Error 1"); print_r($rs->fields);};
+ if (trim($rs->fields[1]) != 'Caroline') {Err("Error 2");print_r($rs->fields);};
+ $rs->MoveNext();
+ if (!$rs->EOF) Err("Error EOF");
+
+ }
+ $ADODB_FETCH_MODE = $savefetch;
+
+ $db->debug = false;
+ print "GetRowAssoc Upper: Should get 1, Caroline
";
+ $rs = $db->SelectLimit('select id,firstname from ADOXYZ order by id',1);
+ if ($rs && !$rs->EOF) {
+ $arr = $rs->GetRowAssoc(ADODB_ASSOC_CASE_UPPER);
+
+ if ($arr[strtoupper($id)] != 1) {Err("Error 1");print_r($arr);};
+ if (trim($arr[strtoupper($fname)]) != 'Caroline') {Err("Error 2"); print_r($arr);};
+ $rs->MoveNext();
+ if (!$rs->EOF) Err("Error EOF");
+
+ }
+ print "GetRowAssoc Lower: Should get 1, Caroline
";
+ $rs = $db->SelectLimit('select id,firstname from ADOXYZ order by id',1);
+ if ($rs && !$rs->EOF) {
+ $arr = $rs->GetRowAssoc(ADODB_ASSOC_CASE_LOWER);
+ if ($arr['id'] != 1) {Err("Error 1"); print_r($arr);};
+ if (trim($arr['firstname']) != 'Caroline') {Err("Error 2"); print_r($arr);};
+
+ }
+
+ print "GetCol Test
";
+ $col = $db->GetCol('select distinct firstname from ADOXYZ order by 1');
+ if (!is_array($col)) Err("Col size is wrong");
+ if (trim($col[0]) != 'Alan' or trim($col[9]) != 'Yat Sun') Err("Col elements wrong");
+
+
+ $col = $db->CacheGetCol('select distinct firstname from ADOXYZ order by 1');
+ if (!is_array($col)) Err("Col size is wrong");
+ if (trim($col[0]) != 'Alan' or trim($col[9]) != 'Yat Sun') Err("Col elements wrong");
+
+ $db->debug = true;
+
+
+ echo "Date Update Test
";
+ $zdate = date('Y-m-d',time()+3600*24);
+ $zdate = $db->DBDate($zdate);
+ $db->Execute("update ADOXYZ set created=$zdate where id=1");
+ $row = $db->GetRow("select created,firstname from ADOXYZ where id=1");
+ print_r($row); echo " ";
+
+
+
+ print "SelectLimit Distinct Test 1: Should see Caroline, John and Mary
";
+ $rs = $db->SelectLimit('select distinct * from ADOXYZ order by id',3);
+
+
+ if ($rs && !$rs->EOF) {
+ if (trim($rs->fields[1]) != 'Caroline') Err("Error 1 (exp Caroline), ".$rs->fields[1]);
+ $rs->MoveNext();
+
+ if (trim($rs->fields[1]) != 'John') Err("Error 2 (exp John), ".$rs->fields[1]);
+ $rs->MoveNext();
+ if (trim($rs->fields[1]) != 'Mary') Err("Error 3 (exp Mary),".$rs->fields[1]);
+ $rs->MoveNext();
+ if (! $rs->EOF) Err("Error EOF");
+ //rs2html($rs);
+ } else Err("Failed SelectLimit Test 1");
+
+ print "SelectLimit Test 2: Should see Mary, George and Mr. Alan
";
+ $rs = $db->SelectLimit('select * from ADOXYZ order by id',3,2);
+ if ($rs && !$rs->EOF) {
+ if (trim($rs->fields[1]) != 'Mary') Err("Error 1 - No Mary, instead: ".$rs->fields[1]);
+ $rs->MoveNext();
+ if (trim($rs->fields[1]) != 'George')Err("Error 2 - No George, instead: ".$rs->fields[1]);
+ $rs->MoveNext();
+ if (trim($rs->fields[1]) != 'Mr. Alan') Err("Error 3 - No Mr. Alan, instead: ".$rs->fields[1]);
+ $rs->MoveNext();
+ if (! $rs->EOF) Err("Error EOF");
+ // rs2html($rs);
+ }
+ else Err("Failed SelectLimit Test 2 ". ($rs ? 'EOF':'no RS'));
+
+ print "SelectLimit Test 3: Should see Wai Hun and Steven
";
+ $db->debug=1;
+ global $A; $A=1;
+ $rs = $db->SelectLimit('select * from ADOXYZ order by id',-1,48);
+ $A=0;
+ if ($rs && !$rs->EOF) {
+ if (empty($rs->connection)) print "Connection object missing from recordset ";
+ if (trim($rs->fields[1]) != 'Wai Hun') Err("Error 1 ".$rs->fields[1]);
+ $rs->MoveNext();
+ if (trim($rs->fields[1]) != 'Steven') Err("Error 2 ".$rs->fields[1]);
+ $rs->MoveNext();
+ if (! $rs->EOF) {
+ Err("Error EOF");
+ }
+ //rs2html($rs);
+ }
+ else Err("Failed SelectLimit Test 3");
+ $db->debug = false;
+
+
+ $rs = $db->Execute("select * from ADOXYZ order by id");
+ print "Testing Move()
";
+ if (!$rs)Err( "Failed Move SELECT");
+ else {
+ if (!$rs->Move(2)) {
+ if (!$rs->canSeek) print "$db->databaseType: Move(), MoveFirst() nor MoveLast() not supported.
";
+ else print 'RecordSet->canSeek property should be set to false
';
+ } else {
+ $rs->MoveFirst();
+ if (trim($rs->Fields("firstname")) != 'Caroline') {
+ print "$db->databaseType: MoveFirst failed -- probably cannot scroll backwards
";
+ }
+ else print "MoveFirst() OK ";
+
+ // Move(3) tests error handling -- MoveFirst should not move cursor
+ $rs->Move(3);
+ if (trim($rs->Fields("firstname")) != 'George') {
+ print ''.$rs->Fields("id")."$db->databaseType: Move(3) failed
";
+ } else print "Move(3) OK ";
+
+ $rs->Move(7);
+ if (trim($rs->Fields("firstname")) != 'Yat Sun') {
+ print ''.$rs->Fields("id")."$db->databaseType: Move(7) failed
";
+ print_r($rs);
+ } else print "Move(7) OK ";
+ if ($rs->EOF) Err("Move(7) is EOF already");
+ $rs->MoveLast();
+ if (trim($rs->Fields("firstname")) != 'Steven'){
+ print ''.$rs->Fields("id")."$db->databaseType: MoveLast() failed
";
+ print_r($rs);
+ }else print "MoveLast() OK ";
+ $rs->MoveNext();
+ if (!$rs->EOF) err("Bad MoveNext");
+ if ($rs->canSeek) {
+ $rs->Move(3);
+ if (trim($rs->Fields("firstname")) != 'George') {
+ print ''.$rs->Fields("id")."$db->databaseType: Move(3) after MoveLast failed
";
+
+ } else print "Move(3) after MoveLast() OK ";
+ }
+
+ print "Empty Move Test";
+ $rs = $db->Execute("select * from ADOXYZ where id > 0 and id < 0");
+ $rs->MoveFirst();
+ if (!$rs->EOF || $rs->fields) Err("Error in empty move first");
+ }
+ }
+
+ $rs = $db->Execute('select * from ADOXYZ where id = 2');
+ if ($rs->EOF || !is_array($rs->fields)) Err("Error in select");
+ $rs->MoveNext();
+ if (!$rs->EOF) Err("Error in EOF (xx) ");
+ // $db->debug=true;
+ print "
Testing ADODB_FETCH_ASSOC and concat: concat firstname and lastname
";
+
+ $save = $ADODB_FETCH_MODE;
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ if ($db->dataProvider == 'postgres') {
+ $sql = "select ".$db->Concat('cast(firstname as varchar)',$db->qstr(' '),'lastname')." as fullname,id,".$db->sysTimeStamp." as d from ADOXYZ";
+ $rs = $db->Execute($sql);
+ } else {
+ $sql = "select distinct ".$db->Concat('firstname',$db->qstr(' '),'lastname')." as fullname,id,".$db->sysTimeStamp." as d from ADOXYZ";
+ $rs = $db->Execute($sql);
+ }
+ if ($rs) {
+ if (empty($_GET['hide'])) rs2html($rs);
+ } else {
+ Err( "Failed Concat:".$sql);
+ }
+ $ADODB_FETCH_MODE = $save;
+ print " Testing GetArray() ";
+ //$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+
+ $rs = $db->Execute("select * from ADOXYZ order by id");
+ if ($rs) {
+ $arr = $rs->GetArray(10);
+ if (sizeof($arr) != 10 || trim($arr[1][1]) != 'John' || trim($arr[1][2]) != 'Lim') print $arr[1][1].' '.$arr[1][2]." ERROR ";
+ else print " OK ";
+ }
+
+ $arr = $db->GetArray("select x from ADOXYZ");
+ $e = $db->ErrorMsg(); $e2 = $db->ErrorNo();
+ echo "Testing error handling, should see illegal column 'x' error=$e ($e2) ";
+ if (!$e || !$e2) Err("Error handling did not work");
+ print "Testing FetchNextObject for 1 object ";
+ $rs = $db->Execute("select distinct lastname,firstname from ADOXYZ where firstname='Caroline'");
+ $fcnt = 0;
+ if ($rs)
+ while ($o = $rs->FetchNextObject()) {
+ $fcnt += 1;
+ }
+ if ($fcnt == 1) print " OK ";
+ else print "FAILED ";
+
+ $stmt = $db->Prepare("select * from ADOXYZ where id < 3");
+ $rs = $db->Execute($stmt);
+ if (!$rs) Err("Prepare failed");
+ else {
+ $arr = $rs->GetArray();
+ if (!$arr) Err("Prepare failed 2");
+ if (sizeof($arr) != 2) Err("Prepare failed 3");
+ }
+ print "Testing GetAssoc() ";
+
+
+ if ($db->dataProvider == 'mysql') {
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $arr = $db->GetAssoc("SELECT 'adodb', '0'");
+ var_dump($arr);
+ die();
+ }
+
+ $savecrecs = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = false;
+ //$arr = $db->GetArray("select lastname,firstname from ADOXYZ");
+ //print_r($arr);
+ print " ";
+ $rs = $db->Execute("select distinct lastname,firstname,created from ADOXYZ");
+
+ if ($rs) {
+ $arr = $rs->GetAssoc();
+ //print_r($arr);
+ if (empty($arr['See']) || trim(reset($arr['See'])) != 'Wai Hun') print $arr['See']." ERROR ";
+ else print " OK 1";
+ }
+
+ $arr = $db->GetAssoc("select distinct lastname,firstname from ADOXYZ");
+ if ($arr) {
+ //print_r($arr);
+ if (empty($arr['See']) || trim($arr['See']) != 'Wai Hun') print $arr['See']." ERROR ";
+ else print " OK 2 ";
+ }
+ // Comment this out to test countrecs = false
+ $ADODB_COUNTRECS = $savecrecs;
+ $db->debug=1;
+ $query = $db->Prepare("select count(*) from ADOXYZ");
+ $rs = $db->CacheExecute(10,$query);
+ if (reset($rs->fields) != 50) echo Err("$cnt wrong for Prepare/CacheGetOne");
+
+ for ($loop=0; $loop < 1; $loop++) {
+ print "Testing GetMenu() and CacheExecute ";
+ $db->debug = true;
+ $rs = $db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+
+
+
+
+ if ($rs) print 'With blanks, Steven selected:'. $rs->GetMenu('menu','Steven').' ';
+ else print " Fail ";
+ $rs = $db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+
+ if ($rs) print ' No blanks, Steven selected: '. $rs->GetMenu('menu','Steven',false).' ';
+ else print " Fail ";
+
+ $rs = $db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+
+ if ($rs) print ' 1st line set to **** , Steven selected: '. $rs->GetMenu('menu','Steven','1st:****').' ';
+ else print " Fail ";
+
+
+
+ $rs = $db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+ if ($rs) print ' Multiple, Alan selected: '. $rs->GetMenu('menu','Alan',false,true).' ';
+ else print " Fail ";
+ print ' ';
+
+ $rs = $db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+ if ($rs) {
+ print ' Multiple, Alan and George selected: '. $rs->GetMenu('menu',array('Alan','George'),false,true);
+ if (empty($rs->connection)) print "Connection object missing from recordset ";
+ } else print " Fail ";
+ print ' ';
+
+ print "Testing GetMenu3() ";
+ $rs = $db->Execute("select ".$db->Concat('firstname',"'-'",'id').",id, lastname from ADOXYZ order by lastname,id");
+ if ($rs) print "Grouped Menu: ".$rs->GetMenu3('name');
+ else Err('Grouped Menu GetMenu3()');
+ print " ";
+
+ print "Testing GetMenu2() ";
+ $rs = $db->CacheExecute(4,"select distinct firstname,lastname from ADOXYZ");
+ if ($rs) print 'With blanks, Steven selected:'. $rs->GetMenu2('menu',('Oey')).' ';
+ else print " Fail ";
+ $rs = $db->CacheExecute(6,"select distinct firstname,lastname from ADOXYZ");
+ if ($rs) print ' No blanks, Steven selected: '. $rs->GetMenu2('menu',('Oey'),false).' ';
+ else print " Fail ";
+ }
+ echo "CacheExecute ";
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs = $db->CacheExecute(6,"select distinct firstname,lastname from ADOXYZ");
+ print_r($rs->fields); echo $rs->fetchMode;echo " ";
+ echo $rs->Fields($fname);
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $rs = $db->CacheExecute(6,"select distinct firstname,lastname from ADOXYZ");
+ print_r($rs->fields);echo " ";
+ echo $rs->Fields($fname);
+ $db->debug = false;
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ // phplens
+
+ $sql = 'select * from ADOXYZ where 0=1';
+ echo "**Testing '$sql' (phplens compat 1)
";
+ $rs = $db->Execute($sql);
+ if (!$rs) err( "No recordset returned for '$sql' ");
+ if (!$rs->FieldCount()) err( "No fields returned for $sql ");
+ if (!$rs->FetchField(1)) err( "FetchField failed for $sql ");
+
+ $sql = 'select * from ADOXYZ order by 1';
+ echo "**Testing '$sql' (phplens compat 2)
";
+ $rs = $db->Execute($sql);
+ if (!$rs) err( "No recordset returned for '$sql' ".$db->ErrorMsg()." ");
+
+
+ $sql = 'select * from ADOXYZ order by 1,1';
+ echo "**Testing '$sql' (phplens compat 3)
";
+ $rs = $db->Execute($sql);
+ if (!$rs) err( "No recordset returned for '$sql' ".$db->ErrorMsg()." ");
+
+
+ // Move
+ $rs1 = $db->Execute("select id from ADOXYZ where id <= 2 order by 1");
+ $rs2 = $db->Execute("select id from ADOXYZ where id = 3 or id = 4 order by 1");
+
+ if ($rs1) $rs1->MoveLast();
+ if ($rs2) $rs2->MoveLast();
+
+ if (empty($rs1) || empty($rs2) || $rs1->fields[0] != 2 || $rs2->fields[0] != 4) {
+ $a = $rs1->fields[0];
+ $b = $rs2->fields[0];
+ print "Error in multiple recordset test rs1=$a rs2=$b (should be rs1=2 rs2=4)
";
+ } else
+ print "Testing multiple recordsets OK
";
+
+
+ echo " GenID test: ";
+ for ($i=1; $i <= 10; $i++)
+ echo "($i: ",$val = $db->GenID($db->databaseType.'abcseq7' ,5), ") ";
+ if ($val == 0) Err("GenID not supported");
+
+ if ($val) {
+ $db->DropSequence('abc_seq2');
+ $db->CreateSequence('abc_seq2');
+ $val = $db->GenID('abc_seq2');
+ $db->DropSequence('abc_seq2');
+ $db->CreateSequence('abc_seq2');
+ $val = $db->GenID('abc_seq2');
+ if ($val != 1) Err("Drop and Create Sequence not supported ($val)");
+ }
+ echo "
";
+
+ if (substr($db->dataProvider,0,3) != 'notused') { // used to crash ado
+ $sql = "select firstnames from ADOXYZ";
+ print "
Testing execution of illegal statement: $sql
";
+ if ($db->Execute($sql) === false) {
+ print "This returns the following ErrorMsg(): ".$db->ErrorMsg()." and ErrorNo(): ".$db->ErrorNo().'
';
+ } else
+ print "Error in error handling -- Execute() should return false
";
+ } else
+ print "ADO skipped error handling of bad select statement
";
+
+ print "ASSOC TEST 2 ";
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $rs = $db->query('select * from ADOXYZ order by id');
+ if ($ee = $db->ErrorMsg()) {
+ Err("Error message=$ee");
+ }
+ if ($ee = $db->ErrorNo()) {
+ Err("Error No = $ee");
+ }
+ print_r($rs->fields);
+ for($i=0;$i<$rs->FieldCount();$i++)
+ {
+ $fld=$rs->FetchField($i);
+ print " Field name is ".$fld->name;
+ print " ".$rs->Fields($fld->name);
+ }
+
+
+ print "
BOTH TEST 2 ";
+ if ($db->dataProvider == 'ado') {
+ print "ADODB_FETCH_BOTH not supported for dataProvider=".$db->dataProvider." ";
+ } else {
+ $ADODB_FETCH_MODE = ADODB_FETCH_BOTH;
+ $rs = $db->query('select * from ADOXYZ order by id');
+ for($i=0;$i<$rs->FieldCount();$i++)
+ {
+ $fld=$rs->FetchField($i);
+ print " Field name is ".$fld->name;
+ print " ".$rs->Fields($fld->name);
+ }
+ }
+
+ print "
NUM TEST 2 ";
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs = $db->query('select * from ADOXYZ order by id');
+ for($i=0;$i<$rs->FieldCount();$i++)
+ {
+ $fld=$rs->FetchField($i);
+ print " Field name is ".$fld->name;
+ print " ".$rs->Fields($fld->name);
+ }
+
+ print "
ASSOC Test of SelectLimit ";
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $rs = $db->selectlimit('select * from ADOXYZ order by id',3,4);
+ $cnt = 0;
+ while ($rs && !$rs->EOF) {
+ $cnt += 1;
+ if (!isset($rs->fields['firstname'])) {
+ print "ASSOC returned numeric field
";
+ break;
+ }
+ $rs->MoveNext();
+ }
+ if ($cnt != 3) print "Count should be 3, instead it was $cnt ";
+
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ if ($db->sysDate) {
+ $saved = $db->debug;
+ $db->debug = 1;
+ $rs = $db->Execute("select {$db->sysDate} from ADOXYZ where id=1");
+ if (ADORecordSet::UnixDate(date('Y-m-d')) != $rs->UnixDate($rs->fields[0])) {
+ print "Invalid date {$rs->fields[0]}
";
+ } else
+ print "Passed \$sysDate test ({$rs->fields[0]})
";
+
+ print_r($rs->FetchField(0));
+ print time();
+ $db->debug=$saved;
+ } else {
+ print "\$db->sysDate not defined
";
+ }
+
+ print "Test CSV
";
+ include_once('../toexport.inc.php');
+ //$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $rs = $db->SelectLimit('select id,firstname,lastname,created,\'He, he\' he,\'"\' q from ADOXYZ',10);
+
+ print "";
+ print rs2csv($rs);
+ print " ";
+
+ $rs = $db->SelectLimit('select id,firstname,lastname,created,\'The "young man", he said\' from ADOXYZ',10);
+
+ #print " CacheFlush ";
+ #$db->CacheFlush();
+
+ $date = $db->SQLDate('d-m-M-Y-\QQ h:i:s A');
+ $sql = "SELECT $date from ADOXYZ";
+ print "Test SQLDate: ".htmlspecialchars($sql)."
";
+ $rs = $db->SelectLimit($sql,1);
+ $d = date('d-m-M-Y-').'Q'.(ceil(date('m')/3.0)).date(' h:i:s A');
+ if (!$rs) Err("SQLDate query returned no recordset");
+ else if ($d != $rs->fields[0]) Err("SQLDate 1 failed expected: act:$d sql:".$rs->fields[0]);
+
+ $dbdate = $db->DBDate("1974-02-25");
+ if (substr($db->dataProvider, 0, 8) == 'postgres') {
+ $dbdate .= "::TIMESTAMP";
+ }
+
+ $date = $db->SQLDate('d-m-M-Y-\QQ h:i:s A', $dbdate);
+ $sql = "SELECT $date from ADOXYZ";
+ print "Test SQLDate: ".htmlspecialchars($sql)."
";
+ $db->debug=1;
+ $rs = $db->SelectLimit($sql,1);
+ $ts = ADOConnection::UnixDate('1974-02-25');
+ $d = date('d-m-M-Y-',$ts).'Q'.(ceil(date('m',$ts)/3.0)).date(' h:i:s A',$ts);
+ if (!$rs) {
+ Err("SQLDate query returned no recordset");
+ echo $db->ErrorMsg(),' ';
+ } else if ($d != reset($rs->fields)) {
+ Err("SQLDate 2 failed expected: act:$d sql:".$rs->fields[0].' '.$db->ErrorMsg());
+ }
+
+
+ print "Test Filter
";
+ $db->debug = 1;
+
+ $rs = $db->SelectLimit('select * from ADOXYZ where id < 3 order by id');
+
+ $rs = RSFilter($rs,'do_strtolower');
+ if (trim($rs->fields[1]) != 'caroline' && trim($rs->fields[2]) != 'miranda') {
+ err('**** RSFilter failed');
+ print_r($rs->fields);
+ }
+
+ rs2html($rs);
+
+ $db->debug=1;
+
+
+ print "Test Replace
";
+
+ $ret = $db->Replace('ADOXYZ',
+ array('id'=>1,'firstname'=>'Caroline','lastname'=>'Miranda'),
+ array('id'),
+ $autoq = true);
+ if (!$ret) echo "Error in replacing existing record
";
+ else {
+ $saved = $db->debug;
+ $db->debug = 0;
+ $savec = $ADODB_COUNTRECS;
+ $ADODB_COUNTRECS = true;
+ $rs = $db->Execute('select * FROM ADOXYZ where id=1');
+ $db->debug = $saved;
+ if ($rs->RecordCount() != 1) {
+ $cnt = $rs->RecordCount();
+ rs2html($rs);
+ print "Error - Replace failed, count=$cnt ";
+ }
+ $ADODB_COUNTRECS = $savec;
+ }
+ $ret = $db->Replace('ADOXYZ',
+ array('id'=>1000,'firstname'=>'Harun','lastname'=>'Al-Rashid'),
+ array('id','firstname'),
+ $autoq = true);
+ if ($ret != 2) print "Replace failed: ";
+ print "test A return value=$ret (2 expected)
";
+
+ $ret = $db->Replace('ADOXYZ',
+ array('id'=>1000,'firstname'=>'Sherazade','lastname'=>'Al-Rashid'),
+ 'id',
+ $autoq = true);
+ if ($ret != 1)
+ if ($db->dataProvider == 'ibase' && $ret == 2);
+ else print "Replace failed: ";
+ print "test B return value=$ret (1 or if ibase then 2 expected)
";
+
+ print "
rs2rs Test ";
+
+ $rs = $db->Execute('select * from ADOXYZ where id>= 1 order by id');
+ $rs = $db->_rs2rs($rs);
+ $rs->valueX = 'X';
+ $rs->MoveNext();
+ $rs = $db->_rs2rs($rs);
+ if (!isset($rs->valueX)) err("rs2rs does not preserve array recordsets");
+ if (reset($rs->fields) != 1) err("rs2rs does not move to first row: id=".reset($rs->fields));
+
+ /////////////////////////////////////////////////////////////
+ include_once('../pivottable.inc.php');
+ print "Pivot Test ";
+ $db->debug=true;
+ $sql = PivotTableSQL(
+ $db, # adodb connection
+ 'ADOXYZ', # tables
+ 'firstname', # row fields
+ 'lastname', # column fields
+ false, # join
+ 'ID', # sum
+ 'Sum ', # label for sum
+ 'sum', # aggregate function
+ true
+ );
+ $rs = $db->Execute($sql);
+ if ($rs) rs2html($rs);
+ else Err("Pivot sql error");
+
+ $pear = false; //true;
+ $db->debug=false;
+
+ if ($pear) {
+ // PEAR TESTS BELOW
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+
+ include_once "PEAR.php";
+ $rs = $db->query('select * from ADOXYZ where id>0 and id<10 order by id');
+
+ $i = 0;
+ if ($rs && !$rs->EOF) {
+ while ($arr = $rs->fetchRow()) {
+ $i++;
+ //print "$i ";
+ if ($arr[0] != $i) {
+ print_r($arr);
+ print "PEAR DB emulation error 1.
";
+ $pear = false;
+ break;
+ }
+ }
+ $rs->Close();
+ }
+
+
+ if ($i != $db->GetOne('select count(*) from ADOXYZ where id>0 and id<10')) {
+ print "PEAR DB emulation error 1.1 EOF ($i)
";
+ $pear = false;
+ }
+
+ $rs = $db->limitQuery('select * from ADOXYZ where id>0 order by id',$i=3,$top=3);
+ $i2 = $i;
+ if ($rs && !$rs->EOF) {
+
+ while (!is_object($rs->fetchInto($arr))) {
+ $i2++;
+
+ // print_r($arr);
+ // print "$i ";print_r($arr);
+ if ($arr[0] != $i2) {
+ print "PEAR DB emulation error 2.
";
+ $pear = false;
+ break;
+ }
+ }
+ $rs->Close();
+ }
+ if ($i2 != $i+$top) {
+ print "PEAR DB emulation error 2.1 EOF (correct=$i+$top, actual=$i2)
";
+ $pear = false;
+ }
+ }
+ if ($pear) print "PEAR DB emulation passed.
";
+ flush();
+
+
+ $rs = $db->SelectLimit("select ".$db->sysDate." from ADOXYZ",1);
+ $date = $rs->fields[0];
+ if (!$date) Err("Bad sysDate");
+ else {
+ $ds = $db->UserDate($date,"d m Y");
+ if ($ds != date("d m Y")) Err("Bad UserDate: ".$ds.' expected='.date("d m Y"));
+ else echo "Passed UserDate: $ds";
+ }
+ $db->debug=1;
+ if ($db->dataProvider == 'oci8')
+ $rs = $db->SelectLimit("select to_char(".$db->sysTimeStamp.",'YYYY-MM-DD HH24:MI:SS') from ADOXYZ",1);
+ else
+ $rs = $db->SelectLimit("select ".$db->sysTimeStamp." from ADOXYZ",1);
+ $date = $rs->fields[0];
+ if (!$date) Err("Bad sysTimeStamp");
+ else {
+ $ds = $db->UserTimeStamp($date,"H \\h\\r\\s-d m Y");
+ if ($ds != date("H \\h\\r\\s-d m Y")) Err("Bad UserTimeStamp: ".$ds.", correct is ".date("H \\h\\r\\s-d m Y"));
+ else echo "Passed UserTimeStamp: $ds
";
+
+ $date = 100;
+ $ds = $db->UserTimeStamp($date,"H \\h\\r\\s-d m Y");
+ $ds2 = date("H \\h\\r\\s-d m Y",$date);
+ if ($ds != $ds2) Err("Bad UserTimeStamp 2: $ds: $ds2");
+ else echo "Passed UserTimeStamp 2: $ds
";
+ }
+ flush();
+
+ if ($db->hasTransactions) {
+ $db->debug=1;
+ echo "
Testing StartTrans CompleteTrans
";
+ $db->raiseErrorFn = false;
+
+ $db->SetTransactionMode('SERIALIZABLE');
+ $db->StartTrans();
+ $rs = $db->Execute('select * from notable');
+ $db->StartTrans();
+ $db->BeginTrans();
+ $db->Execute("update ADOXYZ set firstname='Carolx' where id=1");
+ $db->CommitTrans();
+ $db->CompleteTrans();
+ $rez = $db->CompleteTrans();
+ $db->SetTransactionMode('');
+ $db->debug=0;
+ if ($rez !== false) {
+ if (is_null($rez)) Err("Error: _transOK not modified");
+ else Err("Error: CompleteTrans (1) should have failed");
+ } else {
+ $name = $db->GetOne("Select firstname from ADOXYZ where id=1");
+ if ($name == "Carolx") Err("Error: CompleteTrans (2) should have failed");
+ else echo " -- Passed StartTrans test1 - rolling back
";
+ }
+
+ $db->StartTrans();
+ $db->BeginTrans();
+ $db->Execute("update ADOXYZ set firstname='Carolx' where id=1");
+ $db->RollbackTrans();
+ $rez = $db->CompleteTrans();
+ if ($rez !== true) Err("Error: CompleteTrans (1) should have succeeded");
+ else {
+ $name = $db->GetOne("Select firstname from ADOXYZ where id=1");
+ if (trim($name) != "Carolx") Err("Error: CompleteTrans (2) should have succeeded, returned name=$name");
+ else echo " -- Passed StartTrans test2 - committing
";
+ }
+ }
+ flush();
+ $saved = $db->debug;
+ $db->debug=1;
+ $cnt = _adodb_S($db, 'select * from ADOXYZ where firstname in (select firstname from ADOXYZ)');
+ echo "Count= $cnt";
+ $db->debug=$saved;
+
+ global $TESTERRS;
+ $debugerr = true;
+
+ global $ADODB_LANG;$ADODB_LANG = 'fr';
+ $db->debug = false;
+ $TESTERRS = 0;
+ $db->raiseErrorFn = 'adodb_test_err';
+ global $ERRNO; // from adodb_test_err
+ $db->Execute('select * from nowhere');
+ $metae = $db->MetaError($ERRNO);
+ if ($metae !== DB_ERROR_NOSUCHTABLE) print "MetaError=".$metae." wrong , should be ".DB_ERROR_NOSUCHTABLE."
";
+ else print "MetaError ok (".DB_ERROR_NOSUCHTABLE."): ".$db->MetaErrorMsg($metae)."
";
+ if ($TESTERRS != 1) print "raiseErrorFn select nowhere failed ";
+ $rs = $db->Execute('select * from ADOXYZ');
+ if ($debugerr) print " Move";
+ $rs->Move(100);
+ $rs->_queryID = false;
+ if ($debugerr) print " MoveNext";
+ $rs->MoveNext();
+ if ($debugerr) print " $rs=false";
+ $rs = false;
+
+ flush();
+
+ print "SetFetchMode() tests
";
+ $db->SetFetchMode(ADODB_FETCH_ASSOC);
+ $rs = $db->SelectLimit('select firstname from ADOXYZ',1);
+ if (!isset($rs->fields['firstname'])) Err("BAD FETCH ASSOC");
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
+ $rs = $db->SelectLimit('select firstname from ADOXYZ',1);
+ //var_dump($rs->fields);
+ if (!isset($rs->fields['firstname'])) Err("BAD FETCH ASSOC");
+
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $db->SetFetchMode(ADODB_FETCH_NUM);
+ $rs = $db->SelectLimit('select firstname from ADOXYZ',1);
+ if (!isset($rs->fields[0])) Err("BAD FETCH NUM");
+
+ flush();
+
+ print "Test MetaTables again with SetFetchMode()
";
+ $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+ $db->SetFetchMode(ADODB_FETCH_ASSOC);
+ print_r($db->MetaTables());
+ print "";
+
+ ////////////////////////////////////////////////////////////////////
+
+ print "
Testing Bad Connection
";
+ flush();
+
+ if ($db->dataProvider == 'odbtp') {
+ $db->databaseType = 'odbtp';
+ }
+ $conn = NewADOConnection($db->databaseType);
+ $conn->raiseErrorFn = 'adodb_test_err';
+ $conn->PConnect('abc','baduser','badpassword');
+ if ($TESTERRS == 2) {
+ print "raiseErrorFn tests passed ";
+ }
+ else {
+ print "raiseErrorFn tests failed ($TESTERRS) ";
+ }
+
+ flush();
+
+ ////////////////////////////////////////////////////////////////////
+
+ global $nocountrecs;
+
+ if (isset($nocountrecs) && $ADODB_COUNTRECS) err("Error: \$ADODB_COUNTRECS is set");
+ if (empty($nocountrecs) && $ADODB_COUNTRECS==false) err("Error: \$ADODB_COUNTRECS is not set");
+
+ flush();
+?>
+
+
+
+Close();
+ if ($rs2) $rs2->Close();
+ if ($rs) $rs->Close();
+ $db->Close();
+
+ if ($db->transCnt != 0) Err("Error in transCnt=$db->transCnt (should be 0)");
+
+
+ printf("Total queries=%d; total cached=%d
",$EXECS+$CACHED, $CACHED);
+ flush();
+}
+
+function adodb_test_err($dbms, $fn, $errno, $errmsg, $p1=false, $p2=false)
+{
+global $TESTERRS,$ERRNO;
+
+ $ERRNO = $errno;
+ $TESTERRS += 1;
+ print "** $dbms ($fn): errno=$errno errmsg=$errmsg ($p1,$p2) ";
+}
+
+//--------------------------------------------------------------------------------------
+
+
+@set_time_limit(240); // increase timeout
+
+include("../tohtml.inc.php");
+include("../adodb.inc.php");
+include("../rsfilter.inc.php");
+
+/* White Space Check */
+
+if (isset($_SERVER['argv'][1])) {
+ //print_r($_SERVER['argv']);
+ $_GET[$_SERVER['argv'][1]] = 1;
+}
+
+if (@$_SERVER['COMPUTERNAME'] == 'TIGRESS') {
+ CheckWS('mysqlt');
+ CheckWS('postgres');
+ CheckWS('oci8po');
+
+ CheckWS('firebird');
+ CheckWS('sybase');
+ if (!ini_get('safe_mode')) CheckWS('informix');
+
+ CheckWS('ado_mssql');
+ CheckWS('ado_access');
+ CheckWS('mssql');
+
+ CheckWS('vfp');
+ CheckWS('sqlanywhere');
+ CheckWS('db2');
+ CheckWS('access');
+ CheckWS('odbc_mssql');
+ CheckWS('firebird15');
+ //
+ CheckWS('oracle');
+ CheckWS('proxy');
+ CheckWS('fbsql');
+ print "White Space Check complete";
+}
+if (sizeof($_GET) == 0) $testmysql = true;
+
+
+foreach($_GET as $k=>$v) {
+ // XSS protection (see Github issue #274) - only set variables for
+ // expected get parameters used in testdatabases.inc.php
+ if(preg_match('/^(test|no)\w+$/', $k)) {
+ $$k = $v;
+ }
+}
+
+?>
+
+
ADODB Testing
+
+ADODB Test
+
+This script tests the following databases: Interbase, Oracle, Visual FoxPro, Microsoft Access (ODBC and ADO), MySQL, MSSQL (ODBC, native, ADO).
+There is also support for Sybase, PostgreSQL.
+For the latest version of ADODB, visit adodb.org .
+
+Test GetInsertSQL/GetUpdateSQL
+ Sessions
+ Paging
+ Perf Monitor
+vers=",ADOConnection::Version();
+
+
+
+?>
+
ADODB Database Library (c) 2000-2014 John Lim. All rights reserved. Released under BSD and LGPL, PHP .
+
+
diff --git a/adodb/tests/test2.php b/adodb/tests/test2.php
new file mode 100644
index 0000000..fd288dc
--- /dev/null
+++ b/adodb/tests/test2.php
@@ -0,0 +1,42 @@
+debug=1;
+ $access = 'd:\inetpub\wwwroot\php\NWIND.MDB';
+ $myDSN = 'PROVIDER=Microsoft.Jet.OLEDB.4.0;'
+ . 'DATA SOURCE=' . $access . ';';
+
+ echo "PHP ",PHP_VERSION,"
";
+
+ $db->Connect($myDSN) || die('fail');
+
+ print_r($db->ServerInfo());
+
+ try {
+ $rs = $db->Execute("select $db->sysTimeStamp,* from adoxyz where id>02xx");
+ print_r($rs->fields);
+ } catch(exception $e) {
+ print_r($e);
+ echo " Date m/d/Y =",$db->UserDate($rs->fields[4],'m/d/Y');
+ }
diff --git a/adodb/tests/test3.php b/adodb/tests/test3.php
new file mode 100644
index 0000000..38c5285
--- /dev/null
+++ b/adodb/tests/test3.php
@@ -0,0 +1,53 @@
+Connect('','scott','natsoft');
+$db->debug=1;
+
+$cnt = $db->GetOne("select count(*) from adoxyz");
+$rs = $db->Execute("select * from adoxyz order by id");
+
+$i = 0;
+foreach($rs as $k => $v) {
+ $i += 1;
+ echo $k; adodb_pr($v);
+ flush();
+}
+
+if ($i != $cnt) die("actual cnt is $i, cnt should be $cnt\n");
+
+
+
+$rs = $db->Execute("select bad from badder");
+
+} catch (exception $e) {
+ adodb_pr($e);
+ $e = adodb_backtrace($e->trace);
+}
diff --git a/adodb/tests/test4.php b/adodb/tests/test4.php
new file mode 100644
index 0000000..cdaf527
--- /dev/null
+++ b/adodb/tests/test4.php
@@ -0,0 +1,147 @@
+PConnect("", "sa", "natsoft", "northwind"); // connect to MySQL, testdb
+
+$conn = ADONewConnection("mysql"); // create a connection
+$conn->PConnect("localhost", "root", "", "test"); // connect to MySQL, testdb
+
+
+#$conn = ADONewConnection('oci8po');
+#$conn->Connect('','scott','natsoft');
+
+$connstr = "mysql:dbname=northwind";
+$u = 'root';$p='';
+$conn = ADONewConnection('pdo');
+$conn->Connect($connstr, $u, $p);
+
+//$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+
+
+$conn->debug=1;
+$conn->Execute("delete from adoxyz where lastname like 'Smi%'");
+
+$rs = $conn->Execute($sql); // Execute the query and get the empty recordset
+$record = array(); // Initialize an array to hold the record data to insert
+
+if (strpos($conn->databaseType,'mysql')===false) $record['id'] = 751;
+$record["firstname"] = 'Jann';
+$record["lastname"] = "Smitts";
+$record["created"] = time();
+
+$insertSQL = $conn->GetInsertSQL($rs, $record);
+$conn->Execute($insertSQL); // Insert the record into the database
+
+if (strpos($conn->databaseType,'mysql')===false) $record['id'] = 752;
+// Set the values for the fields in the record
+$record["firstname"] = 'anull';
+$record["lastname"] = "Smith\$@//";
+$record["created"] = time();
+
+if (isset($_GET['f'])) $ADODB_FORCE_TYPE = $_GET['f'];
+
+//$record["id"] = -1;
+
+// Pass the empty recordset and the array containing the data to insert
+// into the GetInsertSQL function. The function will process the data and return
+// a fully formatted insert sql statement.
+$insertSQL = $conn->GetInsertSQL($rs, $record);
+$conn->Execute($insertSQL); // Insert the record into the database
+
+
+
+$insertSQL2 = $conn->GetInsertSQL($table='ADOXYZ', $record);
+if ($insertSQL != $insertSQL2) echo "
Walt's new stuff failed : $insertSQL2
";
+//==========================
+// This code tests an update
+
+$sql = "
+SELECT *
+FROM ADOXYZ WHERE lastname=".$conn->Param('var'). " ORDER BY 1";
+// Select a record to update
+
+$varr = array('var'=>$record['lastname'].'');
+$rs = $conn->Execute($sql,$varr); // Execute the query and get the existing record to update
+if (!$rs || $rs->EOF) print "No record found!
";
+
+$record = array(); // Initialize an array to hold the record data to update
+
+
+// Set the values for the fields in the record
+$record["firstName"] = "Caroline".rand();
+//$record["lasTname"] = ""; // Update Caroline's lastname from Miranda to Smith
+$record["creAted"] = '2002-12-'.(rand()%30+1);
+$record['num'] = '';
+// Pass the single record recordset and the array containing the data to update
+// into the GetUpdateSQL function. The function will process the data and return
+// a fully formatted update sql statement.
+// If the data has not changed, no recordset is returned
+
+$updateSQL = $conn->GetUpdateSQL($rs, $record);
+$conn->Execute($updateSQL,$varr); // Update the record in the database
+if ($conn->Affected_Rows() != 1)print "Error1 : Rows Affected=".$conn->Affected_Rows().", should be 1
";
+
+$record["firstName"] = "Caroline".rand();
+$record["lasTname"] = "Smithy Jones"; // Update Caroline's lastname from Miranda to Smith
+$record["creAted"] = '2002-12-'.(rand()%30+1);
+$record['num'] = 331;
+$updateSQL = $conn->GetUpdateSQL($rs, $record);
+$conn->Execute($updateSQL,$varr); // Update the record in the database
+if ($conn->Affected_Rows() != 1)print "Error 2 : Rows Affected=".$conn->Affected_Rows().", should be 1
";
+
+$rs = $conn->Execute("select * from ADOXYZ where lastname like 'Sm%'");
+//adodb_pr($rs);
+rs2html($rs);
+
+$record["firstName"] = "Carol-new-".rand();
+$record["lasTname"] = "Smithy"; // Update Caroline's lastname from Miranda to Smith
+$record["creAted"] = '2002-12-'.(rand()%30+1);
+$record['num'] = 331;
+
+$conn->AutoExecute('ADOXYZ',$record,'UPDATE', "lastname like 'Sm%'");
+$rs = $conn->Execute("select * from ADOXYZ where lastname like 'Sm%'");
+//adodb_pr($rs);
+rs2html($rs);
+}
+
+
+testsql();
diff --git a/adodb/tests/test5.php b/adodb/tests/test5.php
new file mode 100644
index 0000000..15327d1
--- /dev/null
+++ b/adodb/tests/test5.php
@@ -0,0 +1,53 @@
+debug=1;
+ $conn->PConnect("localhost","root","","xphplens");
+ print $conn->databaseType.':'.$conn->GenID().' ';
+}
+
+if (0) {
+ $conn = ADONewConnection("oci8"); // create a connection
+ $conn->debug=1;
+ $conn->PConnect("falcon", "scott", "tiger", "juris8.ecosystem.natsoft.com.my"); // connect to MySQL, testdb
+ print $conn->databaseType.':'.$conn->GenID();
+}
+
+if (0) {
+ $conn = ADONewConnection("ibase"); // create a connection
+ $conn->debug=1;
+ $conn->Connect("localhost:c:\\Interbase\\Examples\\Database\\employee.gdb", "sysdba", "masterkey", ""); // connect to MySQL, testdb
+ print $conn->databaseType.':'.$conn->GenID().' ';
+}
+
+if (0) {
+ $conn = ADONewConnection('postgres');
+ $conn->debug=1;
+ @$conn->PConnect("susetikus","tester","test","test");
+ print $conn->databaseType.':'.$conn->GenID().' ';
+}
diff --git a/adodb/tests/test_mssqlnative.php b/adodb/tests/test_mssqlnative.php
new file mode 100644
index 0000000..9a4221f
--- /dev/null
+++ b/adodb/tests/test_mssqlnative.php
@@ -0,0 +1,150 @@
+\n".$Msg;
+}
+function DieTrace($Msg){
+ die(" \n".$Msg);
+}
+
+
+define('ADODB_ASSOC_CASE',0);
+$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
+$db = ADONewConnection("mssqlnative"); // create a connection
+$db->Connect('127.0.0.1','adodb','natsoft','northwind') or die('Fail');
+
+//==========================
+// This code tests GenId
+//==========================
+function TestGenID() {
+ global $db;
+ $PrevDebug=$db->debug; $db->debug=false; // Hide debug if present as Drop can cause errors
+ $db->Execute("drop sequence MySequence1;
+drop sequence MySequence2;
+drop sequence MySequence3;
+drop table MySequence1Emul;
+drop table MySequence2Emul;
+drop table MySequence3Emul;
+");
+ $db->debug=$PrevDebug; // Restore debug Initial State
+
+ $ID1a=$db->GenID("MySequence1");
+ $ID2a=$db->GenID("MySequence2");
+ $ID1b=$db->GenID("MySequence1");
+ $ID2b=$db->GenID("MySequence2");
+ Trace("ID1a=$ID1a,ID1b=$ID1b, ID2a=$ID2a,ID2b=$ID2b");
+ if(intval($ID1a)+1!==intval($ID1b)) DieTrace(sprintf("ERROR : Second value obtains by MySequence1 should be %d but is %d",$ID1a+1,$ID1b));
+
+ $db->CreateSequence("MySequence3",100);
+ $ID2b=$db->GenID("MySequence3");
+ if(intval($ID2b)!==100) DieTrace(sprintf("ERROR : Value from MySequence3 should be 100 but is %d",$ID2b));
+
+ $db->mssql_version=10; // Force to simulate Pre 2012 (without sequence) behavior
+ $ID1a=$db->GenID("MySequence1Emul");
+ $ID2a=$db->GenID("MySequence2Emul");
+ $ID1b=$db->GenID("MySequence1Emul");
+ $ID2b=$db->GenID("MySequence2Emul");
+ echo "ID1a=$ID1a,ID1b=$ID1b, ID2a=$ID2a,ID2b=$ID2b \n";
+ if(intval($ID1a+1)!==intval($ID1b)) DieTrace(sprintf("ERROR : Second value obtains by MySequence1Emul should be %d but is %d",$ID1a+1,$ID1b));
+
+ $db->CreateSequence("MySequence3Emul",100);
+ $ID2b=$db->GenID("MySequence3Emul");
+ if(intval($ID2b)!==100) DieTrace(sprintf("ERROR : Value from MySequence3Emul should be 100 but is %d",$ID2b));
+ } //TestGenID()
+
+//==========================
+// This code tests SQLDate
+//==========================
+function TestSQLDate()
+{
+ global $db;
+ $res = $db->GetRow("select testdate,"
+ . $db->SQLDate("d/m/Y", "testdate") . " FR4,"
+ . $db->SQLDate("d/m/y", "testdate") . " FR4b,"
+ . $db->SQLDate("d/m/Y", "NULL") . " nullFR4,"
+ . $db->SQLDate("m/d/Y", "testdate") . " US4,"
+ . $db->SQLDate("m/d/y", "testdate") . " US4b,"
+ . $db->SQLDate("m-d-Y", "testdate") . " USD4,"
+ . $db->SQLDate("m-d-y", "testdate") . " USD4b,"
+ . $db->SQLDate("Y.m.d", "testdate") . " ANSI4,"
+ . $db->SQLDate("d.m.Y", "testdate") . " GE4,"
+ . $db->SQLDate("d.m.y", "testdate") . " GE4b,"
+ . $db->SQLDate("d-m-Y", "testdate") . " IT4,"
+ . $db->SQLDate("d-m-y", "testdate") . " IT4b,"
+ . $db->SQLDate("Y/m/d", "testdate") . " Japan4,"
+ . $db->SQLDate("y/m/d", "testdate") . " Japan4b,"
+ . $db->SQLDate("H:i:s", "testdate") . " timeonly,"
+ . $db->SQLDate("d m Y", "testdate") . " Space4," // Is done by former method
+ . $db->SQLDate("d m Y", "NULL") . " nullSpace4,"
+ . $db->SQLDate("m-d-Y", "testdatesmall") . " nowUSdash4,"
+ . "null from (select convert(datetime,'2016-12-17 18:55:30.590' ,121) testdate,
+ convert(datetime,'2016-01-01 18:55:30.590' ,121) testdatesmall,null nulldate) q "
+ );
+ $TestRes=array(
+ "fr4"=>"17/12/2016",
+ "fr4b"=>"17/12/2016",
+ "nullfr4"=>null,
+ "us4"=>"12/17/2016",
+ "us4b"=>"12/17/2016",
+ "ansi4"=>"2016.12.17",
+ "ge4"=>"17.12.2016",
+ "ge4b"=>"17.12.2016",
+ "it4"=>"17-12-2016",
+ "it4b"=>"17-12-2016",
+ "japan4"=>"2016/12/17",
+ "japan4b"=>"2016/12/17",
+ "space4"=>"17 12 2016",
+ "nullspace4"=>null,
+ "timeonly"=>"18:55:30",
+ );
+ var_dump($res);
+ foreach($TestRes as $k=>$v)
+ if($v!==$res[$k])
+ DieTrace(sprintf("ERROR : Expected for '%s' is '%s', but got '%s'",$k,$v,$res[$k]));
+} //TestSQLDate()
+
+//==========================
+// This code is the tests RUNNER
+//==========================
+$db->debug=true;
+// $ToTest Contains * or the name of the test function to RUN
+$ToTest="*";
+//$ToTest="TestSQLDate";
+
+// Here the generic test runner, will launch all functions of the current file beginning by "test", should not be changed use $ToTest
+$functions = get_defined_functions();
+$functions = $functions['user'];
+foreach( $functions as $f) {
+ $refFunc = new ReflectionFunction($f);
+ if(($refFunc->getFileName()==__FILE__)&&(substr($f,0,4)=='test'))
+ if(($ToTest=='*')||(strtolower($ToTest)==$f))
+ {
+ Trace("-------- Launch Test : $f ------------------ ");
+ $f();
+ }
+}
+
+Trace("=========== End of tests Without Error. =================== ");
\ No newline at end of file
diff --git a/adodb/tests/test_rs_array.php b/adodb/tests/test_rs_array.php
new file mode 100644
index 0000000..75848c0
--- /dev/null
+++ b/adodb/tests/test_rs_array.php
@@ -0,0 +1,65 @@
+InitArray($array,$typearr);
+
+while (!$rs->EOF) {
+ print_r($rs->fields);echo " ";
+ $rs->MoveNext();
+}
+
+echo " 1 Seek ";
+$rs->Move(1);
+while (!$rs->EOF) {
+ print_r($rs->fields);echo " ";
+ $rs->MoveNext();
+}
+
+echo " 2 Seek ";
+$rs->Move(2);
+while (!$rs->EOF) {
+ print_r($rs->fields);echo " ";
+ $rs->MoveNext();
+}
+
+echo " 3 Seek ";
+$rs->Move(3);
+while (!$rs->EOF) {
+ print_r($rs->fields);echo " ";
+ $rs->MoveNext();
+}
+
+
+
+die();
diff --git a/adodb/tests/testcache.php b/adodb/tests/testcache.php
new file mode 100644
index 0000000..bf8676b
--- /dev/null
+++ b/adodb/tests/testcache.php
@@ -0,0 +1,38 @@
+
+
+PConnect('nwind');
+} else {
+ $db = ADONewConnection('mysql');
+ $db->PConnect('mangrove','root','','xphplens');
+}
+if (isset($cache)) $rs = $db->CacheExecute(120,'select * from products');
+else $rs = $db->Execute('select * from products');
+
+$arr = $rs->GetArray();
+print sizeof($arr);
diff --git a/adodb/tests/testdatabases.inc.php b/adodb/tests/testdatabases.inc.php
new file mode 100644
index 0000000..8c6358a
--- /dev/null
+++ b/adodb/tests/testdatabases.inc.php
@@ -0,0 +1,475 @@
+
+
+
+
+
+
+FETCH MODE IS NOT ADODB_FETCH_DEFAULT";
+
+if (isset($nocountrecs)) $ADODB_COUNTRECS = false;
+
+// cannot test databases below, but we include them anyway to check
+// if they parse ok...
+
+if (sizeof($_GET) || !isset($_SERVER['HTTP_HOST'])) {
+ echo " ";
+ ADOLoadCode2("sybase");
+ ADOLoadCode2("postgres");
+ ADOLoadCode2("postgres7");
+ ADOLoadCode2("firebird");
+ ADOLoadCode2("borland_ibase");
+ ADOLoadCode2("informix");
+ ADOLoadCode2('mysqli');
+ if (defined('ODBC_BINMODE_RETURN')) {
+ ADOLoadCode2("sqlanywhere");
+ ADOLoadCode2("access");
+ }
+ ADOLoadCode2("mysql");
+ ADOLoadCode2("oci8");
+}
+
+function ADOLoadCode2($d)
+{
+ ADOLoadCode($d);
+ $c = ADONewConnection($d);
+ echo "Loaded $d ",($c ? 'ok' : 'extension not installed')," ";
+}
+
+flush();
+
+// dregad 2014-04-15 added serial field to avoid error with lastval()
+$pg_test_table = "create table ADOXYZ (id integer, firstname char(24), lastname varchar,created date, ser serial)";
+$pg_hostname = 'localhost';
+$pg_user = 'tester';
+$pg_password = 'test';
+$pg_database = 'northwind';
+$pg_errmsg = "ERROR: PostgreSQL requires a database called '$pg_database' "
+ . "on server '$pg_hostname', user '$pg_user', password '$pg_password'. ";
+
+if (!empty($testpostgres)) {
+ //ADOLoadCode("postgres");
+
+ $db = ADONewConnection('postgres');
+ print "Connecting $db->databaseType... ";
+ if ($db->Connect($pg_hostname, $pg_user, $pg_password, $pg_database)) {
+ testdb($db, $pg_test_table);
+ } else {
+ print $pg_errmsg . $db->ErrorMsg();
+ }
+}
+
+if (!empty($testpostgres9)) {
+ //ADOLoadCode("postgres");
+
+ $db = ADONewConnection('postgres9');
+ print "Connecting $db->databaseType... ";
+ if ($db->Connect($pg_hostname, $pg_user, $pg_password, $pg_database)) {
+ testdb($db, $pg_test_table);
+ } else {
+ print $pg_errmsg . $db->ErrorMsg();
+ }
+}
+
+if (!empty($testpgodbc)) {
+
+ $db = ADONewConnection('odbc');
+ $db->hasTransactions = false;
+ print "Connecting $db->databaseType... ";
+
+ if ($db->PConnect('Postgresql')) {
+ $db->hasTransactions = true;
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");
+ } else print "ERROR: PostgreSQL requires a database called test on server, user tester, password test. ".$db->ErrorMsg();
+}
+
+if (!empty($testibase)) {
+ //$_GET['nolog'] = true;
+ $db = ADONewConnection('firebird');
+ print "Connecting $db->databaseType... ";
+ if ($db->PConnect("localhost:d:\\firebird\\151\\examples\\EMPLOYEE.fdb", "sysdba", "masterkey", ""))
+ testdb($db,"create table ADOXYZ (id integer, firstname char(24), lastname char(24),price numeric(12,2),created date)");
+ else print "ERROR: Interbase test requires a database called employee.gdb".' '.$db->ErrorMsg();
+
+}
+
+
+if (!empty($testsqlite)) {
+ $path =urlencode('d:\inetpub\adodb\sqlite.db');
+ $dsn = "sqlite://$path/";
+ $db = ADONewConnection($dsn);
+ //echo $dsn;
+
+ //$db = ADONewConnection('sqlite');
+
+
+ if ($db && $db->PConnect("d:\\inetpub\\adodb\\sqlite.db", "", "", "")) {
+ print "Connecting $db->databaseType... ";
+ testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");
+ } else
+ print "ERROR: SQLite";
+
+}
+
+if (!empty($testpdopgsql)) {
+ $connstr = "pgsql:dbname=test";
+ $u = 'tester';$p='test';
+ $db = ADONewConnection('pdo');
+ print "Connecting $db->databaseType... ";
+ $db->Connect($connstr,$u,$p) || die("CONNECT FAILED");
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+}
+
+if (!empty($testpdomysql)) {
+ $connstr = "mysql:dbname=northwind";
+ $u = 'root';$p='';
+ $db = ADONewConnection('pdo');
+ print "Connecting $db->databaseType... ";
+ $db->Connect($connstr,$u,$p) || die("CONNECT FAILED");
+
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+}
+
+if (!empty($testpdomssql)) {
+ $connstr = "mssql:dbname=northwind";
+ $u = 'sa';$p='natsoft';
+ $db = ADONewConnection('pdo');
+ print "Connecting $db->databaseType... ";
+ $db->Connect($connstr,$u,$p) || die("CONNECT FAILED");
+
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+}
+
+if (!empty($testpdosqlite)) {
+ $connstr = "sqlite:d:/inetpub/adodb/sqlite-pdo.db3";
+ $u = '';$p='';
+ $db = ADONewConnection('pdo');
+ $db->hasTransactions = false;
+ print "Connecting $db->databaseType... ";
+ $db->Connect($connstr,$u,$p) || die("CONNECT FAILED");
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+}
+
+if (!empty($testpdoaccess)) {
+ $connstr = 'odbc:nwind';
+ $u = '';$p='';
+ $db = ADONewConnection('pdo');
+ $db->hasTransactions = false;
+ print "Connecting $db->databaseType... ";
+ $db->Connect($connstr,$u,$p) || die("CONNECT FAILED");
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+}
+
+if (!empty($testpdoora)) {
+ $connstr = 'oci:';
+ $u = 'scott';$p='natsoft';
+ $db = ADONewConnection('pdo');
+ #$db->hasTransactions = false;
+ print "Connecting $db->databaseType... ";
+ $db->Connect($connstr,$u,$p) || die("CONNECT FAILED");
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+}
+
+// REQUIRES ODBC DSN CALLED nwind
+if (!empty($testaccess)) {
+ $db = ADONewConnection('access');
+ print "Connecting $db->databaseType... ";
+ $access = 'd:\inetpub\wwwroot\php\NWIND.MDB';
+ $dsn = "nwind";
+ $dsn = "Driver={Microsoft Access Driver (*.mdb)};Dbq=$access;Uid=Admin;Pwd=;";
+
+ //$dsn = 'Provider=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=' . $access . ';';
+ if ($db->PConnect($dsn, "", "", ""))
+ testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");
+ else print "ERROR: Access test requires a Windows ODBC DSN=nwind, Access driver";
+
+}
+
+if (!empty($testaccess) && !empty($testado)) { // ADO ACCESS
+
+ $db = ADONewConnection("ado_access");
+ print "Connecting $db->databaseType... ";
+
+ $access = 'd:\inetpub\wwwroot\php\NWIND.MDB';
+ $myDSN = 'PROVIDER=Microsoft.Jet.OLEDB.4.0;'
+ . 'DATA SOURCE=' . $access . ';';
+ //. 'USER ID=;PASSWORD=;';
+ $_GET['nolog'] = 1;
+ if ($db->PConnect($myDSN, "", "", "")) {
+ print "ADO version=".$db->_connectionID->version." ";
+ testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");
+ } else print "ERROR: Access test requires a Access database $access".' '.$db->ErrorMsg();
+
+}
+
+if (!empty($testvfp)) { // ODBC
+ $db = ADONewConnection('vfp');
+ print "Connecting $db->databaseType... ";flush();
+
+ if ( $db->PConnect("vfp-adoxyz")) {
+ testdb($db,"create table d:\\inetpub\\adodb\\ADOXYZ (id int, firstname char(24), lastname char(24),created date)");
+ } else print "ERROR: Visual FoxPro test requires a Windows ODBC DSN=vfp-adoxyz, VFP driver";
+
+ echo " ";
+ $db = ADONewConnection('odbtp');
+
+ if ( $db->PConnect('localhost','DRIVER={Microsoft Visual FoxPro Driver};SOURCETYPE=DBF;SOURCEDB=d:\inetpub\adodb;EXCLUSIVE=NO;')) {
+ print "Connecting $db->databaseType... ";flush();
+ testdb($db,"create table d:\\inetpub\\adodb\\ADOXYZ (id int, firstname char(24), lastname char(24),created date)");
+ } else print "ERROR: Visual FoxPro odbtp requires a Windows ODBC DSN=vfp-adoxyz, VFP driver";
+
+}
+
+
+// REQUIRES MySQL server at localhost with database 'test'
+if (!empty($testmysql)) { // MYSQL
+
+
+ $server = 'localhost';
+ $user = 'root'; $password = ''; $database = 'northwind';
+ $db = ADONewConnection("mysqlt://$user:$password@$server/$database?persist");
+ print "Connecting $db->databaseType... ";
+
+ if (true || $db->PConnect($server, "root", "", "northwind")) {
+ //$db->Execute("DROP TABLE ADOXYZ") || die('fail drop');
+ //$db->debug=1;$db->Execute('drop table ADOXYZ');
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) Type=InnoDB");
+ } else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".' '.$db->ErrorMsg();
+}
+
+// REQUIRES MySQL server at localhost with database 'test'
+if (!empty($testmysqli)) { // MYSQL
+
+ $db = ADONewConnection('mysqli');
+ print "Connecting $db->databaseType... ";
+ $server = 'localhost';
+ if ($db->PConnect($server, "root", "", "northwind")) {
+ //$db->debug=1;$db->Execute('drop table ADOXYZ');
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date)");
+ } else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".' '.$db->ErrorMsg();
+}
+
+
+// REQUIRES MySQL server at localhost with database 'test'
+if (!empty($testmysqlodbc)) { // MYSQL
+
+ $db = ADONewConnection('odbc');
+ $db->hasTransactions = false;
+ print "Connecting $db->databaseType... ";
+ $server = 'localhost';
+ if ($db->PConnect('mysql', "root", ""))
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");
+ else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".' '.$db->ErrorMsg();
+}
+
+if (!empty($testproxy)){
+ $db = ADONewConnection('proxy');
+ print "Connecting $db->databaseType... ";
+ $server = 'localhost';
+
+ if ($db->PConnect('http://localhost/php/phplens/adodb/server.php'))
+ testdb($db,
+ "create table ADOXYZ (id int, firstname char(24), lastname char(24), created date) type=innodb");
+ else print "ERROR: MySQL test requires a MySQL server on localhost, userid='admin', password='', database='test'".' '.$db->ErrorMsg();
+
+}
+
+ADOLoadCode('oci805');
+ADOLoadCode("oci8po");
+
+if (!empty($testoracle)) {
+ $dsn = "oci8";//://scott:natsoft@kk2?persist";
+ $db = ADONewConnection($dsn );//'oci8');
+
+ //$db->debug=1;
+ print "Connecting $db->databaseType... ";
+ if ($db->Connect('mobydick', "scott", "natsoft",'SID=mobydick'))
+ testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");
+ else
+ print "ERROR: Oracle test requires an Oracle server setup with scott/natsoft".' '.$db->ErrorMsg();
+
+}
+ADOLoadCode("oracle"); // no longer supported
+if (false && !empty($testoracle)) {
+
+ $db = ADONewConnection();
+ print "Connecting $db->databaseType... ";
+ if ($db->PConnect("", "scott", "tiger", "natsoft.domain"))
+ testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");
+ else print "ERROR: Oracle test requires an Oracle server setup with scott/tiger".' '.$db->ErrorMsg();
+
+}
+
+ADOLoadCode("odbc_db2"); // no longer supported
+if (!empty($testdb2)) {
+ $db = ADONewConnection("db2");
+ print "Connecting $db->databaseType... ";
+
+ #$db->curMode = SQL_CUR_USE_ODBC;
+ #$dsn = "driver={IBM db2 odbc DRIVER};Database=test;hostname=localhost;port=50000;protocol=TCPIP; uid=natsoft; pwd=guest";
+ if ($db->Connect('localhost','natsoft','guest','test')) {
+ testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");
+ } else {
+ print "ERROR: DB2 test requires an server setup with odbc data source db2_sample".' '.$db->ErrorMsg();
+ }
+echo " ";
+flush();
+ $dsn = "driver={IBM db2 odbc DRIVER};Database=sample;hostname=localhost;port=50000;protocol=TCPIP; uid=root; pwd=natsoft";
+
+ $db = ADONewConnection('odbtp');
+ if ($db->Connect('127.0.0.1',$dsn)) {
+
+ $db->debug=1;
+ $arr = $db->GetArray( "||SQLProcedures" ); adodb_pr($arr);
+ $arr = $db->GetArray( "||SQLProcedureColumns|||GET_ROUTINE_SAR" );adodb_pr($arr);
+
+ testdb($db,"create table ADOXYZ (id int, firstname varchar(24), lastname varchar(24),created date)");
+ } else echo ("ERROR Connection");
+ echo $db->ErrorMsg();
+}
+
+
+$server = 'localhost';
+
+
+
+ADOLoadCode("mssqlpo");
+if (false && !empty($testmssql)) { // MS SQL Server -- the extension is buggy -- probably better to use ODBC
+ $db = ADONewConnection("mssqlpo");
+ //$db->debug=1;
+ print "Connecting $db->databaseType... ";
+
+ $ok = $db->Connect('','sa','natsoft','northwind');
+ echo $db->ErrorMsg();
+ if ($ok /*or $db->PConnect("mangrove", "sa", "natsoft", "ai")*/) {
+ AutoDetect_MSSQL_Date_Order($db);
+ // $db->Execute('drop table adoxyz');
+ testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");
+ } else print "ERROR: MSSQL test 2 requires a MS SQL 7 on a server='$server', userid='adodb', password='natsoft', database='ai'".' '.$db->ErrorMsg();
+
+}
+
+
+ADOLoadCode('odbc_mssql');
+if (!empty($testmssql)) { // MS SQL Server via ODBC
+ $db = ADONewConnection();
+
+ print "Connecting $db->databaseType... ";
+
+ $dsn = "PROVIDER=MSDASQL;Driver={SQL Server};Server=$server;Database=northwind;";
+ $dsn = 'condor';
+ if ($db->PConnect($dsn, "sa", "natsoft", "")) {
+ testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");
+ }
+ else print "ERROR: MSSQL test 1 requires a MS SQL 7 server setup with DSN setup";
+
+}
+
+ADOLoadCode("ado_mssql");
+if (!empty($testmssql) && !empty($testado) ) { // ADO ACCESS MSSQL -- through ODBC -- DSN-less
+
+ $db = ADONewConnection("ado_mssql");
+ //$db->debug=1;
+ print "Connecting DSN-less $db->databaseType... ";
+
+ $myDSN="PROVIDER=MSDASQL;DRIVER={SQL Server};"
+ . "SERVER=$server;DATABASE=NorthWind;UID=adodb;PWD=natsoft;Trusted_Connection=No";
+
+
+ if ($db->PConnect($myDSN, "", "", ""))
+ testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");
+ else print "ERROR: MSSQL test 2 requires MS SQL 7";
+
+}
+
+if (!empty($testmssql) && !empty($testado)) { // ADO ACCESS MSSQL with OLEDB provider
+
+ $db = ADONewConnection("ado_mssql");
+ print "Connecting DSN-less OLEDB Provider $db->databaseType... ";
+ //$db->debug=1;
+ $myDSN="SERVER=localhost;DATABASE=northwind;Trusted_Connection=yes";
+ if ($db->PConnect($myDSN, "adodb", "natsoft", 'SQLOLEDB')) {
+ testdb($db,"create table ADOXYZ (id int, firstname char(24), lastname char(24),created datetime)");
+ } else print "ERROR: MSSQL test 2 requires a MS SQL 7 on a server='mangrove', userid='sa', password='', database='ai'";
+
+}
+
+
+if (extension_loaded('odbtp') && !empty($testmssql)) { // MS SQL Server via ODBC
+ $db = ADONewConnection('odbtp');
+
+ $dsn = "PROVIDER=MSDASQL;Driver={SQL Server};Server=$server;Database=northwind;uid=adodb;pwd=natsoft";
+
+ if ($db->PConnect('localhost',$dsn, "", "")) {
+ print "Connecting $db->databaseType... ";
+ testdb($db,"create table ADOXYZ (id int, firstname char(24) null, lastname char(24) null,created datetime null)");
+ }
+ else print "ERROR: MSSQL test 1 requires a MS SQL 7 server setup with DSN setup";
+
+}
+
+
+print "Tests Completed ";
diff --git a/adodb/tests/testgenid.php b/adodb/tests/testgenid.php
new file mode 100644
index 0000000..3a8a973
--- /dev/null
+++ b/adodb/tests/testgenid.php
@@ -0,0 +1,52 @@
+Execute("drop table $table");
+ //$db->debug=true;
+
+ $ctr = 5000;
+ $lastnum = 0;
+
+ while (--$ctr >= 0) {
+ $num = $db->GenID($table);
+ if ($num === false) {
+ print "GenID returned false";
+ break;
+ }
+ if ($lastnum + 1 == $num) print " $num ";
+ else {
+ print " $num ";
+ flush();
+ }
+ $lastnum = $num;
+ }
+}
diff --git a/adodb/tests/testmssql.php b/adodb/tests/testmssql.php
new file mode 100644
index 0000000..fa8570b
--- /dev/null
+++ b/adodb/tests/testmssql.php
@@ -0,0 +1,81 @@
+Connect('127.0.0.1','adodb','natsoft','northwind') or die('Fail');
+
+$conn->debug =1;
+$query = 'select * from products';
+$conn->SetFetchMode(ADODB_FETCH_ASSOC);
+$rs = $conn->Execute($query);
+echo "";
+while( !$rs->EOF ) {
+ $output[] = $rs->fields;
+ var_dump($rs->fields);
+ $rs->MoveNext();
+ print "";
+}
+die();
+
+
+$p = $conn->Prepare('insert into products (productname,unitprice,dcreated) values (?,?,?)');
+echo "
";
+print_r($p);
+
+$conn->debug=1;
+$conn->Execute($p,array('John'.rand(),33.3,$conn->DBDate(time())));
+
+$p = $conn->Prepare('select * from products where productname like ?');
+$arr = $conn->getarray($p,array('V%'));
+print_r($arr);
+die();
+
+//$conn = ADONewConnection("mssql");
+//$conn->Connect('mangrove','sa','natsoft','ai');
+
+//$conn->Connect('mangrove','sa','natsoft','ai');
+$conn->debug=1;
+$conn->Execute('delete from blobtest');
+
+$conn->Execute('insert into blobtest (id) values(1)');
+$conn->UpdateBlobFile('blobtest','b1','../cute_icons_for_site/adodb.gif','id=1');
+$rs = $conn->Execute('select b1 from blobtest where id=1');
+
+$output = "c:\\temp\\test_out-".date('H-i-s').".gif";
+print "Saving file $output , size=".strlen($rs->fields[0])."";
+$fd = fopen($output, "wb");
+fwrite($fd, $rs->fields[0]);
+fclose($fd);
+
+print " View Image ";
+//$rs = $conn->Execute('SELECT id,SUBSTRING(b1, 1, 10) FROM blobtest');
+//rs2html($rs);
diff --git a/adodb/tests/testoci8.php b/adodb/tests/testoci8.php
new file mode 100644
index 0000000..81cf185
--- /dev/null
+++ b/adodb/tests/testoci8.php
@@ -0,0 +1,93 @@
+
+
+PConnect('','scott','natsoft');
+ if (!empty($testblob)) {
+ $varHoldingBlob = 'ABC DEF GEF John TEST';
+ $num = time()%10240;
+ // create table atable (id integer, ablob blob);
+ $db->Execute('insert into ATABLE (id,ablob) values('.$num.',empty_blob())');
+ $db->UpdateBlob('ATABLE', 'ablob', $varHoldingBlob, 'id='.$num, 'BLOB');
+
+ $rs = $db->Execute('select * from atable');
+
+ if (!$rs) die("Empty RS");
+ if ($rs->EOF) die("EOF RS");
+ rs2html($rs);
+ }
+ $stmt = $db->Prepare('select * from adoxyz where id=?');
+ for ($i = 1; $i <= 10; $i++) {
+ $rs = $db->Execute(
+ $stmt,
+ array($i));
+
+ if (!$rs) die("Empty RS");
+ if ($rs->EOF) die("EOF RS");
+ rs2html($rs);
+ }
+}
+if (1) {
+ $db = ADONewConnection('oci8');
+ $db->PConnect('','scott','natsoft');
+ $db->debug = true;
+ $db->Execute("delete from emp where ename='John'");
+ print $db->Affected_Rows().' ';
+ $stmt = $db->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
+ $rs = $db->Execute($stmt,array('empno'=>4321,'ename'=>'John'));
+ // prepare not quite ready for prime time
+ //$rs = $db->Execute($stmt,array('empno'=>3775,'ename'=>'John'));
+ if (!$rs) die("Empty RS");
+
+ $db->setfetchmode(ADODB_FETCH_NUM);
+
+ $vv = 'A%';
+ $stmt = $db->PrepareSP("BEGIN adodb.open_tab2(:rs,:tt); END;",true);
+ $db->OutParameter($stmt, $cur, 'rs', -1, OCI_B_CURSOR);
+ $db->OutParameter($stmt, $vv, 'tt');
+ $rs = $db->Execute($stmt);
+ while (!$rs->EOF) {
+ adodb_pr($rs->fields);
+ $rs->MoveNext();
+ }
+ echo " val = $vv";
+
+}
+
+if (0) {
+ $db = ADONewConnection('odbc_oracle');
+ if (!$db->PConnect('local_oracle','scott','tiger')) die('fail connect');
+ $db->debug = true;
+ $rs = $db->Execute(
+ 'select * from adoxyz where firstname=? and trim(lastname)=?',
+ array('first'=>'Caroline','last'=>'Miranda'));
+ if (!$rs) die("Empty RS");
+ if ($rs->EOF) die("EOF RS");
+ rs2html($rs);
+}
diff --git a/adodb/tests/testoci8cursor.php b/adodb/tests/testoci8cursor.php
new file mode 100644
index 0000000..9dcf8ca
--- /dev/null
+++ b/adodb/tests/testoci8cursor.php
@@ -0,0 +1,116 @@
+PConnect('','scott','natsoft');
+ $db->debug = 99;
+
+
+/*
+*/
+
+ define('MYNUM',5);
+
+
+ $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS,'A%'); END;");
+
+ if ($rs && !$rs->EOF) {
+ print "Test 1 RowCount: ".$rs->RecordCount()."";
+ } else {
+ print "Error in using Cursor Variables 1
";
+ }
+
+ print "
Testing Stored Procedures for oci8 ";
+
+ $stid = $db->PrepareSP('BEGIN adodb.myproc('.MYNUM.', :myov); END;');
+ $db->OutParameter($stid, $myov, 'myov');
+ $db->Execute($stid);
+ if ($myov != MYNUM) print "Error with myproc
";
+
+
+ $stmt = $db->PrepareSP("BEGIN adodb.data_out(:a1, :a2); END;",true);
+ $a1 = 'Malaysia';
+ //$a2 = ''; # a2 doesn't even need to be defined!
+ $db->InParameter($stmt,$a1,'a1');
+ $db->OutParameter($stmt,$a2,'a2');
+ $rs = $db->Execute($stmt);
+ if ($rs) {
+ if ($a2 !== 'Cinta Hati Malaysia') print "Stored Procedure Error: a2 = $a2 ";
+ else echo "OK: a2=$a2
";
+ } else {
+ print "Error in using Stored Procedure IN/Out Variables
";
+ }
+
+
+ $tname = 'A%';
+
+ $stmt = $db->PrepareSP('select * from tab where tname like :tablename');
+ $db->Parameter($stmt,$tname,'tablename');
+ $rs = $db->Execute($stmt);
+ rs2html($rs);
diff --git a/adodb/tests/testpaging.php b/adodb/tests/testpaging.php
new file mode 100644
index 0000000..956d748
--- /dev/null
+++ b/adodb/tests/testpaging.php
@@ -0,0 +1,95 @@
+PConnect('localhost','tester','test','test');
+}
+
+if ($driver == 'access') {
+ $db = NewADOConnection('access');
+ $db->PConnect("nwind", "", "", "");
+}
+
+if ($driver == 'ibase') {
+ $db = NewADOConnection('ibase');
+ $db->PConnect("localhost:e:\\firebird\\examples\\employee.gdb", "sysdba", "masterkey", "");
+ $sql = 'select distinct firstname, lastname from adoxyz order by firstname';
+
+}
+if ($driver == 'mssql') {
+ $db = NewADOConnection('mssql');
+ $db->Connect('JAGUAR\vsdotnet','adodb','natsoft','northwind');
+}
+if ($driver == 'oci8') {
+ $db = NewADOConnection('oci8');
+ $db->Connect('','scott','natsoft');
+
+$sql = "select * from (select ID, firstname as \"First Name\", lastname as \"Last Name\" from adoxyz
+ order by 1)";
+}
+
+if ($driver == 'access') {
+ $db = NewADOConnection('access');
+ $db->Connect('nwind');
+}
+
+if (empty($driver) or $driver == 'mysql') {
+ $db = NewADOConnection('mysql');
+ $db->Connect('localhost','root','','test');
+}
+
+//$db->pageExecuteCountRows = false;
+
+$db->debug = true;
+
+if (0) {
+$rs = $db->Execute($sql);
+include_once('../toexport.inc.php');
+print "
";
+print rs2csv($rs); # return a string
+
+print ' ';
+$rs->MoveFirst(); # note, some databases do not support MoveFirst
+print rs2tab($rs); # return a string
+
+print ' ';
+$rs->MoveFirst();
+rs2tabout($rs); # send to stdout directly
+print " ";
+}
+
+$pager = new ADODB_Pager($db,$sql);
+$pager->showPageLinks = true;
+$pager->linksPerPage = 10;
+$pager->cache = 60;
+$pager->Render($rows=7);
diff --git a/adodb/tests/testpear.php b/adodb/tests/testpear.php
new file mode 100644
index 0000000..5949abe
--- /dev/null
+++ b/adodb/tests/testpear.php
@@ -0,0 +1,43 @@
+setFetchMode(ADODB_FETCH_ASSOC);
+$rs = $db->Query('select firstname,lastname from adoxyz');
+$cnt = 0;
+while ($arr = $rs->FetchRow()) {
+ print_r($arr);
+ print " ";
+ $cnt += 1;
+}
+
+if ($cnt != 50) print "Error in \$cnt = $cnt ";
diff --git a/adodb/tests/testsessions.php b/adodb/tests/testsessions.php
new file mode 100644
index 0000000..2eca41b
--- /dev/null
+++ b/adodb/tests/testsessions.php
@@ -0,0 +1,107 @@
+Notify Expiring=$ref, sessionkey=$key ";
+}
+
+//-------------------------------------------------------------------
+
+error_reporting(E_ALL);
+
+
+ob_start();
+include('../session/adodb-cryptsession2.php');
+
+
+$options['debug'] = 1;
+$db = 'postgres';
+
+#### CONNECTION
+switch($db) {
+case 'oci8':
+ $options['table'] = 'adodb_sessions2';
+ ADOdb_Session::config('oci8', 'mobydick', 'jdev', 'natsoft', 'mobydick',$options);
+ break;
+
+case 'postgres':
+ $options['table'] = 'sessions2';
+ ADOdb_Session::config('postgres', 'localhost', 'postgres', 'natsoft', 'northwind',$options);
+ break;
+
+case 'mysql':
+default:
+ $options['table'] = 'sessions2';
+ ADOdb_Session::config('mysql', 'localhost', 'root', '', 'xphplens_2',$options);
+ break;
+
+
+}
+
+
+
+#### SETUP NOTIFICATION
+ $USER = 'JLIM'.rand();
+ $ADODB_SESSION_EXPIRE_NOTIFY = array('USER','NotifyExpire');
+
+ adodb_session_create_table();
+ session_start();
+
+ adodb_session_regenerate_id();
+
+### SETUP SESSION VARIABLES
+ if (empty($_SESSION['MONKEY'])) $_SESSION['MONKEY'] = array(1,'abc',44.41);
+ else $_SESSION['MONKEY'][0] += 1;
+ if (!isset($_GET['nochange'])) @$_SESSION['AVAR'] += 1;
+
+
+### START DISPLAY
+ print "PHP ".PHP_VERSION." ";
+ print "\$_SESSION['AVAR']={$_SESSION['AVAR']}
";
+
+ print " Cookies : ";
+ print_r($_COOKIE);
+
+ var_dump($_SESSION['MONKEY']);
+
+### RANDOMLY PERFORM Garbage Collection
+### In real-production environment, this is done for you
+### by php's session extension, which calls adodb_sess_gc()
+### automatically for you. See php.ini's
+### session.cookie_lifetime and session.gc_probability
+
+ if (rand() % 5 == 0) {
+
+ print "Garbage Collection
";
+ adodb_sess_gc(10);
+
+ if (rand() % 2 == 0) {
+ print "Random own session destroy
";
+ session_destroy();
+ }
+ } else {
+ $DB = ADODB_Session::_conn();
+ $sessk = $DB->qstr('%AZ'.rand().time());
+ $olddate = $DB->DBTimeStamp(time()-30*24*3600);
+ $rr = $DB->qstr(rand());
+ $DB->Execute("insert into {$options['table']} (sesskey,expiry,expireref,sessdata,created,modified) values ($sessk,$olddate, $rr,'',$olddate,$olddate)");
+ }
diff --git a/adodb/tests/time.php b/adodb/tests/time.php
new file mode 100644
index 0000000..8760ccd
--- /dev/null
+++ b/adodb/tests/time.php
@@ -0,0 +1,35 @@
+
+" );
+echo( "Converted: $convertedDate" ); //why is string returned as one day (3 not 4) less for this example??
diff --git a/adodb/tests/tmssql.php b/adodb/tests/tmssql.php
new file mode 100644
index 0000000..6b85551
--- /dev/null
+++ b/adodb/tests/tmssql.php
@@ -0,0 +1,98 @@
+mssql";
+ $db = mssql_connect('JAGUAR\vsdotnet','adodb','natsoft') or die('No Connection');
+ mssql_select_db('northwind',$db);
+
+ $rs = mssql_query('select getdate() as date',$db);
+ $o = mssql_fetch_row($rs);
+ print_r($o);
+ mssql_free_result($rs);
+
+ print "Delete
"; flush();
+ $rs2 = mssql_query('delete from adoxyz',$db);
+ $p = mssql_num_rows($rs2);
+ mssql_free_result($rs2);
+
+}
+
+function tpear()
+{
+include_once('DB.php');
+
+ print "PEAR ";
+ $username = 'adodb';
+ $password = 'natsoft';
+ $hostname = 'JAGUAR\vsdotnet';
+ $databasename = 'northwind';
+
+ $dsn = "mssql://$username:$password@$hostname/$databasename";
+ $conn = DB::connect($dsn);
+ print "date=".$conn->GetOne('select getdate()')." ";
+ @$conn->query('create table tester (id integer)');
+ print "Delete
"; flush();
+ $rs = $conn->query('delete from tester');
+ print "date=".$conn->GetOne('select getdate()')." ";
+}
+
+function tadodb()
+{
+include_once('../adodb.inc.php');
+
+ print "ADOdb ";
+ $conn = NewADOConnection('mssql');
+ $conn->Connect('JAGUAR\vsdotnet','adodb','natsoft','northwind');
+// $conn->debug=1;
+ print "date=".$conn->GetOne('select getdate()')." ";
+ $conn->Execute('create table tester (id integer)');
+ print "Delete
"; flush();
+ $rs = $conn->Execute('delete from tester');
+ print "date=".$conn->GetOne('select getdate()')." ";
+}
+
+
+$ACCEPTIP = '127.0.0.1';
+
+$remote = $_SERVER["REMOTE_ADDR"];
+
+if (!empty($ACCEPTIP))
+ if ($remote != '127.0.0.1' && $remote != $ACCEPTIP)
+ die("Unauthorised client: '$remote'");
+
+?>
+mssql
+pear
+adodb
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+
+
+ id
+
+
+
+
+
+ SQL to be executed only on specific platforms
+
+ insert into mytable ( row1, row2 ) values ( 12, 'postgres stuff' )
+
+
+ insert into mytable ( row1, row2 ) values ( 12, 'mysql stuff' )
+
+
+ INSERT into simple_table ( name, description ) values ( '12', 'Microsoft stuff' )
+
+
+
\ No newline at end of file
diff --git a/adodb/tests/xmlschema.xml b/adodb/tests/xmlschema.xml
new file mode 100644
index 0000000..ea48ae2
--- /dev/null
+++ b/adodb/tests/xmlschema.xml
@@ -0,0 +1,33 @@
+
+
+
+
+ An integer row that's a primary key and autoincrements
+
+
+
+
+ A 16 character varchar row that can't be null
+
+
+
+ row1
+ row2
+
+
+
+ SQL to be executed only on specific platforms
+
+ insert into mytable ( row1, row2 ) values ( 12, 'postgres stuff' )
+
+
+ insert into mytable ( row1, row2 ) values ( 12, 'mysql stuff' )
+
+
+ insert into mytable ( row1, row2 ) values ( 12, 'Microsoft stuff' )
+
+
+
+
\ No newline at end of file
diff --git a/adodb/toexport.inc.php b/adodb/toexport.inc.php
index b3dd6ef..66bbf54 100644
--- a/adodb/toexport.inc.php
+++ b/adodb/toexport.inc.php
@@ -1,17 +1,11 @@
FieldTypesArray();
reset($fieldTypes);
- while(list(,$o) = each($fieldTypes)) {
-
- $v = $o->name;
+ $i = 0;
+ $elements = array();
+ foreach ($fieldTypes as $o) {
+
+ $v = ($o) ? $o->name : 'Field'.($i++);
if ($escquote) $v = str_replace($quote,$escquotequote,$v);
$v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
$elements[] = $v;
-
+
}
$s .= implode($sep, $elements).$NEWLINE;
}
$hasNumIndex = isset($rs->fields[0]);
-
+
$line = 0;
$max = $rs->FieldCount();
-
+
while (!$rs->EOF) {
$elements = array();
$i = 0;
-
+
if ($hasNumIndex) {
for ($j=0; $j < $max; $j++) {
$v = $rs->fields[$j];
@@ -99,7 +111,7 @@ function _adodb_export(&$rs,$sep,$sepreplace,$fp=false,$addtitles=true,$quote =
else $v = 'Object';
if ($escquote) $v = str_replace($quote,$escquotequote,$v);
$v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
-
+
if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
else $elements[] = $v;
}
@@ -107,7 +119,7 @@ function _adodb_export(&$rs,$sep,$sepreplace,$fp=false,$addtitles=true,$quote =
foreach($rs->fields as $v) {
if ($escquote) $v = str_replace($quote,$escquotequote,trim($v));
$v = strip_tags(str_replace("\n", $replaceNewLine, str_replace("\r\n",$replaceNewLine,str_replace($sep,$sepreplace,$v))));
-
+
if (strpos($v,$sep) !== false || strpos($v,$quote) !== false) $elements[] = "$quote$v$quote";
else $elements[] = $v;
}
@@ -121,13 +133,12 @@ function _adodb_export(&$rs,$sep,$sepreplace,$fp=false,$addtitles=true,$quote =
$s = '';
}
}
-
+
if ($fp) {
if ($fp === true) echo $s;
else fwrite($fp,$s);
$s = '';
}
-
+
return $s;
}
-?>
\ No newline at end of file
diff --git a/adodb/tohtml.inc.php b/adodb/tohtml.inc.php
index 784fbe1..e92c8b4 100644
--- a/adodb/tohtml.inc.php
+++ b/adodb/tohtml.inc.php
@@ -1,13 +1,30 @@
-
-*/
-
+ $gSQLBlockRows. This is because
+ * web browsers normally require the whole table to be downloaded
+ * before it can be rendered, so we break the output into several
+ * smaller, faster rendering tables.
+ *
+ * This file is part of ADOdb, a Database Abstraction Layer library for PHP.
+ *
+ * @package ADOdb
+ * @link https://adodb.org Project's web site and documentation
+ * @link https://github.com/ADOdb/ADOdb Source code and issue tracker
+ *
+ * The ADOdb Library is dual-licensed, released under both the BSD 3-Clause
+ * and the GNU Lesser General Public Licence (LGPL) v2.1 or, at your option,
+ * any later version. This means you can use it in proprietary products.
+ * See the LICENSE.md file distributed with this source code for details.
+ * @license BSD-3-Clause
+ * @license LGPL-2.1-or-later
+ *
+ * @copyright 2000-2013 John Lim
+ * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
+ */
+
// specific code for tohtml
GLOBAL $gSQLMaxRows,$gSQLBlockRows,$ADODB_ROUND;
@@ -15,14 +32,6 @@
$gSQLMaxRows = 1000; // max no of rows to download
$gSQLBlockRows=20; // max no of rows per table block
-// RecordSet to HTML Table
-//------------------------------------------------------------
-// Convert a recordset to a html table. Multiple tables are generated
-// if the number of rows is > $gSQLBlockRows. This is because
-// web browsers normally require the whole table to be downloaded
-// before it can be rendered, so we break the output into several
-// smaller faster rendering tables.
-//
// $rs: the recordset
// $ztabhtml: the table tag attributes (optional)
// $zheaderarray: contains the replacement strings for the headers (optional)
@@ -47,17 +56,17 @@ function rs2html(&$rs,$ztabhtml=false,$zheaderarray=false,$htmlspecialchars=true
printf(ADODB_BAD_RS,'rs2html');
return false;
}
-
+
if (! $ztabhtml) $ztabhtml = "BORDER='1' WIDTH='98%'";
//else $docnt = true;
$typearr = array();
$ncols = $rs->FieldCount();
$hdr = " \n\n";
- for ($i=0; $i < $ncols; $i++) {
+ for ($i=0; $i < $ncols; $i++) {
$field = $rs->FetchField($i);
if ($field) {
if ($zheaderarray) $fname = $zheaderarray[$i];
- else $fname = htmlspecialchars($field->name);
+ else $fname = htmlspecialchars($field->name);
$typearr[$i] = $rs->MetaType($field->type,$field->max_length);
//print " $field->name $field->type $typearr[$i] ";
} else {
@@ -70,38 +79,44 @@ function rs2html(&$rs,$ztabhtml=false,$zheaderarray=false,$htmlspecialchars=true
$hdr .= "\n ";
if ($echo) print $hdr."\n\n";
else $html = $hdr;
-
+
// smart algorithm - handles ADODB_FETCH_MODE's correctly by probing...
$numoffset = isset($rs->fields[0]) ||isset($rs->fields[1]) || isset($rs->fields[2]);
while (!$rs->EOF) {
-
+
$s .= "\n";
-
+
for ($i=0; $i < $ncols; $i++) {
if ($i===0) $v=($numoffset) ? $rs->fields[0] : reset($rs->fields);
else $v = ($numoffset) ? $rs->fields[$i] : next($rs->fields);
-
+
$type = $typearr[$i];
switch($type) {
case 'D':
- if (empty($v)) $s .= " \n";
- else if (!strpos($v,':')) {
- $s .= " ".$rs->UserDate($v,"D d, M Y") ." \n";
+ if (strpos($v,':') !== false);
+ else {
+ if (empty($v)) {
+ $s .= " \n";
+ } else {
+ $s .= " ".$rs->UserDate($v,"D d, M Y") ." \n";
+ }
+ break;
}
- break;
case 'T':
if (empty($v)) $s .= " \n";
- else $s .= " ".$rs->UserTimeStamp($v,"D d, M Y, h:i:s") ." \n";
+ else $s .= " ".$rs->UserTimeStamp($v,"D d, M Y, H:i:s") ." \n";
break;
-
+
case 'N':
if (abs(abs($v) - round($v,0)) < 0.00000001)
$v = round($v);
else
$v = round($v,$ADODB_ROUND);
case 'I':
- $s .= " ".stripslashes((trim($v))) ." \n";
-
+ $vv = stripslashes((trim($v)));
+ if (strlen($vv) == 0) $vv .= ' ';
+ $s .= " ".$vv ." \n";
+
break;
/*
case 'B':
@@ -128,11 +143,11 @@ function mime_content_type ($file) {
$v = trim($v);
if (strlen($v) == 0) $v = ' ';
$s .= " ". str_replace("\n",' ',stripslashes($v)) ." \n";
-
+
}
} // for
$s .= " \n\n";
-
+
$rows += 1;
if ($rows >= $gSQLMaxRows) {
$rows = "Truncated at $gSQLMaxRows
";
@@ -140,10 +155,10 @@ function mime_content_type ($file) {
} // switch
$rs->MoveNext();
-
+
// additional EOF check to prevent a widow header
if (!$rs->EOF && $rows % $gSQLBlockRows == 0) {
-
+
//if (connection_aborted()) break;// not needed as PHP aborts script, unlike ASP
if ($echo) print $s . "
\n\n";
else $html .= $s ."
\n\n";
@@ -153,17 +168,17 @@ function mime_content_type ($file) {
if ($echo) print $s."
\n\n";
else $html .= $s."\n\n";
-
+
if ($docnt) if ($echo) print "".$rows." Rows ";
-
+
return ($echo) ? $rows : $html;
}
-
+
// pass in 2 dimensional array
function arr2html(&$arr,$ztabhtml='',$zheaderarray='')
{
if (!$ztabhtml) $ztabhtml = 'BORDER=1';
-
+
$s = "";//';print_r($arr);
if ($zheaderarray) {
@@ -173,11 +188,11 @@ function arr2html(&$arr,$ztabhtml='',$zheaderarray='')
}
$s .= "\n";
}
-
+
for ($i=0; $i
\ No newline at end of file
diff --git a/adodb/xmlschema.dtd b/adodb/xmlschema.dtd
index 4a055da..2d0b579 100644
--- a/adodb/xmlschema.dtd
+++ b/adodb/xmlschema.dtd
@@ -3,7 +3,7 @@
-
diff --git a/adodb/xmlschema03.dtd b/adodb/xmlschema03.dtd
index a7c8864..351ea44 100644
--- a/adodb/xmlschema03.dtd
+++ b/adodb/xmlschema03.dtd
@@ -1,43 +1,53 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-]>
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/adodb/xsl/convert-0.1-0.2.xsl b/adodb/xsl/convert-0.1-0.2.xsl
new file mode 100644
index 0000000..5b2e3ce
--- /dev/null
+++ b/adodb/xsl/convert-0.1-0.2.xsl
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+
+
+
+ 0.2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/adodb/xsl/convert-0.1-0.3.xsl b/adodb/xsl/convert-0.1-0.3.xsl
new file mode 100644
index 0000000..3202dce
--- /dev/null
+++ b/adodb/xsl/convert-0.1-0.3.xsl
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+
+
+
+ 0.3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/adodb/xsl/convert-0.2-0.1.xsl b/adodb/xsl/convert-0.2-0.1.xsl
new file mode 100644
index 0000000..6398e3e
--- /dev/null
+++ b/adodb/xsl/convert-0.2-0.1.xsl
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+
+
+
+ 0.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/adodb/xsl/convert-0.2-0.3.xsl b/adodb/xsl/convert-0.2-0.3.xsl
new file mode 100644
index 0000000..9e1f2ae
--- /dev/null
+++ b/adodb/xsl/convert-0.2-0.3.xsl
@@ -0,0 +1,281 @@
+
+
+
+
+
+
+
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+
+
+
+ 0.3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/adodb/xsl/remove-0.2.xsl b/adodb/xsl/remove-0.2.xsl
new file mode 100644
index 0000000..c82c3ad
--- /dev/null
+++ b/adodb/xsl/remove-0.2.xsl
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+
+
+
+Uninstallation Schema
+
+
+
+ 0.2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/adodb/xsl/remove-0.3.xsl b/adodb/xsl/remove-0.3.xsl
new file mode 100644
index 0000000..4b1cd02
--- /dev/null
+++ b/adodb/xsl/remove-0.3.xsl
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+ADODB XMLSchema
+http://adodb-xmlschema.sourceforge.net
+
+
+
+Uninstallation Schema
+
+
+
+ 0.3
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gacl.class.php b/gacl.class.php
index 4cdc4a6..47f23d2 100644
--- a/gacl.class.php
+++ b/gacl.class.php
@@ -1,5 +1,5 @@
= 0) {
+ // PHP-Version 7.2 oder hoeher
+ if (is_countable($array_or_countable)) {
+ return count($array_or_countable, $mode);
+ } elseif ($array_or_countable === null) {
+ return 0;
+ }
+ return 1;
+ } else {
+ return count($array_or_countable, $mode);
+ }
+}
+
/**
* phpGACL main class
*
@@ -57,8 +72,7 @@ class gacl {
--- Private properties ---
*/
/** @var boolean Enables Debug output if true */
- var $_debug = FALSE;
-
+ var $_debug = FALSE; // replaced by DEBUG in line 150
/*
--- Database configuration. ---
*/
@@ -105,9 +119,9 @@ class gacl {
/**
* Constructor
- * @param array An arry of options to oeverride the class defaults
+ * @param array An arry of options to override the class defaults
*/
- function gacl($options = NULL) {
+ function __construct($options = NULL) {
$available_options = array('db','debug','items_per_page','max_select_box_items','max_search_return_items','db_table_prefix','db_type','db_host','db_user','db_password','db_name','caching','force_cache_expire','cache_dir','cache_expire_time');
@@ -148,6 +162,7 @@ function gacl($options = NULL) {
$this->db->PConnect($this->_db_host, $this->_db_user, $this->_db_password, $this->_db_name);
}
$this->db->debug = $this->_debug;
+ $this->db->debug = (DEBUG > 2);
if ( $this->_caching == TRUE ) {
if (!class_exists('Hashed_Cache_Lite')) {
@@ -451,7 +466,7 @@ function acl_query($aco_section_value, $aco_value, $aro_section_value, $aro_valu
return FALSE;
}
- $row =& $rs->FetchRow();
+ $row = $rs->FetchRow();
/*
* Return ACL ID. This is the key to "hooking" extras like pricing assigned to ACLs etc... Very useful.
@@ -468,7 +483,7 @@ function acl_query($aco_section_value, $aco_value, $aro_section_value, $aro_valu
$allow = FALSE;
}
- $retarr = array('acl_id' => &$row[0], 'return_value' => &$row[2], 'allow' => $allow);
+ $retarr = array('acl_id' => $row[0], 'return_value' => $row[2], 'allow' => $allow);
} else {
// Permission denied.
$retarr = array('acl_id' => NULL, 'return_value' => NULL, 'allow' => FALSE);
diff --git a/gacl.ini.php b/gacl.ini.php
index 5ffbe3a..650d595 100644
--- a/gacl.ini.php
+++ b/gacl.ini.php
@@ -1,4 +1,4 @@
-; if (; //Cause parse error to hide from prying eyes?>
+; die(); /* hide from prying eyes */?>
;
; *WARNING*
;
diff --git a/gacl_api.class.php b/gacl_api.class.php
index 14283a8..8cb13a8 100644
--- a/gacl_api.class.php
+++ b/gacl_api.class.php
@@ -214,7 +214,7 @@ function consolidated_edit_acl($aco_section_value, $aco_value, $aro_section_valu
}
//showarray($acl_ids);
- $acl_ids_count = count($acl_ids);
+ $acl_ids_count = phpgacl_legacy_count($acl_ids);
//If acl_id's turns up more then one ACL, lets remove the ARO from all of them in hopes to
//eliminate any conflicts.
@@ -237,7 +237,7 @@ function consolidated_edit_acl($aco_section_value, $aco_value, $aro_section_valu
//At this point there should be no conflicting ACLs, searching for an existing ACL with the new values.
$new_acl_ids = $this->search_acl($aco_section_value, $aco_value, FALSE, FALSE, NULL, NULL, NULL, NULL, $return_value);
- $new_acl_count = count($new_acl_ids);
+ $new_acl_count = phpgacl_legacy_count($new_acl_ids);
//showarray($new_acl_ids);
if (is_array($new_acl_ids)) {
@@ -258,7 +258,7 @@ function consolidated_edit_acl($aco_section_value, $aco_value, $aro_section_valu
}
//showarray($acl_ids);
- $acl_ids_count = count($acl_ids);
+ $acl_ids_count = phpgacl_legacy_count($acl_ids);
if (is_array($acl_ids) AND $acl_ids_count == 1) {
$this->debug_text("add_consolidated_acl(): Appending specified ARO to existing ACL.");
@@ -398,7 +398,7 @@ function search_acl($aco_section_value=NULL, $aco_value=NULL, $aro_section_value
}
}
- if (count($where_query) > 0) {
+ if (phpgacl_legacy_count($where_query) > 0) {
$query .= '
WHERE '. implode (' AND ', $where_query);
}
@@ -434,12 +434,12 @@ function append_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NU
$acl_array = &$this->get_acl($acl_id);
//Append each object type seperately.
- if (is_array($aro_array) AND count($aro_array) > 0) {
+ if (is_array($aro_array) AND phpgacl_legacy_count($aro_array) > 0) {
$this->debug_text("append_acl(): Appending ARO's");
- while (list($aro_section_value,$aro_value_array) = @each($aro_array)) {
+ foreach($aro_array as $aro_section_value=>$aro_value_array) {
foreach ($aro_value_array as $aro_value) {
- if ( count($acl_array['aro'][$aro_section_value]) != 0 ) {
+ if ( phpgacl_legacy_count($acl_array['aro'][$aro_section_value]) != 0 ) {
if (!in_array($aro_value, $acl_array['aro'][$aro_section_value])) {
$this->debug_text("append_acl(): ARO Section Value: $aro_section_value ARO VALUE: $aro_value");
$acl_array['aro'][$aro_section_value][] = $aro_value;
@@ -455,10 +455,10 @@ function append_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NU
}
}
- if (is_array($aro_group_ids) AND count($aro_group_ids) > 0) {
+ if (is_array($aro_group_ids) AND phpgacl_legacy_count($aro_group_ids) > 0) {
$this->debug_text("append_acl(): Appending ARO_GROUP_ID's");
- while (list(,$aro_group_id) = @each($aro_group_ids)) {
+ foreach($aro_group_ids as $aro_group_id) {
if (!is_array($acl_array['aro_groups']) OR !in_array($aro_group_id, $acl_array['aro_groups'])) {
$this->debug_text("append_acl(): ARO Group ID: $aro_group_id");
$acl_array['aro_groups'][] = $aro_group_id;
@@ -469,10 +469,10 @@ function append_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NU
}
}
- if (is_array($axo_array) AND count($axo_array) > 0) {
+ if (is_array($axo_array) AND phpgacl_legacy_count($axo_array) > 0) {
$this->debug_text("append_acl(): Appending AXO's");
- while (list($axo_section_value,$axo_value_array) = @each($axo_array)) {
+ foreach($axo_array as $axo_section_value=>$axo_value_array) {
foreach ($axo_value_array as $axo_value) {
if (!in_array($axo_value, $acl_array['axo'][$axo_section_value])) {
$this->debug_text("append_acl(): AXO Section Value: $axo_section_value AXO VALUE: $axo_value");
@@ -486,9 +486,9 @@ function append_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NU
}
}
- if (is_array($axo_group_ids) AND count($axo_group_ids) > 0) {
+ if (is_array($axo_group_ids) AND phpgacl_legacy_count($axo_group_ids) > 0) {
$this->debug_text("append_acl(): Appending AXO_GROUP_ID's");
- while (list(,$axo_group_id) = @each($axo_group_ids)) {
+ foreach($axo_group_ids as $axo_group_id) {
if (!is_array($acl_array['axo_groups']) OR !in_array($axo_group_id, $acl_array['axo_groups'])) {
$this->debug_text("append_acl(): AXO Group ID: $axo_group_id");
$acl_array['axo_groups'][] = $axo_group_id;
@@ -499,10 +499,10 @@ function append_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NU
}
}
- if (is_array($aco_array) AND count($aco_array) > 0) {
+ if (is_array($aco_array) AND phpgacl_legacy_count($aco_array) > 0) {
$this->debug_text("append_acl(): Appending ACO's");
- while (list($aco_section_value,$aco_value_array) = @each($aco_array)) {
+ foreach($aco_array as $aco_section_value=>$aco_value_array) {
foreach ($aco_value_array as $aco_value) {
if (!in_array($aco_value, $acl_array['aco'][$aco_section_value])) {
$this->debug_text("append_acl(): ACO Section Value: $aco_section_value ACO VALUE: $aco_value");
@@ -555,15 +555,15 @@ function shift_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NUL
//showarray($acl_array);
//Remove each object type seperately.
- if (is_array($aro_array) AND count($aro_array) > 0) {
+ if (is_array($aro_array) AND phpgacl_legacy_count($aro_array) > 0) {
$this->debug_text("shift_acl(): Removing ARO's");
- while (list($aro_section_value,$aro_value_array) = @each($aro_array)) {
+ foreach($aro_array as $aro_section_value=>$aro_value_array) {
foreach ($aro_value_array as $aro_value) {
$this->debug_text("shift_acl(): ARO Section Value: $aro_section_value ARO VALUE: $aro_value");
//Only search if aro array contains data.
- if ( count($acl_array['aro'][$aro_section_value]) != 0 ) {
+ if ( phpgacl_legacy_count($acl_array['aro'][$aro_section_value]) != 0 ) {
$aro_key = array_search($aro_value, $acl_array['aro'][$aro_section_value]);
if ($aro_key !== FALSE) {
@@ -579,10 +579,10 @@ function shift_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NUL
}
}
- if (is_array($aro_group_ids) AND count($aro_group_ids) > 0) {
+ if (is_array($aro_group_ids) AND phpgacl_legacy_count($aro_group_ids) > 0) {
$this->debug_text("shift_acl(): Removing ARO_GROUP_ID's");
- while (list(,$aro_group_id) = @each($aro_group_ids)) {
+ foreach($aro_group_ids as $aro_group_id) {
$this->debug_text("shift_acl(): ARO Group ID: $aro_group_id");
$aro_group_key = array_search($aro_group_id, $acl_array['aro_groups']);
@@ -596,10 +596,10 @@ function shift_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NUL
}
}
- if (is_array($axo_array) AND count($axo_array) > 0) {
+ if (is_array($axo_array) AND phpgacl_legacy_count($axo_array) > 0) {
$this->debug_text("shift_acl(): Removing AXO's");
- while (list($axo_section_value,$axo_value_array) = @each($axo_array)) {
+ foreach($axo_array as $axo_section_value=>$axo_value_array) {
foreach ($axo_value_array as $axo_value) {
$this->debug_text("shift_acl(): AXO Section Value: $axo_section_value AXO VALUE: $axo_value");
$axo_key = array_search($axo_value, $acl_array['axo'][$axo_section_value]);
@@ -615,10 +615,10 @@ function shift_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NUL
}
}
- if (is_array($axo_group_ids) AND count($axo_group_ids) > 0) {
+ if (is_array($axo_group_ids) AND phpgacl_legacy_count($axo_group_ids) > 0) {
$this->debug_text("shift_acl(): Removing AXO_GROUP_ID's");
- while (list(,$axo_group_id) = @each($axo_group_ids)) {
+ foreach($axo_group_ids as $axo_group_id) {
$this->debug_text("shift_acl(): AXO Group ID: $axo_group_id");
$axo_group_key = array_search($axo_group_id, $acl_array['axo_groups']);
@@ -632,10 +632,10 @@ function shift_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NUL
}
}
- if (is_array($aco_array) AND count($aco_array) > 0) {
+ if (is_array($aco_array) AND phpgacl_legacy_count($aco_array) > 0) {
$this->debug_text("shift_acl(): Removing ACO's");
- while (list($aco_section_value,$aco_value_array) = @each($aco_array)) {
+ foreach($aco_array as $aco_section_value=>$aco_value_array) {
foreach ($aco_value_array as $aco_value) {
$this->debug_text("shift_acl(): ACO Section Value: $aco_section_value ACO VALUE: $aco_value");
$aco_key = array_search($aco_value, $acl_array['aco'][$aco_section_value]);
@@ -659,8 +659,8 @@ function shift_acl($acl_id, $aro_array=NULL, $aro_group_ids=NULL, $axo_array=NUL
if ( $this->count_all($acl_array['aco']) == 0
OR ( $this->count_all($acl_array['aro']) == 0
AND ( $this->count_all($acl_array['axo']) == 0 OR $acl_array['axo'] == FALSE)
- AND (count($acl_array['aro_groups']) == 0 OR $acl_array['aro_groups'] == FALSE)
- AND (count($acl_array['axo_groups']) == 0 OR $acl_array['axo_groups'] == FALSE)
+ AND (phpgacl_legacy_count($acl_array['aro_groups']) == 0 OR $acl_array['aro_groups'] == FALSE)
+ AND (phpgacl_legacy_count($acl_array['axo_groups']) == 0 OR $acl_array['axo_groups'] == FALSE)
) ) {
$this->debug_text("shift_acl(): No ACOs or ( AROs AND AXOs AND ARO Groups AND AXO Groups) left assigned to this ACL (ID: $acl_id), deleting ACL.");
@@ -725,7 +725,7 @@ function get_acl($acl_id) {
$rows = $rs->GetRows();
$retarr['aco'] = array();
- while (list(,$row) = @each($rows)) {
+ foreach($rows as $row) {
list($section_value, $value, $section, $aco) = $row;
$this->debug_text("Section Value: $section_value Value: $value Section: $section ACO: $aco");
@@ -741,7 +741,7 @@ function get_acl($acl_id) {
$rows = $rs->GetRows();
$retarr['aro'] = array();
- while (list(,$row) = @each($rows)) {
+ foreach($rows as $row) {
list($section_value, $value, $section, $aro) = $row;
$this->debug_text("Section Value: $section_value Value: $value Section: $section ARO: $aro");
@@ -757,7 +757,7 @@ function get_acl($acl_id) {
$rows = $rs->GetRows();
$retarr['axo'] = array();
- while (list(,$row) = @each($rows)) {
+ foreach($rows as $row) {
list($section_value, $value, $section, $axo) = $row;
$this->debug_text("Section Value: $section_value Value: $value Section: $section AXO: $axo");
@@ -853,7 +853,7 @@ function is_conflicting_acl($aco_array, $aro_array, $aro_group_ids=NULL, $axo_ar
//$where_query['ar1'] = 'ar.acl_id=a.id';
$where_query['ar2'] = '(ar.section_value='. $this->db->quote($aro_section_value) .' AND ar.value IN (\''. implode ('\',\'', $aro_value_array) .'\'))';
- if (is_array($axo_array) AND count($axo_array) > 0) {
+ if (is_array($axo_array) AND phpgacl_legacy_count($axo_array) > 0) {
foreach ($axo_array as $axo_section_value => $axo_value_array) {
$this->debug_text("is_conflicting_acl(): AXO Section Value: $axo_section_value AXO VALUE: $axo_value_array");
@@ -880,7 +880,7 @@ function is_conflicting_acl($aco_array, $aro_array, $aro_group_ids=NULL, $axo_ar
$conflict_result = array_diff($conflict_result, $ignore_acl_ids);
}
- if (count($conflict_result) > 0) {
+ if (phpgacl_legacy_count($conflict_result) > 0) {
$conflicting_acls_str = implode(',', $conflict_result);
$this->debug_text("is_conflicting_acl(): Conflict FOUND!!! ACL_IDS: ($conflicting_acls_str)");
return TRUE;
@@ -902,7 +902,7 @@ function is_conflicting_acl($aco_array, $aro_array, $aro_group_ids=NULL, $axo_ar
$conflict_result = array_diff($conflict_result, $ignore_acl_ids);
}
- if (count($conflict_result) > 0) {
+ if (phpgacl_legacy_count($conflict_result) > 0) {
$conflicting_acls_str = implode(',', $conflict_result);
$this->debug_text("is_conflicting_acl(): Conflict FOUND!!! ACL_IDS: ($conflicting_acls_str)");
return TRUE;
@@ -940,12 +940,12 @@ function add_acl($aco_array, $aro_array, $aro_group_ids=NULL, $axo_array=NULL, $
$this->debug_text("add_acl():");
- if (count($aco_array) == 0) {
+ if (phpgacl_legacy_count($aco_array) == 0) {
$this->debug_text("Must select at least one Access Control Object");
return false;
}
- if (count($aro_array) == 0 AND count($aro_group_ids) == 0) {
+ if (phpgacl_legacy_count($aro_array) == 0 AND phpgacl_legacy_count($aro_group_ids) == 0) {
$this->debug_text("Must select at least one Access Request Object or Group");
return false;
}
@@ -1176,12 +1176,12 @@ function edit_acl($acl_id, $aco_array, $aro_array, $aro_group_ids=NULL, $axo_arr
$this->debug_text("edit_acl(): Must specify a single ACL_ID to edit");
return false;
}
- if (count($aco_array) == 0) {
+ if (phpgacl_legacy_count($aco_array) == 0) {
$this->debug_text("edit_acl(): Must select at least one Access Control Object");
return false;
}
- if (count($aro_array) == 0 AND count($aro_group_ids) == 0) {
+ if (phpgacl_legacy_count($aro_array) == 0 AND phpgacl_legacy_count($aro_group_ids) == 0) {
$this->debug_text("edit_acl(): Must select at least one Access Request Object or Group");
return false;
}
@@ -1334,7 +1334,7 @@ function format_groups($sorted_groups, $type='TEXT', $root_id=0, $level=0, $form
//$this->showarray($formatted_groups);
- //while (list($id,$name) = @each($sorted_groups[$root_id])) {
+ //foreach($sorted_groups[$root_id] as $id=>$name) {
if (isset($sorted_groups[$root_id])) {
//$last_id = end( array_keys($sorted_groups[$root_id]));
//PHP5 compatibility
@@ -1389,7 +1389,7 @@ function format_groups($sorted_groups, $type='TEXT', $root_id=0, $level=0, $form
* Recurse if we can.
*/
- //if (isset($sorted_groups[$id]) AND count($sorted_groups[$id]) > 0) {
+ //if (isset($sorted_groups[$id]) AND phpgacl_legacy_count($sorted_groups[$id]) > 0) {
if (isset($sorted_groups[$id]) ) {
//$this->debug_text("format_groups(): Recursing! Level: $level");
$formatted_groups = $this->format_groups($sorted_groups, $type, $id, $next, $formatted_groups);
@@ -2354,7 +2354,7 @@ function del_group($group_id, $reparent_children=TRUE, $group_type='ARO') {
switch (TRUE) {
// there are no child groups, just delete group
case !is_array($children_ids):
- case count($children_ids) == 0:
+ case phpgacl_legacy_count($children_ids) == 0:
// remove acl maps
$query = 'DELETE FROM '. $groups_map_table .' WHERE group_id='. $group_id;
$rs = $this->db->Execute($query);
@@ -3313,7 +3313,7 @@ function del_object($object_id, $object_type=NULL, $erase=FALSE) {
// Get rid of $object_id map referencing erased objects
$query = "DELETE FROM $object_map_table WHERE section_value='$section_value' AND value='$value'";
- $rs = $this->db->Execute($query);
+ $this->db->Execute($query);
if (!is_object($rs)) {
$this->debug_db('edit_object');
@@ -3381,7 +3381,7 @@ function del_object($object_id, $object_type=NULL, $erase=FALSE) {
if ( ( isset($acl_ids) AND !empty($acl_ids) ) OR ( isset($groups_ids) AND !empty($groups_ids) ) ) {
// The Object is referenced somewhere (group or acl), can't delete it
- $this->debug_text("del_object(): Can't delete the object as it is being referenced by GROUPs (".@implode($groups_ids).") or ACLs (".@implode($acl_ids,",").")");
+ $this->debug_text("del_object(): Can't delete the object as it is being referenced by GROUPs (".@implode($groups_ids).") or ACLs (".@implode(",", $acl_ids).")");
$this->db->RollBackTrans();
return false;
} else {
@@ -3838,7 +3838,7 @@ function get_section_data($section_value, $object_type=NULL) {
return false;
}
- $query = 'SELECT id, value, order_value, name, hidden FROM '. $table .' WHERE value = \''. $section_value .'\'';
+ $query = "SELECT id, value, order_value, name, hidden FROM '. $table .' WHERE value='$section_value'";
$row = $this->db->GetRow($query);
if ($row) {
diff --git a/profiler.inc b/profiler.inc
index a9c9032..8e13d46 100644
--- a/profiler.inc
+++ b/profiler.inc
@@ -132,7 +132,7 @@ class Profiler {
echo"============================================================================\n";
print( "Calls Time Routine\n");
echo"-----------------------------------------------------------------------------\n";
- while (list ($key, $val) = each ($this->description)) {
+ foreach($this->description as $key=>$val) {
$t = $this->elapsedTime($key);
$total = $this->running[$key];
$count = $this->count[$key];
@@ -177,7 +177,7 @@ class Profiler {
*
*/
function getMicroTime(){
- $tmp=split(" ",microtime());
+ $tmp=explode(" ",microtime());
$rt=$tmp[0]+$tmp[1];
return $rt;
}
diff --git a/soap/nusoap.php b/soap/nusoap.php
index d75ca8e..b543626 100644
--- a/soap/nusoap.php
+++ b/soap/nusoap.php
@@ -1402,7 +1402,7 @@ function send($data, $timeout=0) {
if($this->encoding != '' && function_exists('gzdeflate')){
$this->outgoing_payload .= "Accept-Encoding: $this->encoding\r\n".
"Connection: close\r\n";
- set_magic_quotes_runtime(0);
+ if(function_exists('set_magic_quotes_runtime')) @set_magic_quotes_runtime(0);
}
// set soapaction
if($this->useSOAPAction){
@@ -1568,7 +1568,7 @@ function sendHTTPS($data, $timeout=0) {
if(function_exists('gzdeflate')){
$encoding_headers = "Accept-Encoding: $this->encoding\r\n".
"Connection: close\r\n";
- set_magic_quotes_runtime(0);
+ if(function_exists('set_magic_quotes_runtime')) @set_magic_quotes_runtime(0);
}
}
@@ -3694,7 +3694,7 @@ function soapclient($endpoint,$wsdl = false){
// instantiate wsdl object and parse wsdl file
$this->debug('instantiating wsdl class with doc: '.$endpoint);
- $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport);
+ $this->wsdl = new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport);
$this->debug("wsdl debug: \n".$this->wsdl->debug_str);
$this->wsdl->debug_str = '';
// catch errors
diff --git a/soap/server.php b/soap/server.php
index bfe131c..e8eff87 100644
--- a/soap/server.php
+++ b/soap/server.php
@@ -29,5 +29,8 @@ function test($text) {
return $text;
}
+if ( !isset( $HTTP_RAW_POST_DATA ) ){
+ // TODO: , php://input should be used instead of $HTTP_RAW_POST_DATA
+ $HTTP_RAW_POST_DATA =file_get_contents( 'php://input' );
+}
$s->service($HTTP_RAW_POST_DATA);
-?>
diff --git a/test_suite/phpunit/phpunit.php b/test_suite/phpunit/phpunit.php
index d21bb74..b337d11 100644
--- a/test_suite/phpunit/phpunit.php
+++ b/test_suite/phpunit/phpunit.php
@@ -5,7 +5,7 @@
// Written by Fred Yankowski
// OntoSys, Inc
//
-// $Id$
+// $Id: phpunit.php 212 2003-10-07 02:12:56Z ipso $
// Copyright (c) 2000 Fred Yankowski
@@ -118,8 +118,8 @@ function assertRegexp($regexp, $actual, $message=false) {
function assertEqualsMultilineStrings($string0, $string1,
$message="") {
- $lines0 = split("\n",$string0);
- $lines1 = split("\n",$string1);
+ $lines0 = explode("\n",$string0);
+ $lines1 = explode("\n",$string1);
if (sizeof($lines0) != sizeof($lines1)) {
$this->failNotEquals(sizeof($lines0)." line(s)",
sizeof($lines1)." line(s)", "expected", $message);
@@ -201,7 +201,7 @@ function run($testResult=0) {
if (! $testResult)
$testResult = $this->_createResult();
$this->fResult = $testResult;
- $testResult->run(&$this);
+ $testResult->run($this);
$this->fResult = 0;
return $testResult;
}
@@ -264,19 +264,19 @@ function fail($message=0) {
//printf("TestCase::fail(%s) \n", ($message) ? $message : '');
/* JUnit throws AssertionFailedError here. We just record the
failure and carry on */
- $this->fExceptions[] = new Exception(&$message, 'FAILURE');
+ $this->fExceptions[] = new Exception($message, 'FAILURE');
}
function error($message) {
/* report error that requires correction in the test script
itself, or (heaven forbid) in this testing infrastructure */
- $this->fExceptions[] = new Exception(&$message, 'ERROR');
+ $this->fExceptions[] = new Exception($message, 'ERROR');
$this->fResult->stop(); // [does not work]
}
function failed() {
reset($this->fExceptions);
- while (list($key, $exception) = each($this->fExceptions)) {
+ foreach($this->fExceptions as $key=>$exception) {
if ($exception->type == 'FAILURE')
return true;
}
@@ -284,7 +284,7 @@ function failed() {
}
function errored() {
reset($this->fExceptions);
- while (list($key, $exception) = each($this->fExceptions)) {
+ foreach($this->fExceptions as $key=>$exception) {
if ($exception->type == 'ERROR')
return true;
}
@@ -337,7 +337,7 @@ function TestSuite($classname=false) {
// PHP4 introspection, submitted by Dylan Kuhn
$names = get_class_methods($classname);
- while (list($key, $method) = @each($names)) {
+ foreach($names as $key=>$method) {
if (preg_match('/^test/', $method)) {
$test = new $classname($method);
if (strcasecmp($method, $classname) == 0 || is_subclass_of($test, $method)) {
@@ -357,7 +357,7 @@ function TestSuite($classname=false) {
else { // PHP3
$dummy = new $classname("dummy");
$names = (array) $dummy;
- while (list($key, $value) = each($names)) {
+ foreach($names as $key=>$value) {
$type = gettype($value);
if ($type == "user function" && preg_match('/^test/', $key)
&& $key != "testcase") {
@@ -376,10 +376,10 @@ function run(&$testResult) {
/* Run all TestCases and TestSuites comprising this TestSuite,
accumulating results in the given TestResult object. */
reset($this->fTests);
- while (list($na, $test) = each($this->fTests)) {
+ foreach($this->fTests as $na=>$test) {
if ($testResult->shouldStop())
break;
- $test->run(&$testResult);
+ $test->run($testResult);
}
}
@@ -388,7 +388,7 @@ function countTestCases() {
in any constituent TestSuites) */
$count = 0;
reset($fTests);
- while (list($na, $test_case) = each($this->fTests)) {
+ foreach($this->fTests as $na=>$test_case) {
$count += $test_case->countTestCases();
}
return $count;
@@ -436,11 +436,11 @@ function _endTest($test) /* protected */ {
}
function addError($test, $exception) {
- $this->fErrors[] = new TestFailure(&$test, &$exception);
+ $this->fErrors[] = new TestFailure($test, $exception);
}
function addFailure($test, $exception) {
- $this->fFailures[] = new TestFailure(&$test, &$exception);
+ $this->fFailures[] = new TestFailure($test, $exception);
}
function getFailures() {
@@ -457,7 +457,7 @@ function run($test) {
/* this is where JUnit would catch AssertionFailedError */
$exceptions = $test->getExceptions();
reset($exceptions);
- while (list($key, $exception) = each($exceptions)) {
+ foreach($exceptions as $key=>$exception) {
if ($exception->type == 'ERROR')
$this->addError($test, $exception);
else if ($exception->type == 'FAILURE')
@@ -517,13 +517,13 @@ function report() {
print("Failures ");
print("\n");
$failures = $this->getFailures();
- while (list($i, $failure) = each($failures)) {
+ foreach($failures as $i=>$failure) {
$failedTestName = $failure->getTestName();
printf("%s\n", $failedTestName);
$exceptions = $failure->getExceptions();
print("");
- while (list($na, $exception) = each($exceptions))
+ foreach($exceptions as $na=>$exception)
printf("%s\n", $exception->getMessage());
print(" ");
}
@@ -534,7 +534,7 @@ function report() {
print("Errors ");
print("\n");
reset($this->fErrors);
- while (list($i, $error) = each($this->fErrors)) {
+ foreach($this->fErrors as $i=>$error) {
$erroredTestName = $error->getTestName();
printf("%s\n", $failedTestName);
@@ -594,13 +594,13 @@ function report() {
echo "Failure Details ";
print("\n");
$failures = $this->getFailures();
- while (list($i, $failure) = each($failures)) {
+ foreach($failures as $i=>$failure) {
$failedTestName = $failure->getTestName();
printf("%s\n", $failedTestName);
$exceptions = $failure->getExceptions();
print("");
- while (list($na, $exception) = each($exceptions))
+ foreach($exceptions as $na=>$exception)
printf("%s\n", $exception->getMessage());
print(" ");
}