| # dio_Postgresql.tcl -- Postgres backend. |
| |
| # Copyright 2002-2024 The Apache Software Foundation |
| |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you 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 DIO 1.2 |
| package provide dio_Postgresql 1.2 |
| |
| namespace eval DIO { |
| ::itcl::class Postgresql { |
| inherit Database |
| |
| constructor {args} {eval configure -interface Postgresql $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 build_special_field {table_name field_name val {convert_to {}}} { |
| switch [$this select_special_field $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] |
| } |
| } |
| } |
| |
| |
| ## 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 |
| |
| } |