[Phplib-commit] CVS: php-lib/php/db/odbc db_sql.inc,1.1,1.2
Brought to you by:
nhruby,
richardarcher
From: Richard A. <ric...@us...> - 2001-08-26 12:13:49
|
Update of /cvsroot/phplib/php-lib/php/db/odbc In directory usw-pr-cvs1:/tmp/cvs-serv12719 Modified Files: db_sql.inc Log Message: Major overhaul to the ODBC abstraction class. Brings the style up to date with the MySQL driver. Table locking and sequence numbers are still not implemented. Fixes numerous bugs, especially in num_rows. Index: db_sql.inc =================================================================== RCS file: /cvsroot/phplib/php-lib/php/db/odbc/db_sql.inc,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** db_sql.inc 2000/04/13 13:06:59 1.1 --- db_sql.inc 2001/08/26 12:13:46 1.2 *************** *** 3,7 **** * Session Management for PHP3 * ! * Copyright (c) 1998,1999 Cameron Taggart (cam...@wo...) * Modified by Guarneri carmelo (ca...@me...) * --- 3,7 ---- * Session Management for PHP3 * ! * Copyright (c) 1998-2000 Cameron Taggart (cam...@wo...) * Modified by Guarneri carmelo (ca...@me...) * *************** *** 10,43 **** class DB_Sql { var $Host = ""; var $Database = ""; var $User = ""; var $Password = ""; - var $UseODBCCursor = 0; ! var $Link_ID = 0; ! var $Query_ID = 0; var $Record = array(); var $Row = 0; ! var $Errno = 0; var $Error = ""; ! var $Auto_Free = 0; ## set this to 1 to automatically free results ! function connect() { if ( 0 == $this->Link_ID ) { ! $this->Link_ID=odbc_pconnect($this->Database, $this->User, $this->Password, $this->UseODBCCursor); if (!$this->Link_ID) { ! $this->halt("Link-ID == false, odbc_pconnect failed"); } } } ! function query($Query_String) { ! $this->connect(); ! ! # printf("<br>Debug: query = %s<br>\n", $Query_String); # re...@ne... suggested that we use this instead of the odbc_exec(). # He is on NT, connecting to a Unix MySQL server with ODBC. -- KK --- 10,113 ---- class DB_Sql { + + /* public: connection parameters */ var $Host = ""; var $Database = ""; var $User = ""; var $Password = ""; ! /* public: configuration parameters */ ! var $Auto_Free = 0; ## Set to 1 to automatically free results ! var $Debug = 0; ## Set to 1 for debugging messages ! var $Halt_On_Error = "yes"; ## "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore errror, but spit a warning) ! var $Seq_Table = "db_sequence"; ## Name of the sequence table ! var $Seq_ID_Col = "p_nextid"; ## Name of the Sequence ID column in $Seq_Tab ! var $Seq_Name_Col = "p_seq_name"; ## Name of the Sequence Name column in $Seq_Tab ! var $UseODBCCursor = 0; ## Set to 1 to enable execution of stored procedures on the server ! ! /* public: result array and current row number */ var $Record = array(); var $Row = 0; ! var $RowCount = -1; ## used to remember num_rows() return value ! ! /* public: current error number and error text */ var $Errno = 0; var $Error = ""; ! /* public: this is an api revision, not a CVS revision. */ ! var $type = "odbc"; ! var $revision = "1.2"; ! /* private: link and query handles */ ! var $Link_ID = 0; ! var $Query_ID = 0; ! ! ! /* public: constructor */ ! function DB_Sql($query = "") { ! $this->query($query); ! } ! ! /* public: some trivial reporting */ ! function link_id() { ! return $this->Link_ID; ! } ! ! function query_id() { ! return $this->Query_ID; ! } ! ! /* public: connection management */ ! function connect($Database = "", $Host = "", $User = "", $Password = "") { ! /* Handle defaults */ ! if ("" == $Database) ! $Database = $this->Database; ! if ("" == $Host) ! $Host = $this->Host; ! if ("" == $User) ! $User = $this->User; ! if ("" == $Password) ! $Password = $this->Password; ! ! /* establish connection, select database */ if ( 0 == $this->Link_ID ) { ! $this->Link_ID=odbc_pconnect($Database, $User, $Password, $this->UseODBCCursor); if (!$this->Link_ID) { ! $this->halt("odbc_pconnect failed"); ! return 0; } } + + return $this->Link_ID; } ! ! /* public: discard the query result */ ! function free() { ! odbc_free_result($this->Query_ID); ! $this->Query_ID = 0; ! } ! ! /* public: perform a query */ function query($Query_String) { ! /* No empty queries, please, since PHP4 chokes on them. */ ! if ($Query_String == "") ! /* The empty query string is passed on from the constructor, ! * when calling the class without a query, e.g. in situations ! * like these: '$db = new DB_Sql_Subclass;' ! */ ! return 0; ! ! if (!$this->connect()) { ! return 0; /* we already complained in connect() about that. */ ! }; ! ! # New query, discard previous result. ! if ($this->Query_ID) { ! $this->free(); ! } + if ($this->Debug) + printf("Debug: query = %s<br>\n", $Query_String); + # re...@ne... suggested that we use this instead of the odbc_exec(). # He is on NT, connecting to a Unix MySQL server with ODBC. -- KK *************** *** 46,117 **** $this->Query_ID = odbc_exec($this->Link_ID,$Query_String); ! $this->Row = 0; odbc_binmode($this->Query_ID, 1); odbc_longreadlen($this->Query_ID, 4096); if (!$this->Query_ID) { - $this->Errno = 1; - $this->Error = "General Error (The ODBC interface cannot return detailed error messages)."; $this->halt("Invalid SQL: ".$Query_String); } return $this->Query_ID; } ! function next_record() { $this->Record = array(); ! $stat = odbc_fetch_into($this->Query_ID, ++$this->Row, &$this->Record); if (!$stat) { if ($this->Auto_Free) { ! odbc_free_result($this->Query_ID); ! $this->Query_ID = 0; ! }; } else { - // add to Record[<key>] $count = odbc_num_fields($this->Query_ID); ! for ($i=1; $i<=$count; $i++) ! $this->Record[strtolower(odbc_field_name ($this->Query_ID, $i)) ] = $this->Record[ $i - 1 ]; } return $stat; } ! ! function seek($pos) { $this->Row = $pos; } ! function metadata($table) { ! $count = 0; ! $id = 0; ! $res = array(); ! ! $this->connect(); ! $id = odbc_exec($this->Link_ID, "select * from $table"); ! if (!$id) { ! $this->Errno = 1; ! $this->Error = "General Error (The ODBC interface cannot return detailed error messages)."; ! $this->halt("Metadata query failed."); ! } ! $count = odbc_num_fields($id); ! ! for ($i=1; $i<=$count; $i++) { ! $res[$i]["table"] = $table; ! $name = odbc_field_name ($id, $i); ! $res[$i]["name"] = $name; ! $res[$i]["type"] = odbc_field_type ($id, $name); ! $res[$i]["len"] = 0; // can we determine the width of this column? ! $res[$i]["flags"] = ""; // any optional flags to report? ! } ! ! odbc_free_result($id); ! return $res; } function affected_rows() { return odbc_num_rows($this->Query_ID); } ! function num_rows() { # Many ODBC drivers don't support odbc_num_rows() on SELECT statements. $num_rows = odbc_num_rows($this->Query_ID); - //printf ($num_rows."<br>"); # This is a workaround. It is intended to be ugly. --- 116,193 ---- $this->Query_ID = odbc_exec($this->Link_ID,$Query_String); ! $this->RowCount = -1; # reset num_rows() return value ! $this->Row = 0; ! $this->Errno = 0; ! $this->Error = ""; odbc_binmode($this->Query_ID, 1); odbc_longreadlen($this->Query_ID, 4096); if (!$this->Query_ID) { $this->halt("Invalid SQL: ".$Query_String); } + + # Will return nada if it fails. That's fine. return $this->Query_ID; } ! ! /* public: walk result set */ function next_record() { + if (!$this->Query_ID) { + $this->halt("next_record called with no query pending."); + return 0; + } + $this->Record = array(); ! $this->Row += 1; ! $stat = odbc_fetch_row($this->Query_ID, $this->Row); ! $this->Errno = 0; ! $this->Error = ""; ! if (!$stat) { if ($this->Auto_Free) { ! $this->free(); ! } } else { $count = odbc_num_fields($this->Query_ID); ! for ($i=1; $i<=$count; $i++) { ! $this->Record[strtolower(odbc_field_name($this->Query_ID, $i))] = odbc_result($this->Query_ID, $i); ! } } return $stat; } ! ! /* public: position in result set */ ! function seek($pos = 0) { $this->Row = $pos; + return 1; } ! /* public: table locking */ ! function lock($table, $mode="write") { ! $this->halt("Does " . $this->type ." have table locking functions?"); ! return false; } + function unlock() { + $this->halt("Does " . $this->type ." have table locking functions?"); + return false; + } + + /* public: evaluate the result (size, width) */ function affected_rows() { return odbc_num_rows($this->Query_ID); } ! function num_rows() { + # Due to a strange problem with the odbc_fetch_row function it is only + # possible to walk through the result set once. By storing the row count + # this problem is avoided. + # Once the number of rows has been calculated it is stored in $RowCount. + if ($this->RowCount != -1) { + return $this->RowCount; + } + # Many ODBC drivers don't support odbc_num_rows() on SELECT statements. $num_rows = odbc_num_rows($this->Query_ID); # This is a workaround. It is intended to be ugly. *************** *** 139,172 **** } return $num_rows; } ! function num_fields() { return count($this->Record)/2; } function nf() { return $this->num_rows(); } ! function np() { print $this->num_rows(); } ! ! function f($Field_Name) { ! return $this->Record[strtolower($Field_Name)]; } ! ! function p($Field_Name) { ! print $this->f($Field_Name); } ! function halt($msg) { printf("</td></tr></table><b>Database error:</b> %s<br>\n", $msg); printf("<b>ODBC Error</b>: %s (%s)<br>\n", $this->Errno, $this->Error); - die("Session halted."); } } ?> --- 215,394 ---- } + $this->RowCount = $num_rows; return $num_rows; } ! function num_fields() { + # NOTE: this only works after next_record has been called! return count($this->Record)/2; } + /* public: shorthand notation */ function nf() { return $this->num_rows(); } ! function np() { print $this->num_rows(); } ! ! function f($Name) { ! if (isset($this->Record[$Name])) { ! return $this->Record[strtolower($Name)]; ! } ! return ""; } ! ! function p($Name) { ! print $this->f($Name); } ! ! /* public: sequence numbers */ ! function nextid($seq_name) { ! $this->halt("Sequence numbers require locking. Does " . $this->type ." have table locking functions?"); ! return false; ! } ! ! /* public: return table metadata */ ! function metadata($table = "", $full = false) { ! $count = 0; ! $id = 0; ! $res = array(); ! ! /* ! * Due to compatibility problems with Table we changed the behavior ! * of metadata(); ! * If $full is set, metadata returns additional information ! * ! * This information is always returned: ! * $result[]: ! * [0]["table"] table name ! * [0]["name"] field name ! * [0]["type"] field type ! * [0]["len"] field length ! * [0]["flags"] field flags ! * ! * If $full is set this information is also returned: ! * $result[]: ! * ["num_fields"] number of metadata records ! * [0]["php_type"] the corresponding PHP-type ! * [0]["php_subtype"] the subtype of PHP-type ! * ["meta"][field name] index of field named "field name" ! * This one could be used if you have a field name, but no index. ! * Test: if (isset($result['meta']['myfield'])) { ... ! * [unique] = field names which have an unique key, separated by space ! */ ! ! // if no $table specified, assume that we are working with a query result ! if ($table) { ! $this->connect(); ! $id = odbc_exec($this->Link_ID, "select * from $table"); ! if (!$id) { ! $this->halt("Metadata query failed."); ! return false; ! } ! } else { ! $id = $this->Query_ID; ! if (!$id) { ! $this->halt("No query specified."); ! return false; ! } ! } ! ! $count = odbc_num_fields($id); ! ! for ($i=1; $i<=$count; $i++) { ! $res[$i]["table"] = $table; ! $res[$i]["name"] = odbc_field_name ($id, $i); ! $res[$i]["type"] = odbc_field_type ($id, $i); ! $res[$i]["len"] = odbc_field_len ($id, $i); ! $res[$i]["flags"] = ""; // any optional flags to report? ! } ! ! if ($full) { ! $uniq = array(); ! $res["num_fields"] = $count; ! ! for ($i=1; $i<=$count; $i++) { ! $res["meta"][$res[$i]["name"]] = $i; ! switch ($res[$i]["type"]) { ! case "var string": ! case "string" : ! case "char" : ! $res[$i]["php_type"]="string"; ! $res[$i]["php_subtype"]=""; ! break; ! case "timestamp" : ! case "datetime" : ! case "date" : ! case "time" : ! $res[$i]["php_type"]="string"; ! $res[$i]["php_subtype"]="date"; ! break; ! case "blob" : ! $res[$i]["php_type"]="string"; ! $res[$i]["php_subtype"]="blob"; ! break; ! case "real" : ! $res[$i]["php_type"]="double"; ! $res[$i]["php_subtype"]=""; ! break; ! case "long" : ! default : ! $res[$i]["php_type"]="int"; ! $res[$i]["php_subtype"]=""; ! break; ! } ! if ( ereg("(unique_key|primary_key)",$res[$i]["flags"]) ) { ! $uniq[]=$res[$i]["name"]; ! } ! } ! $res["unique"]=join(" ",$uniq); ! } ! ! // free the result only if we were called on a table ! if ($table) { ! odbc_free_result($id); ! } ! return $res; ! } ! ! /* public: find available table names */ ! function table_names() { ! $this->connect(); ! $h = odbc_tables($this->Link_ID); ! $i = 0; ! while(odbc_fetch_row($h)) { ! if (odbc_result($h, 4) == "TABLE") { ! $return[$i]["table_name"] = odbc_result($h, 3); ! $return[$i]["tablespace_name"] = odbc_result($h, 1); ! $return[$i]["database"] = odbc_result($h, 1); ! $i += 1; ! } ! } ! odbc_free_result($h); ! return $return; ! } ! ! /* private: error handling */ function halt($msg) { + $this->Errno = 1; + $this->Error = "General Error (The ODBC interface cannot return detailed error messages)."; + if ($this->Halt_On_Error == "no") + return; + + $this->haltmsg($msg); + + if ($this->Halt_On_Error != "report") + die("Session halted."); + } + + function haltmsg($msg) { printf("</td></tr></table><b>Database error:</b> %s<br>\n", $msg); printf("<b>ODBC Error</b>: %s (%s)<br>\n", $this->Errno, $this->Error); } + } ?> |