rivet/packages/dio/dio_Postgresql01.tcl (183 lines of code) (raw):
# dio_Postgresql.tcl -- Postgres backend.
# Copyright 2002-2004 The Apache Software Foundation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
package require -exact DIO 1.1
package provide dio_Postgresql 0.1
namespace eval DIO {
::itcl::class Postgresql {
inherit Database
constructor {args} {eval configure $args} {
package require Pgtcl
set_conn_defaults
eval configure $args
}
destructor {
close
}
## Setup our variables with the default conninfo from Postgres.
private method set_conn_defaults {} {
foreach list [pg_conndefaults] {
set var [lindex $list 0]
set val [lindex $list end]
switch -- $var {
"dbname" { set db $val }
default { set $var $val }
}
}
}
method open {} {
set command "pg_connect"
set info ""
if {![::rivet::lempty $user]} { append info " user=$user" }
if {![::rivet::lempty $pass]} { append info " password=$pass" }
if {![::rivet::lempty $host]} { append info " host=$host" }
if {![::rivet::lempty $port]} { append info " port=$port" }
if {![::rivet::lempty $db]} { append info " dbname=$db" }
if {![::rivet::lempty $info]} { append command " -conninfo [::list $info]" }
if {[catch $command error]} { return -code error $error }
set conn $error
}
method close {} {
if {![info exists conn]} { return }
pg_disconnect $conn
unset conn
}
method exec {req} {
if {![info exists conn]} { open }
set command pg_exec
if {[catch {$command $conn $req} result]} { return -code error $result }
set errorinfo ""
set obj [result Postgresql -resultid $result]
if {[$obj error]} { set errorinfo [$obj errorinfo] }
return $obj
}
method nextkey {} {
return [$this string "select nextval( '$sequence' )"]
}
method lastkey {} {
return [$this string "select last_value from $sequence"]
}
method sql_limit_syntax {limit {offset ""}} {
set sql " LIMIT $limit"
if {![::rivet::lempty $offset]} { append sql " OFFSET $offset" }
return $sql
}
#
# handle - return the internal database handle, in the postgres
# case, the postgres connection handle
#
method handle {} {
if {![info exists conn]} { open }
return $conn
}
method makeDBFieldValue {table_name field_name val {convert_to {}}} {
if {[info exists specialFields(${table_name}@${field_name})]} {
switch $specialFields(${table_name}@${field_name}) {
DATE {
set secs [clock scan $val]
set my_val [clock format $secs -format {%Y-%m-%d}]
return "'$my_val'"
}
DATETIME {
set secs [clock scan $val]
set my_val [clock format $secs -format {%Y-%m-%d %T}]
return "'$my_val'"
}
NOW {
switch $convert_to {
# we try to be coherent with the original purpose of this method whose
# goal is to provide to the programmer a uniform way to handle timestamps.
# E.g.: Package session expects this case to return a timestamp in seconds
# so that differences with timestamps returned by [clock seconds]
# can be done and session expirations are computed consistently.
# (Bug #53703)
SECS {
if {[::string compare $val "now"] == 0} {
# set secs [clock seconds]
# set my_val [clock format $secs -format {%Y%m%d%H%M%S}]
# return $my_val
return [clock seconds]
} else {
return "extract(epoch from $field_name)"
}
}
default {
if {[::string compare $val, "now"] == 0} {
set secs [clock seconds]
} else {
set secs [clock scan $val]
}
# this is kind of going back and forth from the same
# format,
return "'[clock format $secs -format {%Y-%m-%d %T}]'"
}
}
}
default {
# no special code for that type!!
return [pg_quote $val]
}
}
} else {
return [pg_quote $val]
}
}
## If they change DBs, we need to close the connection and re-open it.
public variable db "" {
if {[info exists conn]} {
close
open
}
}
public variable interface "Postgresql"
private variable conn
} ; ## ::itcl::class Postgresql
#
# PostgresqlResult object -- superclass of ::DIO::Result object
#
#
::itcl::class PostgresqlResult {
inherit Result
constructor {args} {
eval configure $args
if {[::rivet::lempty $resultid]} {
return -code error "No resultid specified while creating result"
}
set numrows [pg_result $resultid -numTuples]
set fields [pg_result $resultid -attributes]
set errorcode [pg_result $resultid -status]
set errorinfo [pg_result $resultid -error]
# if numrows is zero, see if cmdrows returned anything and if it
# did, put that in in place of numrows, hiding a postgresql
# idiosyncracy from DIO
if {$numrows == 0} {
set cmdrows [pg_result $resultid -cmdTuples]
if {$cmdrows != ""} {
set numrows $cmdrows
}
}
if {$errorcode != "PGRES_COMMAND_OK" && \
$errorcode != "PGRES_TUPLES_OK"} { set error 1 }
## Reconfigure incase we want to overset the default values.
eval configure $args
}
destructor {
pg_result $resultid -clear
}
method clear {} {
pg_result $resultid -clear
}
method nextrow {} {
if {$rowid >= $numrows} { return }
return [pg_result $resultid -getTuple $rowid]
}
} ; ## ::itcl::class PostgresqlResult
}