[Linpha-cvs] SF.net SVN: linpha: [4857] trunk/linpha2
Status: Inactive
Brought to you by:
bzrudi
From: <fan...@us...> - 2008-02-07 23:22:55
|
Revision: 4857 http://linpha.svn.sourceforge.net/linpha/?rev=4857&view=rev Author: fangehrn Date: 2008-02-07 15:22:46 -0800 (Thu, 07 Feb 2008) Log Message: ----------- 2008-02-07 flo * Important: the define ADODB_FETCH_ASSOC never worked now it is enabled and maybe some queries are broken..? -> imgview broken because of $db->GetAssoc() * Added benchmark module * Enabled adodb's logSql() function -> perf.php analysis all sql queries Modified Paths: -------------- trunk/linpha2/ChangeLog trunk/linpha2/index.php trunk/linpha2/lib/classes/linpha.imgview.class.php trunk/linpha2/lib/classes/linpha.sql.class.php trunk/linpha2/lib/classes/linpha.template.class.php trunk/linpha2/lib/include/common.php trunk/linpha2/templates/default/default.html.php trunk/linpha2/templates/default/global.html.php trunk/linpha2/templates/default/home.html.php Added Paths: ----------- trunk/linpha2/lib/adodb/docs/ trunk/linpha2/lib/adodb/docs/docs-active-record.htm trunk/linpha2/lib/adodb/docs/docs-adodb.htm trunk/linpha2/lib/adodb/docs/docs-datadict.htm trunk/linpha2/lib/adodb/docs/docs-oracle.htm trunk/linpha2/lib/adodb/docs/docs-perf.htm trunk/linpha2/lib/adodb/docs/docs-session.htm trunk/linpha2/lib/adodb/docs/docs-session.old.htm trunk/linpha2/lib/adodb/docs/old-changelog.htm trunk/linpha2/lib/adodb/docs/readme.htm trunk/linpha2/lib/adodb/docs/tips_portable_sql.htm trunk/linpha2/lib/adodb/docs/tute.htm trunk/linpha2/lib/adodb/perf/ trunk/linpha2/lib/adodb/perf/perf-db2.inc.php trunk/linpha2/lib/adodb/perf/perf-informix.inc.php trunk/linpha2/lib/adodb/perf/perf-mssql.inc.php trunk/linpha2/lib/adodb/perf/perf-mysql.inc.php trunk/linpha2/lib/adodb/perf/perf-oci8.inc.php trunk/linpha2/lib/adodb/perf/perf-postgres.inc.php trunk/linpha2/lib/modules/module.benchmark.php trunk/linpha2/logsql.txt trunk/linpha2/perf.php Modified: trunk/linpha2/ChangeLog =================================================================== --- trunk/linpha2/ChangeLog 2008-02-07 20:43:31 UTC (rev 4856) +++ trunk/linpha2/ChangeLog 2008-02-07 23:22:46 UTC (rev 4857) @@ -2,6 +2,12 @@ 2008-02-07 flo * AdoDB updated to version 503 * fixed adodb error handler + * Important: the define ADODB_FETCH_ASSOC never worked + now it is enabled and maybe some queries are broken..? + -> imgview broken because of $db->GetAssoc() + * Added benchmark module + * Enabled adodb's logSql() function + -> perf.php analysis all sql queries 2008-02-06 flo * common.php/linpha.class.php Modified: trunk/linpha2/index.php =================================================================== --- trunk/linpha2/index.php 2008-02-07 20:43:31 UTC (rev 4856) +++ trunk/linpha2/index.php 2008-02-07 23:22:46 UTC (rev 4857) @@ -67,11 +67,13 @@ case 'geodata': require_once(LINPHA_DIR.'/lib/modules/module.geodata.php'); break; +case 'benchmark': + require_once(LINPHA_DIR.'/lib/modules/module.benchmark.php'); + break; case 'empty': require_once(LINPHA_DIR.'/lib/modules/module.empty.php'); break; - - + default: // include plugins $pluginDir = LINPHA_DIR.'/lib/plugins'; Added: trunk/linpha2/lib/adodb/docs/docs-active-record.htm =================================================================== --- trunk/linpha2/lib/adodb/docs/docs-active-record.htm (rev 0) +++ trunk/linpha2/lib/adodb/docs/docs-active-record.htm 2008-02-07 23:22:46 UTC (rev 4857) @@ -0,0 +1,544 @@ +<html> +<style> +pre { + background-color: #eee; + padding: 0.75em 1.5em; + font-size: 12px; + border: 1px solid #ddd; +} + +li,p { +font-family: Arial, Helvetica, sans-serif ; +} +</style> +<title>ADOdb Active Record</title> +<body> +<h1>ADOdb Active Record</h1> +<p> (c) 2000-2008 John Lim (jlim#natsoft.com)</p> +<p><font size="1">This software is dual licensed using BSD-Style and LGPL. This + means you can use it in compiled proprietary and commercial products.</font></p> +<p><hr> +<ol> + +<h3><li>Introduction</h3> +<p> +ADOdb_Active_Record is an Object Relation Mapping (ORM) implementation using PHP. In an ORM system, the tables and rows of the database are abstracted into native PHP objects. This allows the programmer to focus more on manipulating the data and less on writing SQL queries. +<p> +This implementation differs from Zend Framework's implementation in the following ways: +<ul> +<li>Works with PHP4 and PHP5 and provides equivalent functionality in both versions of PHP.<p> +<li>ADOdb_Active_Record works when you are connected to multiple databases. Zend's only works when connected to a default database.<p> +<li>Support for $ADODB_ASSOC_CASE. The field names are upper-cased, lower-cased or left in natural case depending on this setting.<p> +<li>No field name conversion to camel-caps style, unlike Zend's implementation which will convert field names such as 'first_name' to 'firstName'.<p> +<li>NewADOConnection::GetActiveRecords() and ADOConnection::GetActiveRecordsClass() functions in adodb.inc.php.<p> +<li>Caching of table metadata so it is only queried once per table, no matter how many Active Records are created.<p> +<li>The additional functionality is described <a href=#additional>below</a>. +</ul> +<P> +ADOdb_Active_Record is designed upon the principles of the "ActiveRecord" design pattern, which was first described by Martin Fowler. The ActiveRecord pattern has been implemented in many forms across the spectrum of programming languages. ADOdb_Active_Record attempts to represent the database as closely to native PHP objects as possible. +<p> +ADOdb_Active_Record maps a database table to a PHP class, and each instance of that class represents a table row. Relations between tables can also be defined, allowing the ADOdb_Active_Record objects to be nested. +<p> + +<h3><li>Setting the Database Connection</h3> +<p> +The first step to using ADOdb_Active_Record is to set the default connection that an ADOdb_Active_Record objects will use to connect to a database. + +<pre> +require_once('adodb/adodb-active-record.inc.php'); + +$db = NewADOConnection('mysql://root:pwd@localhost/dbname'); +ADOdb_Active_Record::SetDatabaseAdapter($db); +</pre> + +<h3><li>Table Rows as Objects</h3> +<p> +First, let's create a temporary table in our MySQL database that we can use for demonstrative purposes throughout the rest of this tutorial. We can do this by sending a CREATE query: + +<pre> +$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; + "); + </pre> +<p> +ADOdb_Active_Record's are object representations of table rows. Each table in the database is represented by a class in PHP. To begin working with a table as a ADOdb_Active_Record, a class that extends ADOdb_Active_Records needs to be created for it. + +<pre> +class Person extends ADOdb_Active_Record{} +$person = new Person(); +</pre> + +<p> +In the above example, a new ADOdb_Active_Record object $person was created to access the "persons" table. Zend_Db_DataObject takes the name of the class, pluralizes it (according to American English rules), and assumes that this is the name of the table in the database. +<p> +This kind of behavior is typical of ADOdb_Active_Record. It will assume as much as possible by convention rather than explicit configuration. In situations where it isn't possible to use the conventions that ADOdb_Active_Record expects, options can be overridden as we'll see later. + +<h3><li>Table Columns as Object Properties</h3> +<p> +When the $person object was instantiated, ADOdb_Active_Record read the table metadata from the database itself, and then exposed the table's columns (fields) as object properties. +<p> +Our "persons" table has three fields: "name_first", "name_last", and "favorite_color". Each of these fields is now a property of the $person object. To see all these properties, use the ADOdb_Active_Record::getAttributeNames() method: +<pre> +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" + * } + */ + </pre> +<p> +One big difference between ADOdb and Zend's implementation is we do not automatically convert to camelCaps style. +<p> +<h3><li>Inserting and Updating a Record</h3><p> + +An ADOdb_Active_Record object is a representation of a single table row. However, when our $person object is instantiated, it does not reference any particular row. It is a blank record that does not yet exist in the database. An ADOdb_Active_Record object is considered blank when its primary key is NULL. The primary key in our persons table is "id". +<p> +To insert a new record into the database, change the object's properties and then call the ADOdb_Active_Record::save() method: +<pre> +$person = new Person(); +$person->nameFirst = 'Andi'; +$person->nameLast = 'Gutmans'; +$person->save(); + </pre> +<p> +Oh, no! The above code snippet does not insert a new record into the database. Instead, outputs an error: +<pre> +1048: Column 'name_first' cannot be null + </pre> +<p> +This error occurred because MySQL rejected the INSERT query that was generated by ADOdb_Active_Record. If exceptions are enabled in ADOdb and you are using PHP5, an error will be thrown. In the definition of our table, we specified all of the fields as NOT NULL; i.e., they must contain a value. +<p> +ADOdb_Active_Records are bound by the same contraints as the database tables they represent. If the field in the database cannot be NULL, the corresponding property in the ADOdb_Active_Record also cannot be NULL. In the example above, we failed to set the property $person->favoriteColor, which caused the INSERT to be rejected by MySQL. +<p> +To insert a new ADOdb_Active_Record in the database, populate all of ADOdb_Active_Record's properties so that they satisfy the constraints of the database table, and then call the save() method: +<pre> +/** + * Calling the save() method will successfully INSERT + * this $person into the database table. + */ +$person = new Person(); +$person->name_first = 'Andi'; +$person->name_last = 'Gutmans'; +$person->favorite_color = 'blue'; +$person->save(); +</pre> +<p> +Once this $person has been INSERTed into the database by calling save(), the primary key can now be read as a property. Since this is the first row inserted into our temporary table, its "id" will be 1: +<pre> +var_dump($person->id); + +/** + * Outputs the following: + * string(1) + */ + </pre> +<p> +From this point on, updating it is simply a matter of changing the object's properties and calling the save() method again: + +<pre> +$person->favorite_color = 'red'; +$person->save(); + </pre> +<p> +The code snippet above will change the favorite color to red, and then UPDATE the record in the database. + +<a name=additional> +<h2>ADOdb Specific Functionality</h2> +<h3><li>Setting the Table Name</h3> +<p>The default behaviour on creating an ADOdb_Active_Record is to "pluralize" the class name and + use that as the table name. Often, this is not the case. For example, the Person class could be reading + from the "People" table. +<p>We provide two ways to define your own table: +<p>1. Use a constructor parameter to override the default table naming behaviour. +<pre> + class Person extends ADOdb_Active_Record{} + $person = new Person('People'); +</pre> +<p>2. Define it in a class declaration: +<pre> + class Person extends ADOdb_Active_Record + { + var $_table = 'People'; + } + $person = new Person(); +</pre> + +<h3><li>$ADODB_ASSOC_CASE</h3> +<p>This allows you to control the case of field names and properties. For example, all field names in Oracle are upper-case by default. So you +can force field names to be lowercase using $ADODB_ASSOC_CASE. Legal values are as follows: +<pre> + 0: lower-case + 1: upper-case + 2: native-case +</pre> +<p>So to force all Oracle field names to lower-case, use +<pre> +$ADODB_ASSOC_CASE = 0; +$person = new Person('People'); +$person->name = 'Lily'; +$ADODB_ASSOC_CASE = 2; +$person2 = new Person('People'); +$person2->NAME = 'Lily'; +</pre> + +<p>Also see <a href=http://phplens.com/adodb/reference.constants.adodb_assoc_case.html>$ADODB_ASSOC_CASE</a>. + +<h3><li>ADOdb_Active_Record::Save()</h3> +<p> +Saves a record by executing an INSERT or UPDATE SQL statement as appropriate. +<p>Returns false on unsuccessful INSERT, true if successsful INSERT. +<p>Returns 0 on failed UPDATE, and 1 on UPDATE if data has changed, and -1 if no data was changed, so no UPDATE statement was executed. + +<h3><li>ADOdb_Active_Record::Replace()</h3> +<p> +ADOdb supports replace functionality, whereby the record is inserted if it does not exists, or updated otherwise. +<pre> +$rec = new ADOdb_Active_Record("product"); +$rec->name = 'John'; +$rec->tel_no = '34111145'; +$ok = $rec->replace(); // 0=failure, 1=update, 2=insert +</pre> + + +<h3><li>ADOdb_Active_Record::Load($where)</h3> +<p>Sometimes, we want to load a single record into an Active Record. We can do so using: +<pre> +$person->load("id=3"); + +// or using bind parameters + +$person->load("id=?", array(3)); +</pre> +<p>Returns false if an error occurs. + +<h3><li>ADOdb_Active_Record::Find($whereOrderBy, $bindarr=false, $pkeyArr=false)</h3> +<p>We want to retrieve an array of active records based on some search criteria. For example: +<pre> +class Person extends ADOdb_Active_Record { +var $_table = 'people'; +} + +$person = new Person(); +$peopleArray = $person->Find("name like ? order by age", array('Sm%')); +</pre> + +<h3><li>Error Handling and Debugging</h3> +<p> +In PHP5, if adodb-exceptions.inc.php is included, then errors are thrown. Otherwise errors are handled by returning a value. False by default means an error has occurred. You can get the last error message using the ErrorMsg() function. +<p> +To check for errors in ADOdb_Active_Record, do not poll ErrorMsg() as the last error message will always be returned, even if it occurred several operations ago. Do this instead: +<pre> +# right! +$ok = $rec->Save(); +if (!$ok) $err = $rec->ErrorMsg(); + +# wrong :( +$rec->Save(); +if ($rec->ErrorMsg()) echo "Wrong way to detect error"; +</pre> +<p>The ADOConnection::Debug property is obeyed. So +if $db->debug is enabled, then ADOdb_Active_Record errors are also outputted to standard output and written to the browser. + +<h3><li>ADOdb_Active_Record::Set()</h3> +<p>You can convert an array to an ADOdb_Active_Record using Set(). The array must be numerically indexed, and have all fields of the table defined in the array. The elements of the array must be in the table's natural order too. +<pre> +$row = $db->GetRow("select * from tablex where id=$id"); + +# PHP4 or PHP5 without enabling exceptions +$obj = new ADOdb_Active_Record('Products'); +if ($obj->ErrorMsg()){ + echo $obj->ErrorMsg(); +} else { + $obj->Set($row); +} + +# in PHP5, with exceptions enabled: + +include('adodb-exceptions.inc.php'); +try { + $obj = new ADOdb_Active_Record('Products'); + $obj->Set($row); +} catch(exceptions $e) { + echo $e->getMessage(); +} +</pre> +<p> +<h3><li>Primary Keys</h3> +<p> +ADOdb_Active_Record does not require the table to have a primary key. You can insert records for such a table, but you will not be able to update nor delete. +<p>Sometimes you are retrieving data from a view or table that has no primary key, but has a unique index. You can dynamically set the primary key of a table through the constructor, or using ADOdb_Active_Record::SetPrimaryKeys(): +<pre> + $pkeys = array('category','prodcode'); + + // set primary key using constructor + $rec = new ADOdb_Active_Record('Products', $pkeys); + + // or use method + $rec->SetPrimaryKeys($pkeys); +</pre> + + +<h3><li>Retrieval of Auto-incrementing ID</h3> +When creating a new record, the retrieval of the last auto-incrementing ID is not reliable for databases that do not support the Insert_ID() function call (check $connection->hasInsertID). In this case we perform a <b>SELECT MAX($primarykey) FROM $table</b>, which will not work reliably in a multi-user environment. You can override the ADOdb_Active_Record::LastInsertID() function in this case. + +<h3><li>Dealing with Multiple Databases</h3> +<p> +Sometimes we want to load data from one database and insert it into another using ActiveRecords. This can be done using the optional parameter of the ADOdb_Active_Record constructor. In the following example, we read data from db.table1 and store it in db2.table2: +<pre> +$db = NewADOConnection(...); +$db2 = NewADOConnection(...); + +ADOdb_Active_Record::SetDatabaseAdapter($db2); + +$activeRecs = $db->GetActiveRecords('table1'); + +foreach($activeRecs as $rec) { + $rec2 = new ADOdb_Active_Record('table2',$db2); + $rec2->id = $rec->id; + $rec2->name = $rec->name; + + $rec2->Save(); +} +</pre> +<p> +If you have to pass in a primary key called "id" and the 2nd db connection in the constructor, you can do so too: +<pre> +$rec = new ADOdb_Active_Record("table1",array("id"),$db2); +</pre> + +<h3><li>$ADODB_ACTIVE_CACHESECS</h3> +<p>You can cache the table metadata (field names, types, and other info such primary keys) in $ADODB_CACHE_DIR (which defaults to /tmp) by setting +the global variable $ADODB_ACTIVE_CACHESECS to a value greater than 0. This will be the number of seconds to cache. + You should set this to a value of 30 seconds or greater for optimal performance. + +<h3><li>Active Record Considered Bad?</h3> +<p>Although the Active Record concept is useful, you have to be aware of some pitfalls when using Active Record. The level of granularity of Active Record is individual records. It encourages code like the following, used to increase the price of all furniture products by 10%: +<pre> + $recs = $db->GetActiveRecords("Products","category='Furniture'"); + foreach($recs as $rec) { + $rec->price *= 1.1; // increase price by 10% for all Furniture products + $rec->save(); + } +</pre> +Of course a SELECT statement is superior because it's simpler and much more efficient (probably by a factor of x10 or more): +<pre> + $db->Execute("update Products set price = price * 1.1 where category='Furniture'"); +</pre> +<p>Another issue is performance. For performance sensitive code, using direct SQL will always be faster than using Active Records due to overhead and the fact that all fields in a row are retrieved (rather than only the subset you need) whenever an Active Record is loaded. + +<h3><li>Transactions</h3> +<p> +The default transaction mode in ADOdb is autocommit. So that is the default with active record too. +The general rules for managing transactions still apply. Active Record to the database is a set of insert/update/delete statements, and the db has no knowledge of active records. +<p> +Smart transactions, that does an auto-rollback if an error occurs, is still the best method to multiple activities (inserts/updates/deletes) that need to be treated as a single transaction: +<pre> +$conn->StartTrans(); +$parent->save(); +$child->save(); +$conn->CompleteTrans(); +</pre> + +<h2>ADOConnection Supplement</h2> + +<h3><li>ADOConnection::GetActiveRecords()</h3> +<p> +This allows you to retrieve an array of ADOdb_Active_Records. Returns false if an error occurs. +<pre> +$table = 'products'; +$whereOrderBy = "name LIKE 'A%' ORDER BY Name"; +$activeRecArr = $db->GetActiveRecords($table, $whereOrderBy); +foreach($activeRecArr as $rec) { + $rec->id = rand(); + $rec->save(); +} +</pre> +<p> +And to retrieve all records ordered by specific fields: +<pre> +$whereOrderBy = "1=1 ORDER BY Name"; +$activeRecArr = $db->ADOdb_Active_Records($table); +</pre> +<p> +To use bind variables (assuming ? is the place-holder for your database): +<pre> +$activeRecArr = $db->GetActiveRecords($tableName, 'name LIKE ?', + array('A%')); +</pre> +<p>You can also define the primary keys of the table by passing an array of field names: +<pre> +$activeRecArr = $db->GetActiveRecords($tableName, 'name LIKE ?', + array('A%'), array('id')); +</pre> + +<h3><li>ADOConnection::GetActiveRecordsClass()</h3> +<p> +This allows you to retrieve an array of objects derived from ADOdb_Active_Records. Returns false if an error occurs. +<pre> +class Product extends ADOdb_Active_Records{}; +$table = 'products'; +$whereOrderBy = "name LIKE 'A%' ORDER BY Name"; +$activeRecArr = $db->GetActiveRecordsClass('Product',$table, $whereOrderBy); + +# the objects in $activeRecArr are of class 'Product' +foreach($activeRecArr as $rec) { + $rec->id = rand(); + $rec->save(); +} +</pre> +<p> +To use bind variables (assuming ? is the place-holder for your database): +<pre> +$activeRecArr = $db->GetActiveRecordsClass($className,$tableName, 'name LIKE ?', + array('A%')); +</pre> +<p>You can also define the primary keys of the table by passing an array of field names: +<pre> +$activeRecArr = $db->GetActiveRecordsClass($className,$tableName, 'name LIKE ?', + array('A%'), array('id')); +</pre> + +</ol> + +<h3><li>ADOConnection::ErrorMsg()</h3> +<p>Returns last error message. +<h3><li>ADOConnection::ErrorNo()</h3> +<p>Returns last error number. +<h2>Code Sample</h2> +<p>The following works with PHP4 and PHP5 +<pre> +include('../adodb.inc.php'); +include('../adodb-active-record.inc.php'); + +// uncomment the following if you want to test exceptions +#if (PHP_VERSION >= 5) include('../adodb-exceptions.inc.php'); + +$db = NewADOConnection('mysql://root@localhost/northwind'); +$db->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; + "); + +class Person extends ADOdb_Active_Record{} +$person = new Person(); + +echo "<p>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->nameFirst = 'Andi'; +$person->nameLast = '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 "<p>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'); +var_dump($person2); + +// retrieve an array of records +$activeArr = $db->GetActiveRecordsClass($class = "Person",$table = "persons","id=".$db->Param(0),array(2)); +$person2 = $activeArr[0]; +echo "<p>Name first (should be John): ",$person->name_first, "<br>Class = ",get_class($person2); +</pre> + + <h3>Todo (Code Contributions welcome)</h3> + <p>Check _original and current field values before update, only update changes. Also if the primary key value is changed, then on update, we should save and use the original primary key values in the WHERE clause! + <p>Handle 1-to-many relationships. + <p>PHP5 specific: Make GetActiveRecords*() return an Iterator. + <p>PHP5 specific: Change PHP5 implementation of Active Record to use __get() and __set() for better performance. + +<h3> Change Log</h3> +<p>0.08 +Added support for assoc arrays in Set(). + +<p>0.07 +<p>$ADODB_ASSOC_CASE=2 did not work properly. Fixed. +<p>Added === check in ADODB_SetDatabaseAdapter for $db, adodb-active-record.inc.php. Thx Christian Affolter. + +<p>0.06 +<p>Added ErrorNo(). +<p>Fixed php 5.2.0 compat issues. + +<p>0.05 +<p>If inserting a record and the value of a primary key field is null, then we do not insert that field in as +we assume it is an auto-increment field. Needed by mssql. + +<p>0.04 5 June 2006 <br> +<p>Added support for declaring table name in $_table in class declaration. Thx Bill Dueber for idea. +<p>Added find($where,$bindarr=false) method to retrieve an array of active record objects. + +<p>0.03 <br> +- Now we only update fields that have changed, using $this->_original.<br> +- We do not include auto_increment fields in replace(). Thx Travis Cline<br> +- Added ADODB_ACTIVE_CACHESECS.<br> + +<p>0.02 <br> +- Much better error handling. ErrorMsg() implemented. Throw implemented if adodb-exceptions.inc.php detected.<br> +- You can now define the primary keys of the view or table you are accessing manually.<br> +- The Active Record allows you to create an object which does not have a primary key. You can INSERT but not UPDATE in this case. +- Set() documented.<br> +- Fixed _pluralize bug with y suffix. + +<p> + 0.01 6 Mar 2006<br> +- Fixed handling of nulls when saving (it didn't save nulls, saved them as '').<br> +- Better error handling messages.<br> +- Factored out a new method GetPrimaryKeys().<br> + <p> + 0.00 5 Mar 2006<br> + 1st release +</body> +</html> \ No newline at end of file Added: trunk/linpha2/lib/adodb/docs/docs-adodb.htm =================================================================== --- trunk/linpha2/lib/adodb/docs/docs-adodb.htm (rev 0) +++ trunk/linpha2/lib/adodb/docs/docs-adodb.htm 2008-02-07 23:22:46 UTC (rev 4857) @@ -0,0 +1,3627 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html><head><title>ADODB Manual</title> + +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + + +<style> +pre { + background-color: #eee; + padding: 0.75em 1.5em; + font-size: 12px; + border: 1px solid #ddd; +} +</style></head> +<body bgcolor="#ffffff" text="black"> + +<h2>ADOdb Library for PHP</h2> +<p>V5.03 22 Jan 2008 (c) 2000-2008 John Lim (jlim#natsoft.com)</p> +<p><font size="1">This software is dual licensed using BSD-Style and LGPL. This + means you can use it in compiled proprietary and commercial products.</font></p> + + + <p>Useful ADOdb links: <a href="http://adodb.sourceforge.net/#download">Download</a> <a href="http://adodb.sourceforge.net/#docs">Other Docs</a> + +</p><p><a href="#intro"><b>Introduction</b></a><b><br> + <a href="#features">Unique Features</a><br> + <a href="#users">How People are using ADOdb</a><br> + <a href="#bugs">Feature Requests and Bug Reports</a><br> + </b><b><a href="#install">Installation</a><br> + <a href="#mininstall">Minimum Install</a><br> + <a href="#coding">Initializing Code and Connectioning to Databases</a><br> + </b><font size="2"> <a href="#dsnsupport">Data Source Name (DSN) Support</a></font> <a href="#connect_ex">Connection Examples</a> <br> + <b><a href="#speed">High Speed ADOdb - tuning tips</a></b><br> + <b><a href="#hack">Hacking and Modifying ADOdb Safely</a><br> + <a href="#php5">PHP5 Features</a></b><br> + <font size="2"><a href="#php5iterators">foreach iterators</a> <a href="#php5exceptions">exceptions</a></font><br> + <b> <a href="#drivers">Supported Databases</a></b><br> + <b> <a href="#quickstart">Tutorials</a></b><br> + <a href="#ex1">Example 1: Select</a><br> + <a href="#ex2">Example 2: Advanced Select</a><br> + <a href="#ex3">Example 3: Insert</a><br> + <a href="#ex4">Example 4: Debugging</a> <a href="#exrs2html">rs2html + example</a><br> + <a href="#ex5">Example 5: MySQL and Menus</a><br> + <a href="#ex6">Example 6: Connecting to Multiple Databases at once</a> <br> + <a href="#ex7">Example 7: Generating Update and Insert SQL</a> <br> + <a href="#ex8">Example 8: Implementing Scrolling with Next and Previous</a><br> + <a href="#ex9">Example 9: Exporting in CSV or Tab-Delimited Format</a> <br> + <a href="#ex10">Example 10: Custom filters</a><br> + <a href="#ex11">Example 11: Smart Transactions</a><br> + <br> + <b> <a href="#errorhandling">Using Custom Error Handlers and PEAR_Error</a><br> + <a href="#DSN">Data Source Names</a><br> + <a href="#caching">Caching</a><br> + <a href="#pivot">Pivot Tables</a></b> +</p><p><a href="#ref"><b>REFERENCE</b></a> +</p><p> <font size="2">Variables: <a href="#adodb_countrecs">$ADODB_COUNTRECS</a> +<a href="#adodb_ansi_padding_off">$ADODB_ANSI_PADDING_OFF</a> + <a href="#adodb_cache_dir">$ADODB_CACHE_DIR</a> <br> + <a href="#force_type">$ADODB_FORCE_TYPE</a> + <a href="#adodb_fetch_mode">$ADODB_FETCH_MODE</a> + <a href="#adodb_lang">$ADODB_LANG</a> <a href=#adodb_auto_quote>ADODB_QUOTE_FIELDNAMES</a> <br> + Constants: </font><font size="2"><a href="#adodb_assoc_case">ADODB_ASSOC_CASE</a> + </font><br> + <a href="#ADOConnection"><b> ADOConnection</b></a><br> + <font size="2">Connections: <a href="#connect">Connect</a> <a href="#pconnect">PConnect</a> + <a href="#nconnect">NConnect</a> <a href="#isconnected">IsConnected</a><br> + Executing SQL: <a href="#execute">Execute</a> <a href="#cacheexecute"><i>CacheExecute</i></a> + <a href="#selectlimit">SelectLimit</a> <a href="#cacheSelectLimit"><i>CacheSelectLimit</i></a> + <a href="#param">Param</a> <a href="#prepare">Prepare</a> <a href="#preparesp">PrepareSP</a> + <a href="#inparameter">InParameter</a> <a href="#outparameter">OutParameter</a> <a href="#autoexecute">AutoExecute</a> + <br> + <a href="#getone">GetOne</a> + <a href="#cachegetone"><i>CacheGetOne</i></a> <a href="#getrow">GetRow</a> <a href="#cachegetrow"><i>CacheGetRow</i></a> + <a href="#getall">GetAll</a> <a href="#cachegetall"><i>CacheGetAll</i></a> <a href="#getcol">GetCol</a> + <a href="#cachegetcol"><i>CacheGetCol</i></a> <a href="#getassoc1">GetAssoc</a> <a href="#cachegetassoc"><i>CacheGetAssoc</i></a> <a href="#replace">Replace</a> + <br> + <a href="#executecursor">ExecuteCursor</a> + (oci8 only)<br> + Generates SQL strings: <a href="#getupdatesql">GetUpdateSQL</a> <a href="#getinsertsql">GetInsertSQL</a> + <a href="#concat">Concat</a> <a href="#ifnull">IfNull</a> <a href="#length">length</a> <a href="#random">random</a> <a href="#substr">substr</a> + <a href="#qstr">qstr</a> <a href="#param">Param</a> <a href="#OffsetDate">OffsetDate</a> <a href="#sqldate">SQLDate</a> + <a href="#dbdate">DBDate</a> <a href="#dbtimestamp">DBTimeStamp</a> + <a href="#binddate">BindDate</a> <a href="#bindtimestamp">BindTimeStamp</a> + <br> + Blobs: <a href="#updateblob">UpdateBlob</a> <a href="#updateclob">UpdateClob</a> + <a href="#updateblobfile">UpdateBlobFile</a> <a href="#blobencode">BlobEncode</a> + <a href="#blobdecode">BlobDecode</a><br> + Paging/Scrolling: <a href="#pageexecute">PageExecute</a> <a href="#cachepageexecute">CachePageExecute</a><br> + Cleanup: <a href="#cacheflush">CacheFlush</a> <a href="#Close">Close</a><br> + Transactions: <a href="#starttrans">StartTrans</a> <a href="#completetrans">CompleteTrans</a> + <a href="#failtrans">FailTrans</a> <a href="#hasfailedtrans">HasFailedTrans</a> + <a href="#begintrans">BeginTrans</a> <a href="#committrans">CommitTrans</a> + <a href="#rollbacktrans">RollbackTrans</a> <a href=#SetTransactionMode>SetTransactionMode</a><br> + Fetching Data: </font> <font size="2"><a href="#setfetchmode">SetFetchMode</a><br> + Strings: <a href="#concat">concat</a> <a href="#length">length</a> <a href="#qstr">qstr</a> <a href="#quote">quote</a> <a href="#substr">substr</a><br> + Dates: <a href="#dbdate">DBDate</a> <a href="#dbtimestamp">DBTimeStamp</a> <a href="#unixdate">UnixDate</a> + <a href="#binddate">BindDate</a> <a href="#bindtimestamp">BindTimeStamp</a> + <a href="#unixtimestamp">UnixTimeStamp</a> <a href="#OffsetDate">OffsetDate</a> + <a href="#SQLDate">SQLDate</a> <br> + Row Management: <a href="#affected_rows">Affected_Rows</a> <a href="#inserted_id">Insert_ID</a> <a href="#rowlock">RowLock</a> + <a href="#genid">GenID</a> <a href="#createseq">CreateSequence</a> <a href="#dropseq">DropSequence</a> + <br> + Error Handling: <a href="#errormsg">ErrorMsg</a> <a href="#errorno">ErrorNo</a> + <a href="#metaerror">MetaError</a> <a href="#metaerrormsg">MetaErrorMsg</a> <a href="#ignoreerrors">IgnoreErrors</a><br> + Data Dictionary (metadata): <a href="#metadatabases">MetaDatabases</a> <a href="#metatables">MetaTables</a> + <a href="#metacolumns">MetaColumns</a> <a href="#metacolumnames">MetaColumnNames</a> + <a href="#metaprimarykeys">MetaPrimaryKeys</a> <a href="#metaforeignkeys">MetaForeignKeys</a> + <a href="#serverinfo">ServerInfo</a> <br> + Statistics and Query-Rewriting: <a href="#logsql">LogSQL</a> <a href="#fnexecute">fnExecute + and fnCacheExecute</a><br> + </font><font size="2">Deprecated: <a href="#bind">Bind</a> <a href="#blankrecordset">BlankRecordSet</a> + <a href="#parameter">Parameter</a></font> + <a href="#adorecordSet"><b><br> + ADORecordSet</b></a><br> + <font size="2"> + Returns one field: <a href="#fields">Fields</a><br> + Returns one row:<a href="#fetchrow">FetchRow</a> <a href="#fetchinto">FetchInto</a> + <a href="#fetchobject">FetchObject</a> <a href="#fetchnextobject">FetchNextObject</a> + <a href="#fetchobj">FetchObj</a> <a href="#fetchnextobj">FetchNextObj</a> + <a href="#getrowassoc">GetRowAssoc</a> <br> + Returns all rows:<a href="#getarray">GetArray</a> <a href="#getrows">GetRows</a> + <a href="#getassoc">GetAssoc</a><br> + Scrolling:<a href="#move">Move</a> <a href="#movenext">MoveNext</a> <a href="#movefirst">MoveFirst</a> + <a href="#movelast">MoveLast</a> <a href="#abspos">AbsolutePosition</a> <a href="#currentrow">CurrentRow</a> + <a href="#atfirstpage">AtFirstPage</a> <a href="#atlastpage">AtLastPage</a> + <a href="#absolutepage">AbsolutePage</a> </font> <font size="2"><br> + Menu generation:<a href="#getmenu">GetMenu</a> <a href="#getmenu2">GetMenu2</a><br> + Dates:<a href="#userdate">UserDate</a> <a href="#usertimestamp">UserTimeStamp</a> + <a href="#unixdate">UnixDate</a> <a href="#unixtimestamp">UnixTimeStamp<br> + </a>Recordset Info:<a href="#recordcount">RecordCount</a> <a href="#po_recordcount">PO_RecordCount</a> + <a href="#nextrecordset">NextRecordSet</a><br> + Field Info:<a href="#fieldcount">FieldCount</a> <a href="#fetchfield">FetchField</a> + <a href="#metatype">MetaType</a><br> + Cleanup: <a href="#rsclose">Close</a></font> +</p> +<p><font size="2"><a href="#rs2html"><b>rs2html</b></a> <a href="#exrs2html">example</a></font><br> + <a href="#adodiff">Differences between ADOdb and ADO</a><br> + <a href="#driverguide"><b>Database Driver Guide<br> + </b></a><b><a href="#changes">Change Log</a></b><br> +</p> +<h2>Introduction<a name="intro"></a></h2> +<p>PHP's database access functions are not standardised. This creates a need for + a database class library to hide the differences between the different database + API's (encapsulate the differences) so we can easily switch databases. PHP 4.0.5 or later + is now required (because we use array-based str_replace).</p> +<p>We currently support MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix, + PostgreSQL, FrontBase, SQLite, Interbase (Firebird and Borland variants), Foxpro, Access, ADO, DB2, SAP DB and ODBC. + We have had successful reports of connecting to Progress and CacheLite via ODBC. We hope more people + will contribute drivers to support other databases.</p> +<p>PHP4 supports session variables. You can store your session information using + ADOdb for true portability and scalability. See adodb-session.php for more information.</p> +<p>Also read <a href="http://phplens.com/lens/adodb/tips_portable_sql.htm">tips_portable_sql.htm</a> + for tips on writing + portable SQL.</p> +<h2>Unique Features of ADOdb<a name="features"></a></h2> +<ul> + <li><b>Easy for Windows programmers</b> to adapt to because many of the conventions + are similar to Microsoft's ADO.</li> + <li>Unlike other PHP database classes which focus only on select statements, + <b>we provide support code to handle inserts and updates which can be adapted + to multiple databases quickly.</b> Methods are provided for date handling, + string concatenation and string quoting characters for differing databases.</li> + <li>A<b> metatype system </b>is built in so that we can figure out that types + such as CHAR, TEXT and STRING are equivalent in different databases.</li> + <li><b>Easy to port</b> because all the database dependant code are stored in + stub functions. You do not need to port the core logic of the classes.</li> + <li><b>Portable table and index creation</b> with the <a href="docs-datadict.htm">datadict</a> classes. + </li><li><b>Database performance monitoring and SQL tuning</b> with the <a href="docs-perf.htm">performance monitoring</a> classes. + </li><li><b>Database-backed sessions</b> with the <a href="docs-session.htm">session management</a> classes. Supports session expiry notification. +<li><b>Object-Relational Mapping</b> using <a href="docs-active-record.htm">ADOdb_Active_Record</a> classes. +</li></ul> +<h2>How People are using ADOdb<a name="users"></a></h2> +Here are some examples of how people are using ADOdb (for a much longer list, +visit <a href="http://phplens.com/phpeverywhere/adodb-cool-apps">adodb-cool-apps</a>): +<ul> +<li><a href="http://phplens.com/">PhpLens</a> is a commercial data grid +component that allows both cool Web designers and serious unshaved +programmers to develop and maintain databases on the Web easily. +Developed by the author of ADOdb.<p> + +</p></li><li><a href="http://www.interakt.ro/phakt/">PHAkt: PHP Extension for DreamWeaver Ultradev</a> allows you to script PHP in the popular Web page editor. Database handling provided by ADOdb.<p> + +</p></li><li><a href="http://www.andrew.cmu.edu/%7Erdanyliw/snort/snortacid.html">Analysis Console for Intrusion Databases</a> +(ACID): PHP-based analysis engine to search and process a database of +security incidents generated by security-related software such as IDSes +and firewalls (e.g. Snort, ipchains). By Roman Danyliw.<p> + +</p></li><li><a href="http://www.postnuke.com/">PostNuke</a> is a very +popular free content management system and weblog system. It offers +full CSS support, HTML 4.01 transitional compliance throughout, an +advanced blocks system, and is fully multi-lingual enabled. <p> + +</p></li><li><a href="http://www.auto-net.no/easypublish.php?page=index&lang_id=2">EasyPublish CMS</a> +is another free content management system for managing information and +integrated modules on your internet, intranet- and extranet-sites. From +Norway.<p> + +</p></li><li><a href="http://nola.noguska.com/">NOLA</a> is a full featured accounting, inventory, and job tracking application. It is licensed under the GPL, and developed by Noguska. +</li></ul><p> + +</p><h2>Feature Requests and Bug Reports<a name="bugs"></a></h2> +<p>Feature requests and bug reports can be emailed to <a href="mailto:jlim#natsoft.com.my">jlim#natsoft.com.my</a> + or posted to the ADOdb Help forums at <a href="http://phplens.com/lens/lensforum/topics.php?id=4">http://phplens.com/lens/lensforum/topics.php?id=4</a>.</p> +<h2>Installation Guide<a name="install"></a></h2> +<p>Make sure you are running PHP 4.0.5 or later. + Unpack all the files into a directory accessible by your webserver.</p> +<p>To test, try modifying some of the tutorial examples. Make sure you customize + the connection settings correctly. You can debug using <i>$db->debug = true</i> as shown below:</p> +<pre><?php<br> include('adodb/adodb.inc.php');<br> $db = <a href="#adonewconnection">ADONewConnection</a>($dbdriver); # eg 'mysql' or 'postgres'<br> $db->debug = true;<br> $db-><a href="#connect">Connect</a>($server, $user, $password, $database);<br> $rs = $db-><a href="#execute">Execute</a>('select * from some_small_table');<br> print "<pre>";<br> print_r($rs-><a href="#getrows">GetRows</a>());<br> print "</pre>";<br>?></pre> + + <h3>Minimum Install<a name="mininstall"></a></h3> +<p>For developers who want to release a minimal install of ADOdb, you will need: +</p><ul> +<li>adodb.inc.php +</li><li>adodb-lib.inc.php +</li><li>adodb-time.inc.php +</li><li>drivers/adodb-$database.inc.php +</li><li>license.txt (for legal reasons) +</li><li>adodb-php4.inc.php +</li><li>adodb-iterator.inc.php (php5 functionality) +</li></ul> +Optional: +<ul> +<li>adodb-error.inc.php and lang/adodb-$lang.inc.php (if you use MetaError()) +</li><li>adodb-csvlib.inc.php (if you use cached recordsets - CacheExecute(), etc) +</li><li>adodb-exceptions.inc.php and adodb-errorhandler.inc.php (if you use adodb error handler or php5 exceptions). +<li>adodb-active-record.inc.php if you use <a href=docs-active-record.htm>Active Records</a>. +</li></ul> + +<h3>Code Initialization Examples<a name="coding"></a></h3> +<p>When running ADOdb, at least two files are loaded. First is adodb/adodb.inc.php, + which contains all functions used by all database classes. The code specific + to a particular database is in the adodb/driver/adodb-????.inc.php file.</p> + <a name="adonewconnection"></a> +<p>For example, to connect to a mysql database:</p> +<pre>include('/path/to/set/here/adodb.inc.php');<br>$conn =ADONewConnection('mysql');<br></pre> +<p>Whenever you need to connect to a database, you create a Connection object + using the <b>ADONewConnection</b>($driver) function. + <b>NewADOConnection</b>($driver) is an alternative name for the same function.</p> + +<p>At this point, you are not connected to the database (no longer true if you pass in a <a href="#dsnsupport">dsn</a>). You will first need to decide +whether to use <i>persistent</i> or <i>non-persistent</i> connections. The advantage of <i>persistent</i> +connections is that they are faster, as the database connection is never closed (even +when you call Close()). <i>Non-persistent </i>connections take up much fewer resources though, +reducing the risk of your database and your web-server becoming overloaded. +</p><p>For persistent connections, +use $conn-><a href="#pconnect">PConnect()</a>, + or $conn-><a href="#connect">Connect()</a> for non-persistent connections. +Some database drivers also support <a href="#nconnect">NConnect()</a>, which forces +the creation of a new connection. + +<a name="connection_gotcha"></a> +</p><p><b>Connection Gotcha</b>: If you create two connections, but both use the same userid and password, +PHP will share the same connection. This can cause problems if the connections are meant to +different databases. The solution is to always use different userid's for different databases, + or use NConnect(). + + <a name="dsnsupport"></a> + </p><h3>Data Source Name (DSN) Support</h3> + <p> Since ADOdb 4.51, you can connect to a database by passing a dsn to NewADOConnection() (or ADONewConnection, which is + the same function). The dsn format is: +</p><pre> $driver://$username:$password@hostname/$database?options[=value]<br></pre><p> +NewADOConnection() calls Connect() or PConnect() internally for you. If the connection fails, false is returned. +</p><pre> <font color="#008000"># non-persistent connection</font> + $dsn = 'mysql://root:pwd@localhost/mydb'; + $db = NewADOConnection($dsn); + if (!$db) die("Connection failed"); + + <font color="#008000"># no need to call connect/pconnect!</font> + $arr = $db->GetArray("select * from table"); + + <font color="#008000"># persistent connection</font> + $dsn2 = 'mysql://root:pwd@localhost/mydb?persist'; +</pre> +<p> +If you have special characters such as /:?_ in your dsn, then you need to rawurlencode them first: +</p><pre> $pwd = rawurlencode($pwd);<br> $dsn = "mysql://root:$pwd@localhost/mydb"; + $dsn2=rawurlencode("sybase_ase")."://user:pass@host/path?query";<br></pre> +<p> +Legal options are: +</p><p> +<table align="center" border="1"><tbody><tr><td>For all drivers</td><td> + 'persist', 'persistent', 'debug', 'fetchmode', 'new' + </td></tr><tr><td>Interbase/Firebird + </td><td> + 'dialect','charset','buffers','role' + </td></tr><tr><td>M'soft ADO</td><td> + 'charpage' + + </td></tr><tr><td>MySQL</td><td> + 'clientflags' +</td></tr><tr><td>MySQLi</td><td> + 'port', 'socket', 'clientflags' +</td></tr><tr><td>Oci8</td><td> + 'nls_date_format','charset' +</td></tr></tbody></table> +</p><p> +For all drivers, when the options <i>persist</i> or <i>persistent</i> are set, a persistent connection is forced; similarly, when <i>new</i> is set, then +a new connection will be created using NConnect if the underlying driver supports it. +The <i>debug</i> option enables debugging. The <i>fetchmode</i> calls <a href="#setfetchmode">SetFetchMode()</a>. +If no value is defined for an option, then the value is set to 1. +</p><p> +ADOdb DSN's are compatible with version 1.0 of PEAR DB's DSN format. +<a name="connect_ex"> +</a></p><h3><a name="connect_ex">Examples of Connecting to Databases</a></h3> +<h4><a name="connect_ex">MySQL and Most Other Database Drivers</a></h4> +<p><a name="connect_ex">MySQL connections are very straightforward, and the parameters are identical + to mysql_connect:</a></p> +<pre><a name="connect_ex"> $conn =ADONewConnection('mysql'); <br> $conn->PConnect('localhost','userid','password','database');<br> <br> <font color="#008000"># or dsn </font> + $dsn = 'mysql://user:pwd@localhost/mydb'; + $conn = ADONewConnection($dsn); # no need for Connect() + + <font color="#008000"># or persistent dsn</font> + $dsn = 'mysql://user:pwd@localhost/mydb?persist'; + $conn = ADONewConnection($dsn); # no need for PConnect() + + <font color="#008000"># a more complex example:</font> + $pwd = urlencode($pwd); + $flags = MYSQL_CLIENT_COMPRESS; + $dsn = "mysql://user:$pwd@localhost/mydb?persist&clientflags=$flags"; + $conn = ADONewConnection($dsn); # no need for PConnect() + </a></pre> +<p><a name="connect_ex"> For most drivers, you can use the standard function: Connect($server, $user, $password, $database), or +a </a><a href="dsnsupport">DSN</a> since ADOdb 4.51. Exceptions to this are listed below. +</p> +<a name=pdo> +<h4>PDO</h4> +<p>PDO, which only works with PHP5, accepts a driver specific connection string: +<pre> + $conn = NewADOConnection('pdo'); + $conn->Connect('mysql:host=localhost',$user,$pwd,$mydb); + $conn->Connect('mysql:host=localhost;dbname=mydb',$user,$pwd); + $conn->Connect("mysql:host=localhost;dbname=mydb;username=$user;password=$pwd"); +</pre> +<p>The DSN mechanism is also supported: +<pre> + $conn = NewADOConnection("pdo_mysql://user:pwd@localhost/mydb?persist"); # persist is optional +</pre> +<h4>PostgreSQL</h4> +<p>PostgreSQL 7 and 8 accepts connections using: </p> +<p>a. the standard connection string:</p> +<pre> $conn = ADONewConnection('postgres'); <br> $conn->PConnect('host=localhost port=5432 dbname=mary');</pre> +<p> b. the classical 4 parameters:</p> + <pre> $conn->PConnect('localhost','userid','password','database');<br> </pre> +<p>c. dsn: +</p><pre> $dsn = 'postgres://user:pwd@localhost/mydb?persist'; # persist is optional + $conn = ADONewConnection($dsn); # no need for Connect/PConnect<br></pre> +<a name="ldap"></a> + + <h4>LDAP</h4> + <p>Here is an example of querying a LDAP server. Thanks to Josh Eldridge for the driver and this example: +</p><pre> +require('/path/to/adodb.inc.php'); + +/* Make sure to set this BEFORE calling Connect() */ +$LDAP_CONNECT_OPTIONS = Array( + Array ("OPTION_NAME"=>LDAP_OPT_DEREF, "OPTION_VALUE"=>2), + Array ("OPTION_NAME"=>LDAP_OPT_SIZELIMIT,"OPTION_VALUE"=>100), + Array ("OPTION_NAME"=>LDAP_OPT_TIMELIMIT,"OPTION_VALUE"=>30), + Array ("OPTION_NAME"=>LDAP_OPT_PROTOCOL_VERSION,"OPTION_VALUE"=>3), + Array ("OPTION_NAME"=>LDAP_OPT_ERROR_NUMBER,"OPTION_VALUE"=>13), + Array ("OPTION_NAME"=>LDAP_OPT_REFERRALS,"OPTION_VALUE"=>FALSE), + Array ("OPTION_NAME"=>LDAP_OPT_RESTART,"OPTION_VALUE"=>FALSE) +); +$host = 'ldap.baylor.edu'; +$ldapbase = 'ou=People,o=Baylor University,c=US'; + +$ldap = NewADOConnection( 'ldap' ); +$ldap->Connect( $host, $user_name='', $password='', $ldapbase ); + +echo "<pre>"; + +print_r( $ldap->ServerInfo() ); +$ldap->SetFetchMode(ADODB_FETCH_ASSOC); +$userName = 'eldridge'; +$filter="(|(CN=$userName*)(sn=$userName*)(givenname=$userName*)(uid=$userName*))"; + +$rs = $ldap->Execute( $filter ); +if ($rs) + while ($arr = $rs->FetchRow()) { + print_r($arr); + } + +$rs = $ldap->Execute( $filter ); +if ($rs) + while (!$rs->EOF) { + print_r($rs->fields); + $rs->MoveNext(); + } + +print_r( $ldap->GetArray( $filter ) ); +print_r( $ldap->GetRow( $filter ) ); + +$ldap->Close(); +echo "</pre>"; +</pre> +<p>Using DSN: +<pre> +$dsn = "ldap://ldap.baylor.edu/ou=People,o=Baylor University,c=US"; +$db = NewADOConnection($dsn); +</pre> +<h4>Interbase/Firebird</h4> +You define the database in the $host parameter: +<pre> $conn =ADONewConnection('ibase'); <br> $conn->PConnect('localhost:c:\ibase\employee.gdb','sysdba','masterkey');<br></pre> +<p>Or dsn: +</p><pre> $dsn = 'firebird://user:pwd@localhost/mydb?persist&dialect=3'; # persist is optional<br> $conn = ADONewConnection($dsn); # no need for Connect/PConnect<br></pre> +<h4>SQLite</h4> +Sqlite will create the database file if it does not exist. +<pre> $conn =ADONewConnection('sqlite'); + $conn->PConnect('c:\path\to\sqlite.db'); # sqlite will create if does not exist<br></pre> +<p>Or dsn: +</p><pre> $path = urlencode('c:\path\to\sqlite.db'); + $dsn = "sqlite://$path/?persist"; # persist is optional + $conn = ADONewConnection($dsn); # no need for Connect/PConnect<br></pre> +<h4>Oracle (oci8)</h4> +<p>With oci8, you can connect in multiple ways. Note that oci8 works fine with +newer versions of the Oracle, eg. 9i and 10g.</p> +<p>a. PHP and Oracle reside on the same machine, use default SID.</p> +<pre> $conn->Connect(false, 'scott', 'tiger');</pre> +<p>b. TNS Name defined in tnsnames.ora (or ONAMES or HOSTNAMES), eg. 'myTNS'</p> +<pre> $conn->PConnect(false, 'scott', 'tiger', 'myTNS');</pre> +<p>or</p> +<pre> $conn->PConnect('myTNS', 'scott', 'tiger');</pre> +<p>c. Host Address and SID</p> +<pre> + $conn->connectSID = true; + $conn->Connect('192.168.0.1', 'scott', 'tiger', 'SID');</pre> +<p>d. Host Address and Service Name</p> +<pre> $conn->Connect('192.168.0.1', 'scott', 'tiger', 'servicename');</pre> +<p>e. Oracle connection string: +</p><pre> $cstr = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=$host)(PORT=$port))<br> (CONNECT_DATA=(SID=$sid)))";<br> $conn->Connect($cstr, 'scott', 'tiger');<br></pre> +<p>f. ADOdb dsn: +</p><pre> $dsn = 'oci8://user:pwd@tnsname/?persist'; # persist is optional<br> $conn = ADONewConnection($dsn); # no need for Connect/PConnect<br> <br> $dsn = 'oci8://user:pwd@host/sid';<br> $conn = ADONewConnection($dsn);<br> <br> $dsn = 'oci8://user:pwd@/'; # oracle on local machine<br> $conn = ADONewConnection($dsn);<br></pre> +<p>You can also set the charSet for Oracle 9.2 and later, supported since PHP 4.3.2, ADOdb 4.54: +</p><pre> $conn->charSet = 'we8iso8859p1';<br> $conn->Connect(...);<br> <br> # or<br> $dsn = 'oci8://user:pwd@tnsname/?charset=WE8MSWIN1252';<br> $db = ADONewConnection($dsn);<br></pre> +<a name="dsnless"></a> +<h4>DSN-less ODBC ( Access, MSSQL and DB2 examples)</h4> +<p>ODBC DSN's can be created in the ODBC control panel, or you can use a DSN-less + connection.To use DSN-less connections with ODBC you need PHP 4.3 or later. +</p> +<p>For Microsoft Access:</p> +<pre> $db = ADONewConnection('access');<br> $dsn = <strong>"Driver={Microsoft Access Driver (*.mdb)};Dbq=d:\\northwind.mdb;Uid=Admin;Pwd=;";</strong> + $db->Connect($dsn); +</pre> +For Microsoft SQL Server: +<pre> $db = ADONewConnection('odbc_mssql');<br> $dsn = <strong>"Driver={SQL Server};Server=localhost;Database=northwind;"</strong>;<br> $db->Connect($dsn,'userid','password');<br></pre> +or if you prefer to use the mssql extension (which is limited to mssql 6.5 functionality): +<pre> $db = ADONewConnection('mssql');<br> $db->Execute('localhost', 'userid', 'password', 'northwind');<br></pre> +For DB2: +<pre> + $dbms = 'db2'; # or 'odbc_db2' if db2 extension not available + $db = ADONewConnection($dbms); + $dsn = "driver={IBM db2 odbc DRIVER};Database=sample;hostname=localhost;port=50000;protocol=TCPIP;". + "uid=root; pwd=secret";<br> $db->Connect($dsn); +</pre> +<b>DSN-less Connections with ADO</b><br> +If you are using versions of PHP earlier than PHP 4.3.0, DSN-less connections +only work with Microsoft's ADO, which is Microsoft's COM based API. An example +using the ADOdb library and Microsoft's ADO: +<pre><?php<br> include('adodb.inc.php'); <br> $db =ADONewConnection("ado_mssql");<br> print "<h1>Connecting DSN-less $db->databaseType...</h1>";<br> <br> <b>$myDSN="PROVIDER=MSDASQL;DRIVER={SQL Server};"<br> . "SERVER=flipper;DATABASE=ai;UID=sa;PWD=;" ;</b> + $db->Connect($myDSN); + + $rs = $db->Execute("select * from table"); + $arr = $rs->GetArray(); + print_r($arr); +?> +</pre><a name="speed"></a> +<h2>High Speed ADOdb - tuning tips</h2> +<p>ADOdb is a big class library, yet it <a href="http://phplens.com/lens/adodb/">consistently beats</a> all other PHP class + libraries in performance. This is because it is designed in a layered fashion, + like an onion, with the fastest functions in the innermost layer. Stick to the + following functions for best performance:</p> +<table align="center" border="1" width="40%"> + <tbody><tr> + <td><div align="center"><b>Innermost Layer</b></div></td> + </tr> + <tr> + <td><p align="center">Connect, PConnect, NConnect<br> + Execute, CacheExecute<br> + SelectLimit, CacheSelectLimit<br> + MoveNext, Close <br> + qstr, Affected_Rows, Insert_ID</p></td> + </tr> +</tbody></table> +<p>The fastest way to access the field data is by accessing the array $recordset->fields + directly. Also set the global variables <a href="#adodb_fetch_mode">$ADODB_FETCH_MODE</a> + = ADODB_FETCH_NUM, and (for oci8, ibase/firebird and odbc) <a href="#adodb_countrecs">$ADODB_COUNTRECS</a> = false + before you connect to your database.</p> +<p>Consider using bind parameters if your database supports it, as it improves + query plan reuse. Use ADOdb's performance tuning system to identify bottlenecks + quickly. At the time of writing (Dec 2003), this means oci8 and odbc drivers.</p> + <p>Lastly make sure you have a PHP accelerator cache installed such as APC, Turck + MMCache, Zend Accelerator or ionCube.</p> + <p>Some examples:</p> + <table align="center" border="1"><tbody><tr><td><b>Fastest data retrieval using PHP</b></td><td><b>Fastest data retrieval using ADOdb extension</b></td></tr> +<tr><td> +<pre>$rs = $rs->Execute($sql);<br>while (!$rs->EOF) {<br> var_dump($rs->fields);<br> $rs->MoveNext();<br>}</pre></td><td> +<pre>$rs = $rs->Execute($sql);<br>$array = adodb_getall($rs);<br>var_dump($array);<br><br><br></pre></td></tr></tbody></table> + <p><b>Advanced Tips</b> + </p><p>If you have the <a href="http://adodb.sourceforge.net/#extension">ADOdb C extension</a> installed, + you can replace your calls to $rs->MoveNext() with adodb_movenext($rs). + This doubles the speed of this operation. For retrieving entire recordsets at once, +use GetArray(), which uses the high speed extension function adodb_getall($rs) internally. + </p><p>Execute() is the default way to run queries. You can use the low-level functions _Execute() and _query() +to reduce query overhead. Both these functions share the same parameters as Execute(). +</p><p>If you do not have any bind parameters or your database supports +binding (without emulation), +then you can call _Execute() directly. Calling this function bypasses +bind emulation. Debugging is still supported in _Execute(). +</p><p>If you do not require debugging facilities nor emulated +binding, and do not require a recordset to be returned, then you can +call _query. This is great for inserts, updates and deletes. Calling +this function +bypasses emulated binding, debugging, and recordset handling. Either +the resultid, true or false are returned by _query(). </p><p>For Informix, you can disable scrollable cursors with $db->cursorType = 0. +</p><p><a name="hack"></a> </p> +<h2>Hacking ADOdb Safely</h2> +<p>You might want to modify ADOdb for your own purposes. Luckily you can +still maintain backward compatibility by sub-classing ADOdb and using the $ADODB_NEWCONNECTION +variable. $ADODB_NEWCONNECTION allows you to override the behaviour of ADONewConnection(). +ADOConnection() checks for this variable and will call +the function-name stored in this variable if it is defined. +</p><p>In the following example, new functionality for the connection object +is placed in the <i>hack_mysql</i> and <i>hack_postgres7</i> classes. The recordset class naming convention +can be controlled using $rsPrefix. Here we set it to 'hack_rs_', which will make ADOdb use +<i>hack_rs_mysql</i> and <i>hack_rs_postgres7</i> as the recordset classes. + + +</p><pre>class hack_mysql extends adodb_mysql {<br>var $rsPrefix = 'hack_rs_';<br> /* Your mods here */<br>}<br><br>class hack_rs_mysql extends ADORecordSet_mysql {<br> /* Your mods here */<br>}<br><br>class hack_postgres7 extends adodb_postgres7 {<br>var $rsPrefix = 'hack_rs_';<br> /* Your mods here */<br>}<br><br>class hack_rs_postgres7 extends ADORecordSet_postgres7 {<br> /* Your mods here */<br>}<br><br>$ADODB_NEWCONNECTION = 'hack_factory';<br><br>function hack_factory($driver)<br>{<br> if ($driver !== 'mysql' && $driver !== 'postgres7') return false;<br> <br> $driver = 'hack_'.$driver;<br> $obj = new $driver();<br> return $obj;<br>}<br><br>include_once('adodb.inc.php');<br></pre> +<p></p><p>Don't forget to call the constructor of the parent class in +your constructor. If you want to use the default ADOdb drivers return +false in the above hack_factory() function. + Also you can define your own ADORecordSet_empty() class, by defining a class $$this->rsPrefix.'empty' since 4.96/5.02. +<a name="php5"></a> +</p><h2>PHP5 Features</h2> + ADOdb 4.02 or later will transparently determine which version of PHP you are using. +If PHP5 is detected, the following features become available: +<ul> + +<li><b>PDO</b>: PDO drivers are available. See the <a href=#pdo>connection examples</a>. Currently PDO drivers are + not as powerful as native drivers, and should be treated as experimental.<br><br> +<a name="php5iterators"></a> +<li><b>Foreach iterators</b>: This is a very natural way of going through a recordset: +<pre> $ADODB_FETCH_MODE = ADODB_FETCH_NUM;<br> $rs = $db->Execute($sql);<br> foreach($rs as $k =gt; $row) {<br> echo "r1=".$row[0]." r2=".$row[1]."<br>";<br> }<br></pre> +<p> +<a name="php5exceptions"></a> +</p></li><li><b>Exceptions</b>: Just include <i>adodb-exceptions.inc.php</i> and you can now +catch exceptions on errors as they occur. +<pre> <b>include("../adodb-exceptions.inc.php");</b> <br> include("../adodb.inc.php"); <br> try { <br> $db = NewADOConnection("oci8"); <br> $db->Connect('','scott','bad-password'); <br> } catch (exception $e) { <br> var_dump($e); <br> adodb_backtrace($e->gettrace());<br> } <br></pre> +<p>Note that reaching EOF is <b>not</b> considered an error nor an exception. +</p></li></ul> +<h3><a name="drivers"></a>Databases Supported</h3> +The <i>name</i> below is the value you pass to NewADOConnection($name) to create a connection object for that database. +<p> +</p><p> +</p><table border="1" width="100%"> + <tbody><tr valign="top"> + <td><b>Name</b></td> + <td><b>Tested</b>... [truncated message content] |