[Phplib-commit] CVS: php-lib/php/db/odbc db_sql.inc,1.2,1.3
Brought to you by:
nhruby,
richardarcher
From: Richard A. <ric...@us...> - 2001-08-27 07:08:22
|
Update of /cvsroot/phplib/php-lib/php/db/odbc In directory usw-pr-cvs1:/tmp/cvs-serv23693 Modified Files: db_sql.inc Log Message: Add pseudo-locking and sequence numbers. Index: db_sql.inc =================================================================== RCS file: /cvsroot/phplib/php-lib/php/db/odbc/db_sql.inc,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** db_sql.inc 2001/08/26 12:13:46 1.2 --- db_sql.inc 2001/08/27 07:08:18 1.3 *************** *** 22,27 **** 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 --- 22,32 ---- 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_Table ! var $Seq_Name_Col = "p_seq_name"; ## Name of the Sequence Name column in $Seq_Table ! var $Lock_Table = "db_sequence"; ## Name of the lock table ! var $Lock_Name_Col = "p_seq_name"; ## Name of the lock Name column ! var $Lock_ID_Col = "p_nextid"; ## Name of the lock Name column ! var $Lock_Timeout = 5; ## Wait this long for a lock ! var $Lock_Override = 1; ## Set to 1 to override lock after $Lock_Timeout seconds var $UseODBCCursor = 0; ## Set to 1 to enable execution of stored procedures on the server *************** *** 115,119 **** # $this->Query_Ok = odbc_execute($this->Query_ID); ! $this->Query_ID = odbc_exec($this->Link_ID,$Query_String); $this->RowCount = -1; # reset num_rows() return value $this->Row = 0; --- 120,124 ---- # $this->Query_Ok = odbc_execute($this->Query_ID); ! $this->Query_ID = odbc_exec($this->Link_ID, $Query_String); $this->RowCount = -1; # reset num_rows() return value $this->Row = 0; *************** *** 163,175 **** } /* 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; } --- 168,315 ---- } + /* public: get the time in msecs */ + function getmicrotime() { + list($usec, $sec) = explode(" ", microtime()); + return (float)$usec + (float)$sec; + } + /* public: table locking */ + /* + ODBC is not guaranteed do table locking natively. This function emulates + locking with certain constraints. The intention is to provide at least the + minimum functionality required to implement sequences via nextid(). + + This function maintains a list of locked tables in a lock table. To lock + a table it inserts a row into the lock table with the locked table name + suffixed with '_p_lock' as a primary key and with a value of 0. + The suffix and value are used so that the sequence table can be used as + the lock table if desired. + While this row exists a lock will not be granted to another process. + To protect against threads failing to release a lock, if a lock is not + obtained within $this->Lock_Timeout seconds the lock may be deleted. + The timeout value needs to be set to a reasonable length based on the + expected transaction time on the locked table. + + This method will only be effective if the locked table is accessed + exclusively via this class. This is not a database-enforced lock and + there is nothing preventing other applications from modifying a table + while it is 'locked'. + + The function uses microtime to prevent multiple threads all hitting the + table simultaneously on the tick of a second. + + The function halt()s if a lock cannot be obtained. + */ function lock($table, $mode="write") { ! ! if (!$this->connect()) { ! return 0; /* we already complained in connect() about that. */ ! }; ! ! $getsql = sprintf("INSERT into %s (%s, %s) VALUES ('%s', 0)", ! $this->Lock_Table, ! $this->Lock_Name_Col, ! $this->Lock_ID_Col, ! strtolower($table)."_p_lock"); ! $delsql = sprintf("DELETE FROM %s where %s='%s' AND %s=0", ! $this->Lock_Table, ! $this->Lock_Name_Col, ! strtolower($table)."_p_lock", ! $this->Lock_ID_Col); ! $selsql = sprintf("SELECT * FROM %s where %s='%s' AND %s=0", ! $this->Lock_Table, ! $this->Lock_Name_Col, ! strtolower($table)."_p_lock", ! $this->Lock_ID_Col); ! $timeout = $this->getmicrotime() + $this->Lock_Timeout; ! $got_lock = 0; ! $override = $this->Lock_Override; ! while (!$got_lock) { ! $got_lock = @odbc_exec($this->Link_ID, $getsql); ! if ($this->Debug && !$got_lock) { ! echo "missed lock... looping\n"; ! flush(); ! } ! $currtime = $this->getmicrotime(); ! if (!$got_lock) { ! if ($timeout < $currtime) { ! if (!$override) { ! # try to select existing lock ! if (!@odbc_exec($this->Link_ID, $selsql)) { ! # lock select failed. Either the table does not exist or the lock was ! # released just this instant. Try to get a lock to see which... ! $got_lock = @odbc_exec($this->Link_ID, $getsql); ! if (!$got_lock) { ! $this->halt("Lock select failed. Does the table $this->Lock_Table exist?"); ! } ! return $got_lock; ! } ! $this->halt("lock() failed."); ! return 0; ! } else { ! # delete existing lock ! if ($this->Debug) { ! echo "overriding lock\n"; ! } ! ! if (!@odbc_exec($this->Link_ID, $delsql)) { ! # lock override failed. Either the table does not exist or the lock was ! # released just this instant. Try to get a lock to see which... ! $got_lock = @odbc_exec($this->Link_ID, $getsql); ! if (!$got_lock) { ! $this->halt("Lock override failed. Does the table $this->Lock_Table exist?"); ! } ! return $got_lock; ! } else { ! # just deleted the lock so try to get it straight away ! $got_lock = @odbc_exec($this->Link_ID, $getsql); ! $timeout = $currtime + $this->Lock_Timeout; # reset the timer ! $override = 0; # override once only ! # fall through to wait loop ! } ! } ! } ! } ! ! if (!$got_lock) { ! $waittime = $currtime + 0.5; ! while ($waittime > $this->getmicrotime()) { ! ; ! } ! } ! } ! if ($this->Debug && !$got_lock) { ! echo "missed lock... bug!\n"; ! } else { ! echo "got lock\n"; ! flush(); ! } ! return $got_lock; } ! function unlock($table = "") { ! if (!$this->connect()) { ! return 0; /* we already complained in connect() about that. */ ! }; ! ! # Note: this unlocks ALL tables if $table is blank! ! if ($table == "") { ! $delsql = sprintf("DELETE FROM %s where %s LIKE '%%_p_lock' AND %s=0", ! $this->Lock_Table, ! $this->Lock_Name_Col, ! $this->Lock_ID_Col); ! } else { ! $delsql = sprintf("DELETE FROM %s where %s='%s' AND %s=0", ! $this->Lock_Table, ! $this->Lock_Name_Col, ! strtolower($table)."_p_lock", ! $this->Lock_ID_Col); ! } ! ! $res = @odbc_exec($this->Link_ID, $delsql); ! if (!$res) { ! $this->halt("unlock() failed."); ! } ! return $res; } *************** *** 246,251 **** /* public: sequence numbers */ function nextid($seq_name) { ! $this->halt("Sequence numbers require locking. Does " . $this->type ." have table locking functions?"); ! return false; } --- 386,437 ---- /* public: sequence numbers */ function nextid($seq_name) { ! if (!$this->connect()) { ! return 0; /* we already complained in connect() about that. */ ! }; ! ! if ($this->lock($this->Seq_Table)) { ! /* get sequence number (locked) and increment */ ! $q = sprintf("select %s from %s where %s = '%s'", ! $this->Seq_ID_Col, ! $this->Seq_Table, ! $this->Seq_Name_Col, ! $seq_name); ! $id = odbc_exec($this->Link_ID, $q); ! $res = 0; ! if (odbc_fetch_row($id, 1)) { ! $res = array(); ! $count = odbc_num_fields($id); ! for ($i=1; $i<=$count; $i++) { ! $res[strtolower(odbc_field_name($id, $i))] = odbc_result($id, $i); ! } ! } ! ! /* No current value, make one */ ! if (!is_array($res)) { ! $currentid = 0; ! $q = sprintf("insert into %s ( %s, %s ) values('%s', %s)", ! $this->Seq_Table, ! $this->Seq_Name_Col, ! $this->Seq_ID_Col, ! $seq_name, ! $currentid); ! $id = odbc_exec($this->Link_ID, $q); ! } else { ! $currentid = $res[$this->Seq_ID_Col]; ! } ! $nextid = $currentid + 1; ! $q = sprintf("update %s set %s = '%s' where %s = '%s'", ! $this->Seq_Table, ! $this->Seq_ID_Col, ! $nextid, ! $this->Seq_Name_Col, ! $seq_name); ! $id = odbc_exec($this->Link_ID, $q); ! $this->unlock(); ! } else { ! $this->halt("cannot lock ".$this->Seq_Table." - has it been created?"); ! return 0; ! } ! return $nextid; } *************** *** 310,313 **** --- 496,500 ---- $res["num_fields"] = $count; + # ODBC result set starts at 1 for ($i=1; $i<=$count; $i++) { $res["meta"][$res[$i]["name"]] = $i; |