NAME | SYNOPSIS | DESCRIPTION | IMPLEMENTATION | NOTES | WARNINGS | SEE ALSO | AUTHORS |
DbObjectOra - This object serves as an interface between the object-oriented entity classes and the relational database. All object data is represented as a tcl array. This class translates between that array and the sybtcl input and output to the relational database.
DbObjectOra | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Standard Public Interface
Private Interface
|
This procedure makes a connection to the database using the given dbuser, dbpass, and dsquery information. This same procedure can also be used to open multiple handles. If after the first invocation, no information is given, it will open another connection using the same information as given for the first handle. It returns the integer handle that is opened.
This procedure closes the sybase connection of the highest number handle and returns that closed handle. Any variable used to hold that handle is unset.
This procedure set the current handle to the given handle and the current handle is returned. This remains the current handle until another DbObjectOra::SetHandle is issued or that handle is closed. If no handle parameter is given, the current handle is returned.
This procedure begins a transaction on the private variable handle. It enforces single layer transactions, preventing nesting.
This procedure commits a transaction on the private variable handle.
This procedure rolls back a transaction on the private variable handle. Since only single layer transactions are supported, it is important that control is returned immediately to the original transaction beginning. In doing this, rollback can be called multiple times without ill effect.
This procedure sets up a query that may involve a join across multiple tables, depending on how the object is defined. The given objref array specifies the attributes that are to be retrieved. The where clause and order by clause specify the filtering and ordering of the retrieved results. Since the where and order clauses are raw SQL strings, the application programmer is encouraged to define new member procedures so these SQL specifications remain private to this object. Note, the same objref given to this procedure must be used to retrieve the results with DbObjectOra::Next.
This procedure retrieves the query results and places them in the objref array.. It is important that the given objref array is the same as the array used in DbObjectOra::Query since the attributes given in the array determine what attributes get loaded with the returned values. Each attribute is given the value returned by the query and an oid is also assigned if the return code is 1.
This procedure counts the rows that match the given where statement. A key can be passed that is unique on the primary table in the case of a join to allow the count to be distinct. It
This procedure cancels the result of a query. It is used to discard unretrieved results if they are unneeded.
This procedure inserts the object into the database. It only inserts into one table, so each attribute in the objref array must belong to that table or an error will be generated. Only the attributes that are given in the objref array are inserted. If a table contains attributes that are not given and they do not accept null, an error will be generated The oid is returned. It
This procedure updates the object represented by the given objref array. This array must contain a valid oid. Only the values of the attributes represented in the array are updated in the database so parts of the object can be updated. This procedure performs the update to only one table as indicated in the entity this(table) variable. Therefore, all parameters in objref must belong to this table or an error will occur.
This procedure deletes the object represented by the given objref array. The only required attribute is the oidsince this tells the procedure which object to delete.
This procedure issues a Sybase sql request. If a timeout (in seconds) is given, it will return to the Tcl event loop every timeout seconds.
This procedure retrieves the sybase row from the private handle connection..
This procedure concatenates the given where clause with any internal entity where clause and returns the final string. If the entity has no internal where clause, the given clause is simply returned.
This procedure formats the given value according to the given type. If the type is an integer, return the given value without modification. If it is a text or datetime type, return the value enclosed in single quotes. If the keyword function is used, the value after the keyword is simply returned. This allows the use of the sybase functions. If any parameter is specified as {} or "", it will be recorded in the database as a null. Nulls are returned as {}.
This procedure builds the SQL update string . Only the attributes found in objref are built in the list. the oid is not included
This procedure builds the SQL select clause used in an SQL query string. Only the attributes found in objref are built in the list. The oid is not included.
This procedure builds the SQL attribute list used in an SQL insert string. Only the attributes found in objref are built in the list. the oid is not included.
This procedure builds the SQL value list used in an SQL insert string. Only the values of the attributes found in objref are built in the list. The oid is not included
The following messages will be logged.
namespace eval DbObjectOra { # this is the logon handle. variable handle # this is the statement handle. variable sth variable sqlString variable _dbuser variable _dbpass variable _dsquery variable handleIndex 0 variable numHandles 0 variable waitInterval 30 variable minSleepInterval 5 variable tranflag variable lda }
proc DbObjectOra::Connect { {dbuser {}} {dbpass {}} {dsquery {}}} { variable handle variable _dbuser variable _dbpass variable _dsquery variable handleIndex variable numHandles 0 variable sth variable tranflag global env scriptName logEntryLS DbgEntryExit "Entering DbObjectOra::Connect" #Save the given information the first time if {$numHandles == 0} { #dbuser and dbpass must be given if {[string equal $dbuser {}]} { if [catch {set dbuser $env(DBUSER)} result ] { error "DbObjectOra::Connect failed: $result" } } if {[string equal $dbpass {}]} { if [catch {set dbpass $env(DBPASS)} result ] { error "DbObjectOra::Connect failed: $result" } } set _dbuser $dbuser set _dbpass $dbpass set _dsquery $dsquery } else { if {[string compare $dbuser {}] == 0 || [string compare $dbpass {}] == 0} { set dbuser $_dbuser set dbpass $_dbpass } } set login "$dbuser/$dbpass$dsquery" #Open the database Connection as asynchronous if {[string compare $dsquery {}] == 0} { if [ catch { #set handle([incr DbObjectOra::numHandles]) [oralogon $login -async] # logon to system in synchonous mode. set handle([incr DbObjectOra::numHandles]) [oralogon $login] set sth [oraopen $handle($numHandles)] #Only set this the first time if {$numHandles == 1} { set handleIndex 1 } #Initialize the transaction for the new connection set tranflag($numHandles) 0 DbObjectOra::Begin } result ] { error "DbObjectOra::Connect: Connect Failed: $result" return $numHandles } } else { if [ catch { set handle([incr numHandles]) [oralogon $login] set sth [oraopen $handle($numHandles)] #Only set this the first time if {$numHandles == 1} { set handleIndex 1 } #Initialize the transaction for the new connection set tranflag($numHandles) 0 DbObjectOra::Begin } result ] { error "DbObjectOra::Connect: Connect Failed: $result" return $numHandles } } #Initialize the transaction for the new connection set tranflag($numHandles) 0 #This variable must be set to retrieve any binary data as hex. #set oramsg(binaryashex) 1 #set oramsg(nullvalue) {} logEntryLS DbgEntryExit "Exiting DbObjectOra::Connect with handle, $handle($handleIndex)" return $numHandles }
proc DbObjectOra::Close {} { variable handle variable handleIndex variable numHandles if {$numHandles == 0} {return $numHandles} logEntryLS DbgEntryExit "Entering DbObjectOra::Close" set closedHandle $numHandles catch { oraclose $handle($numHandles) unset handle($numHandles) if {$handleIndex == $numHandles} {incr DbObjectOra::handleIndex -1} incr DbObjectOra::numHandles -1 } logEntryLS DbgEntryExit "Exiting DbObjectOra::Close" return $closedHandle }
proc DbObjectOra::SetHandle { {index {}} } { variable handle variable dbuser variable dbpass variable dsquery variable handleIndex variable numHandles #Is this a read accessor? if {[string compare $index {}] == 0} {return $handleIndex} logEntryLS DbgEntryExit "Entering DbObjectOra::SetHandle" if {$index > $numHandles || $index <= 0} { error "DbObjectOra::SetHandle: The requested handle does not exist" return $handleIndex } set handleIndex $index logEntryLS DbgEntryExit "Exiting DbObjectOra::SetHandle" return $handleIndex }
proc DbObjectOra::BuildType {type value} { #Include the ability to specify characteristic functions if {[string compare [lindex $value 0] function] == 0} { return [lindex $value 1] } #Include the ability to specify null values if {[string compare $value {}] == 0} { return null } switch -- $type { Text - Datetime {return '$value'} EnumText {return '[Entity::Terse $value]'} Binary { return [format "%#8.8x" $value] } Integer {return $value} EnumInt {return [Entity::Terse $value]} default {return {}} } }
proc DbObjectOra::BuildValue {class objref} { upvar $objref obj logEntryLS DbgEntryExit "Entering DbObjectOra::BuildValue" #Used in insert to build the value list foreach attr [array names obj] { set type [Entity::GetAttribute $class $attr type] if {[info exists valueClause] == 0} { set valueClause [DbObjectOra::BuildType $type $obj($attr)] } else { set valueClause [cconcat $valueClause ", [DbObjectOra::BuildType $type $obj($attr)]"] } } logEntryLS DbgAll "DbObjectOra::BuildValue valueClause: $valueClause" logEntryLS DbgEntryExit "Exiting DbObjectOra::BuildValue" return $valueClause }
proc DbObjectOra::BuildUpdate {class objref} { upvar $objref obj logEntryLS DbgEntryExit "Entering DbObjectOra::BuildUpdate" set updateClause {} #This prepares the update list for an update #Skip the mdt, dt if { [info exists obj(mdt)] } { set tmp_oid $obj(mdt); unset obj(mdt) } if { [info exists obj(dt)] } { set tmp_oid $obj(dt); unset obj(dt) } foreach attr [array names obj] { #Retrieve the attribute column name and remove the alias set column [Entity::GetAttribute $class $attr column] #set column [lindex [split $column .] 1] set type [Entity::GetAttribute $class $attr type] if {[string compare $updateClause {}] == 0} { set updateClause "$column = [DbObjectOra::BuildType $type $obj($attr)]" } else { set updateClause [cconcat $updateClause ", $column = [DbObjectOra::BuildType $type $obj($attr)]"] } } if { [info exists tmp_mdt] } { set $obj(oid) $tmp_mdt} if { [info exists tmp_dt] } { set $obj(oid) $tmp_dt} logEntryLS DbgAll "DbObjectOra::BuildUpdate updateClause: $updateClause" logEntryLS DbgEntryExit "Exiting DbObjectOra::BuildUpdate" return $updateClause }
proc DbObjectOra::BuildWhere {class where} { upvar #0 $class\::this this logEntryLS DbgEntryExit "Entering DbObjectOra::BuildWhere" #This builds the where clause for the Query if {[string compare $this(where) {}] != 0} { if {[string compare $where {}] == 0} { return $this(where) } else { return "$this(where) and $where" } } logEntryLS DbgAll "DbObjectOra::BuildWhere whereClause: $where" logEntryLS DbgEntryExit "Exiting DbObjectOra::BuildWhere" return $where }
proc DbObjectOra::BuildSelect {class objref} { upvar $objref obj variable sth set selectClause {} logEntryLS DbgEntryExit "Entering DbObjectOra::BuildSelect" foreach attr [array names obj] { #Skip the oid if {[string compare oid $attr] == 0} {continue} if {[string match $selectClause {} ]} { set selectClause [Entity::GetAttribute $class $attr column] } else { set selectClause [cconcat $selectClause ", [Entity::GetAttribute $class $attr column]"] } } logEntryLS DbgAll "DbObjectOra::BuildSelect selectClause: $selectClause" logEntryLS DbgEntryExit "Exiting DbObjectOra::BuildSelect" return $selectClause }
proc DbObjectOra::BuildInsert {class objref} { upvar $objref obj upvar #0 $class\::attr classAttr logEntryLS DbgEntryExit "Entering DbObjectOra::BuildInsert" #This builds the select clause for both select and insert foreach attr [array names obj] { #Retrieve the attribute column name and remove the alias set column [Entity::GetAttribute $class $attr column] set column [lindex [split $column .] 1] if {[info exists insertClause] == 0} { set insertClause $column } else { set insertClause [cconcat $insertClause ", $column"] } } logEntryLS DbgAll "DbObjectOra::BuildInsert insertClause: $insertClause" logEntryLS DbgEntryExit "Exiting DbObjectOra::BuildInsert" return $insertClause }
proc DbObjectOra::Query { class objref {where {}} {order {}} } { variable waitInterval variable tranflag upvar $objref obj upvar #0 $class\::this this upvar #0 $class\::attr attr variable sth logEntryLS DbgEntryExit "Entering DbObjectOra::Query" set oidColumn [Entity::GetAttribute $class oid column] #filter out any attributes not belonging to this class array set filteredObj [Entity::ArrayCopy $class obj] set selectString [DbObjectOra::BuildSelect $class filteredObj] if [string match $selectString {} ] { set sqlString "select $oidColumn" } else { set sqlString "select $oidColumn, $selectString" } set sqlString [cconcat $sqlString " from $this(from)"] set where [DbObjectOra::BuildWhere $class $where] if {[string compare $where {}] != 0} {set sqlString [cconcat $sqlString " where $where"]} if {[string compare $order {}] != 0} {set sqlString [cconcat $sqlString " order by $order"]} logEntryLS DbgMsg "DbObjectOra::Query SqlString: $sqlString" if [catch {DbObjectOra::Sql $sqlString $waitInterval} result] { error "DbObjectOra::Query: $result " } }
proc DbObjectOra::GetListOf { class attr {where {}} {order {}} } { variable waitInterval variable sth upvar #0 $class\::this this logEntryLS DbgEntryExit "Entering DbObjectOra::GetListOf" set valueList {} set selectString [Entity::GetAttribute $class $attr column] set sqlString "select distinct $selectString" set sqlString [cconcat $sqlString " from $this(from)"] set where [DbObjectOra::BuildWhere $class $where] if {[string compare $where {}] != 0} {set sqlString [cconcat $sqlString " where $where"]} if {[string compare $order {}] != 0} {set sqlString [cconcat $sqlString " order by $order"]} logEntryLS DbgMsg "DbObjectOra::Count SqlString: $sqlString" if [catch { DbObjectOra::Sql $sqlString $waitInterval set option -datavariable set row [DbObjectOra::Orafetch $sth $option] while {[llength $row] > 0} { lappend valueList [lindex $row 0] set row [DbObjectOra::Orafetch $sth $option] } } result] { error "DbObjectOra::GetListOf: $result: $result" } return $valueList }
proc DbObjectOra::Count { class {where {}} {distinct *} } { variable waitInterval upvar #0 $class\::this this logEntryLS DbgEntryExit "Entering DbObjectOra::Count" if {[string match $distinct *]} { set sqlString "select count(*)" } else { set sqlString "select count(distinct $distinct)" } set sqlString [cconcat $sqlString " from $this(from)"] set where [DbObjectOra::BuildWhere $class $where] if {[string compare $where {}] != 0} {set sqlString [cconcat $sqlString " where $where"]} logEntryLS DbgMsg "DbObjectOra::Count SqlString: $sqlString" if [catch { DbObjectOra::Sql $sqlString $waitInterval set count [DbObjectOra::Nextrow] } result] { error "DbObjectOra::Count: $result: " } return $count }
proc DbObjectOra::Next { class objref } { upvar $objref obj variable handle variable handleIndex variable sth logEntryLS DbgEntryExit "Entering DbObjectOra::Next" #filter out any attributes not belonging to this class array set filteredObj [Entity::ArrayCopy $class obj] #Do the initial fetch. set option -datavariable set row [DbObjectOra::Orafetch $sth $option] logEntryLS DbgMsg "Returned Row: $row" # Determine if you are at the end of the file. if {![cequal [oramsg $sth rc] 1403]} { foreach rowIn $row { set obj(oid) [lindex $rowIn 0] set i 1 foreach attr [array names filteredObj] { # Skip the oid if {[string compare oid $attr] == 0} {continue} # Check for binary switch -- [Entity::GetAttribute $class $attr type] { Binary { set obj($attr) [join [list 0x [string trim [lindex $row $i]]] {}] } EnumText - EnumInt { set obj($attr) [Entity::EnumValue [Entity::GetAttribute $class $attr enum] [lindex $row $i]] } default { set obj($attr) [lindex $row $i] } } incr i } logEntryLS DbgEntryExit "Exiting DbObjectOra::Next after retrieving oid, $obj(oid) " return 1 } } else { logEntryLS DbgEntryExit "Exiting DbObjectOra::Next: No row retrieved" return 0 } }
proc DbObjectOra::Oraparse { stmHandle sqlString } { variable handle variable handleIndex catch { [oraparse $stmHandle $sqlString] } if {![oramsg $handle($handleIndex) rc] == 0} { error "DbObjectOra::Oraparse: $error $sqlString " } }
proc DbObjectOra::Orafetch { stmHandle {option {}} } { variable handle variable handleIndex set rowsRtn {} if {[cequal $option {}]} { catch {orafetch $stmHandle} } else { catch {orafetch $stmHandle $option rowsRtn} } if {!([oramsg $handle($handleIndex) rc] == 0 || [ormsg $handle($handleIndex) rc] == 1403)} { error "DbObjectOra::Orafetch: $error " } return $rowsRtn }
proc DbObjectOra::Oraexec { stmHandle } { variable handle variable handleIndex catch {oraexec $stmHandle} if {![oramsg $handle($handleIndex) rc] == 0} { DbObjectOra::Rollback error "DbObjectOra::Oraexec: $error $stmHandle" } else { DbObjectOra::Commit } }
proc DbObjectOra::Cancel {} { variable handle variable handleIndex variable numHandles if {$numHandles != 0} { oracancel $handle($handleIndex) } }
proc DbObjectOra::Insert { class objref } { variable handle variable handleIndex variable waitInterval variable sth variable sqlString upvar $objref obj upvar #0 $class\::this this logEntryLS DbgEntryExit "Entering DbObjectOra::Insert" set attrList [DbObjectOra::BuildInsert $class obj] set sqlString "select ip_oid.nextval from DUAL " DbObjectOra::Oraparse $sth $sqlString DbObjectOra::Oraexec $sth set option -datavariable set obj(oid) [DbObjectOra::Orafetch $sth $option] # Because you have to do a nextval to make currval work, the nextval # must be decremented by 1 to reflect the currval. set obj(oid) [incr obj(oid) -1] set valueList [DbObjectOra::BuildValue $class obj] set sqlString "insert into [lindex $this(table) 0] ($attrList) values ($valueList)" logEntryLS DbgMsg "DbObjectOra::Insert SqlString: $sqlString" if [ catch { DbObjectOra::Sql $sqlString $waitInterval } result ] { error "DbObjectOra::Insert: $result: " } logEntryLS DbgEntryExit "Exiting DbObjectOra::Insert with oid, $obj(oid)" return $obj(oid) }
proc DbObjectOra::Update {class objref} { variable waitInterval variable sth upvar $objref obj upvar #0 $class\::this this logEntryLS DbgEntryExit "Entering DbObjectOra::Update" set setList [DbObjectOra::BuildUpdate $class obj] #If there is no setlist, we are done if {[string compare $setList {}] == 0} { return } set where "[Entity::GetAttribute $class oid column] = $obj(oid)" set sqlString "update $this(table) set $setList where $where" logEntryLS DbgMsg "DbObjectOra::Update SqlString: $sqlString" if [ catch { DbObjectOra::Sql $sqlString $waitInterval} result ] { error "DbObjectOra::Update: $result: " } logEntryLS DbgEntryExit "Exiting DbObjectOra::Update" }
proc DbObjectOra::Delete {class objref} { variable waitInterval variable sth upvar $objref obj upvar #0 $class\::this this logEntryLS DbgEntryExit "Entering DbObjectOra::Delete" set where "[Entity::GetAttribute $class oid column] = $obj(oid)" set sqlString "delete from $this(table) where $where" logEntryLS DbgMsg "DbObjectOra::Delete SqlString: $sqlString" if [ catch { DbObjectOra::Sql $sqlString $waitInterval} result ] { error "DbObjectOra::Delete: $result: " } logEntryLS DbgEntryExit "Exiting DbObjectOra::Delete" }
proc DbObjectOra::Begin {} { variable waitInterval variable tranflag variable handleIndex variable sth logEntryLS DbgEntryExit "Entering DbObjectOra::Begin" set sqlStatement "set transaction use rollback segment " if {$tranflag($handleIndex) == 0} { if [catch {DbObjectOra::Sql $sqlStatement $waitInterval} result] { error "DbObjectOra::Begin: $result: " return } } incr tranflag($handleIndex) logEntryLS DbgMsg "Begin Transaction" logEntryLS DbgEntryExit "Exiting DbObjectOra::Begin" }
proc DbObjectOra::Commit {} { variable waitInterval variable tranflag variable handleIndex variable handle variable this logEntryLS DbgEntryExit "Entering DbObjectOra::Commit" if {$tranflag($handleIndex) == 1} { catch {oracommit $handle($handleIndex)} if {![oramsg $handle($handleIndex) rc] == 0} { error "DbObjectOra::Insert oracommit: $rc " error "DbObjectOra::Insert Commit table: [lindex $this(table) 0] " } } if {$tranflag($handleIndex) > 0 } { incr tranflag($handleIndex) -1 } logEntryLS DbgMsg "Commit Transaction" logEntryLS DbgEntryExit "Exiting DbObjectOra::Commit" }
proc DbObjectOra::Rollback {} { variable waitInterval variable tranflag variable handleIndex variable handle variable sth variable this logEntryLS DbgEntryExit "Entering DbObjectOra::Rollback" if {$tranflag($handleIndex) > 0} { catch {oraroll $handle($handleIndex)} if {![oramsg $handle($handleIndex) rc] == 0} { error "DbObjectOra::Oraroll: $error " return } set tranflag($handleIndex) 0 } logEntryLS DbgMsg "Rollback Transaction" logEntryLS DbgEntryExit "Exiting DbObjectOra::Rollback" }
proc DbObjectOra::Sql {sqlString {timeout -1}} { variable handle variable handleIndex variable minSleepInterval variable sth logEntryLS DbgEntryExit "Entering DbObjectOra::Sql $sqlString, $timeout" logEntryLS DbgMsg "DbObjectOra::Sql SqlString: $sqlString" set start [clock seconds] set numDeadlocks 0 #A timeout of -1 is equivalent to synchronous #If not -1, it is a timeout in seconds if {[string compare $timeout -1] != 0} { set msInterval [expr $timeout * 1000] } else {set msInterval -1} catch { [orasql $sth $sqlString] } if {[oramsg $handle($handleIndex) rc] == 00500} { set deadlockFlag 1 set tranflag($handleIndex) 0 logEntryLS Error "DbObjectOra::Sql: Encountered Oracle deadlock error ORA-0050" error "DbObjectOra::OraSql: $rc $sqlString " } DbObjectOra::Oraparse $sth $sqlString DbObjectOra::Oraexec $sth logEntryLS DbgEntryExit "Exiting DbObjectOra::Sql $sqlString, $timeout" }
proc DbObjectOra::Nextrow {} { variable handle variable sth variable handleIndex global oramsg set option -datavariable set row [DbObjectOra::Orafetch $DbObjectOra::sth $option] return $row }