summaryrefslogtreecommitdiff
path: root/ZPsycopgDA
diff options
context:
space:
mode:
authorFederico Di Gregorio <fog@initd.org>2004-10-19 03:17:12 +0000
committerFederico Di Gregorio <fog@initd.org>2004-10-19 03:17:12 +0000
commitc904d97f696a665958c2cc43333d09c0e6357577 (patch)
treede88cb1cb6a48230f79bc0b532835d26a33660e9 /ZPsycopgDA
downloadpsycopg2-c904d97f696a665958c2cc43333d09c0e6357577.tar.gz
Initial psycopg 2 import after SVN crash.
Diffstat (limited to 'ZPsycopgDA')
-rw-r--r--ZPsycopgDA/DA.py202
-rw-r--r--ZPsycopgDA/DABase.py67
-rw-r--r--ZPsycopgDA/__init__.py32
-rw-r--r--ZPsycopgDA/db.py209
-rw-r--r--ZPsycopgDA/dtml/add.dtml96
-rw-r--r--ZPsycopgDA/dtml/edit.dtml67
-rw-r--r--ZPsycopgDA/icons/bin.gifbin0 -> 924 bytes
-rw-r--r--ZPsycopgDA/icons/date.gifbin0 -> 930 bytes
-rw-r--r--ZPsycopgDA/icons/datetime.gifbin0 -> 925 bytes
-rw-r--r--ZPsycopgDA/icons/field.gifbin0 -> 915 bytes
-rw-r--r--ZPsycopgDA/icons/float.gifbin0 -> 929 bytes
-rw-r--r--ZPsycopgDA/icons/int.gifbin0 -> 918 bytes
-rw-r--r--ZPsycopgDA/icons/stable.gifbin0 -> 884 bytes
-rw-r--r--ZPsycopgDA/icons/table.gifbin0 -> 878 bytes
-rw-r--r--ZPsycopgDA/icons/text.gifbin0 -> 918 bytes
-rw-r--r--ZPsycopgDA/icons/time.gifbin0 -> 926 bytes
-rw-r--r--ZPsycopgDA/icons/view.gifbin0 -> 893 bytes
-rw-r--r--ZPsycopgDA/icons/what.gifbin0 -> 894 bytes
-rw-r--r--ZPsycopgDA/pool.py51
19 files changed, 724 insertions, 0 deletions
diff --git a/ZPsycopgDA/DA.py b/ZPsycopgDA/DA.py
new file mode 100644
index 0000000..b9979b7
--- /dev/null
+++ b/ZPsycopgDA/DA.py
@@ -0,0 +1,202 @@
+# ZPsycopgDA/DA.py - ZPsycopgDA Zope product: Database Connection
+#
+# Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# Or, at your option this program (ZPsycopgDA) can be distributed under the
+# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
+# http://www.zope.org/Resources/ZPL.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# See the LICENSE file for details.
+
+
+ALLOWED_PSYCOPG_VERSIONS = ('1.99.9',)
+
+import sys
+import db
+import DABase
+import Shared.DC.ZRDB.Connection
+
+from db import DB
+from Globals import DTMLFile
+from Globals import HTMLFile
+from ImageFile import ImageFile
+from ExtensionClass import Base
+from DateTime import DateTime
+
+# import psycopg and functions/singletons needed for date/time conversions
+
+import psycopg
+from psycopg import DATETIME
+from psycopg.extensions import TIME, DATE, INTERVAL
+from psycopg.extensions import new_type, register_type
+
+
+
+# add a new connection to a folder
+
+manage_addZPsycopgConnectionForm = DTMLFile('dtml/add',globals())
+
+def manage_addZPsycopgConnection(self, id, title, connection_string,
+ zdatetime=None, tilevel=2,
+ check=None, REQUEST=None):
+ """Add a DB connection to a folder."""
+ self._setObject(id, Connection(id, title, connection_string,
+ zdatetime, check, tilevel))
+ if REQUEST is not None: return self.manage_main(self, REQUEST)
+
+
+
+# the connection object
+
+class Connection(DABase.Connection):
+ """ZPsycopg Connection."""
+ id = 'Psycopg_database_connection'
+ database_type = 'Psycopg'
+ meta_type = title = 'Z Psycopg Database Connection'
+ icon = 'misc_/ZPsycopg/conn'
+
+ def __init__(self, id, title, connection_string,
+ zdatetime, check=None, tilevel=2, encoding=''):
+ self.zdatetime = zdatetime
+ self.id = str(id)
+ self.edit(title, connection_string, zdatetime,
+ check=check, tilevel=tilevel, encoding=encoding)
+
+ def factory(self):
+ return DB
+
+ def table_info(self):
+ return self._v_database_connection.table_info()
+
+ def edit(self, title, connection_string,
+ zdatetime, check=None, tilevel=2, encoding=''):
+ self.title = title
+ self.connection_string = connection_string
+ self.zdatetime = zdatetime
+ self.tilevel = tilevel
+ self.encoding = encoding
+
+ self.set_type_casts()
+
+ if check: self.connect(self.connection_string)
+
+ manage_properties = DTMLFile('dtml/edit', globals())
+
+ def manage_edit(self, title, connection_string,
+ zdatetime=None, check=None, tilevel=2, encoding='UTF-8',
+ REQUEST=None):
+ """Edit the DB connection."""
+ self.edit(title, connection_string, zdatetime,
+ check=check, tilevel=tilevel, encoding=encoding)
+ if REQUEST is not None:
+ msg = "Connection edited."
+ return self.manage_main(self,REQUEST,manage_tabs_message=msg)
+
+ def connect(self, s):
+ try:
+ self._v_database_connection.close()
+ except:
+ pass
+
+ # check psycopg version and raise exception if does not match
+ if psycopg.__version__ not in ALLOWED_PSYCOPG_VERSIONS:
+ raise ImportError("psycopg version mismatch (imported %s)" +
+ psycopg.__version__)
+
+ self.set_type_casts()
+ self._v_connected = ''
+ dbf = self.factory()
+
+ # TODO: let the psycopg exception propagate, or not?
+ self._v_database_connection = dbf(
+ self.connection_string, self.tilevel, self.encoding)
+ self._v_database_connection.open()
+ self._v_connected = DateTime()
+
+ return self
+
+ def set_type_casts(self):
+ # note that in both cases order *is* important
+ if self.zdatetime:
+ # use zope internal datetime routines
+ register_type(ZDATETIME)
+ register_type(ZDATE)
+ register_type(ZTIME)
+ register_type(ZINTERVAL)
+ else:
+ # use the standard
+ register_type(DATETIME)
+ register_type(DATE)
+ register_type(TIME)
+ register_type(INTERVAL)
+
+# database connection registration data
+
+classes = (Connection,)
+
+meta_types = ({'name':'Z Psycopg Database Connection',
+ 'action':'manage_addZPsycopgConnectionForm'},)
+
+folder_methods = {
+ 'manage_addZPsycopgConnection': manage_addZPsycopgConnection,
+ 'manage_addZPsycopgConnectionForm': manage_addZPsycopgConnectionForm}
+
+__ac_permissions__ = (
+ ('Add Z Psycopg Database Connections',
+ ('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),)
+
+# add icons
+
+misc_={'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')}
+
+for icon in ('table', 'view', 'stable', 'what', 'field', 'text', 'bin',
+ 'int', 'float', 'date', 'time', 'datetime'):
+ misc_[icon] = ImageFile('icons/%s.gif' % icon, globals())
+
+# zope-specific psycopg typecasters
+
+# convert an ISO timestamp string from postgres to a Zope DateTime object
+def _cast_DateTime(str):
+ if str:
+ # this will split us into [date, time, GMT/AM/PM(if there)]
+ dt = split(str, ' ')
+ if len(dt) > 1:
+ # we now should split out any timezone info
+ dt[1] = split(dt[1], '-')[0]
+ dt[1] = split(dt[1], '+')[0]
+ return DateTime(join(dt[:2], ' '))
+ else:
+ return DateTime(dt[0])
+
+# convert an ISO date string from postgres to a Zope DateTime object
+def _cast_Date(str):
+ if str:
+ return DateTime(str)
+
+# Convert a time string from postgres to a Zope DateTime object.
+# NOTE: we set the day as today before feeding to DateTime so
+# that it has the same DST settings.
+def _cast_Time(str):
+ if str:
+ return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
+ time.localtime(time.time())[:3]+
+ time.strptime(str[:8], "%H:%M:%S")[3:]))
+
+# TODO: DateTime does not support intervals: what's the best we can do?
+def _cast_Interval(str):
+ return str
+
+ZDATETIME = new_type((1184, 1114), "ZDATETIME", _cast_DateTime)
+ZINTERVAL = new_type((1186,), "ZINTERVAL", _cast_Interval)
+ZDATE = new_type((1082,), "ZDATE", _cast_Date)
+ZTIME = new_type((1083,), "ZTIME", _cast_Time)
+
diff --git a/ZPsycopgDA/DABase.py b/ZPsycopgDA/DABase.py
new file mode 100644
index 0000000..03102c3
--- /dev/null
+++ b/ZPsycopgDA/DABase.py
@@ -0,0 +1,67 @@
+# ZPsycopgDA/DABase.py - ZPsycopgDA Zope product: Database inspection
+#
+# Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# Or, at your option this program (ZPsycopgDA) can be distributed under the
+# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
+# http://www.zope.org/Resources/ZPL.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# See the LICENSE file for details.
+
+import sys
+import Shared.DC.ZRDB.Connection
+
+from db import DB
+from Globals import HTMLFile
+from ImageFile import ImageFile
+from ExtensionClass import Base
+from DateTime import DateTime
+
+# import psycopg and functions/singletons needed for date/time conversions
+
+import psycopg
+from psycopg.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN
+from psycopg import NUMBER, STRING, ROWID, DATETIME
+
+
+
+class Connection(Shared.DC.ZRDB.Connection.Connection):
+ _isAnSQLConnection = 1
+
+ info = None
+
+ #manage_options = Shared.DC.ZRDB.Connection.Connection.manage_options + (
+ # {'label': 'Browse', 'action':'manage_browse'},)
+
+ #manage_tables = HTMLFile('tables', globals())
+ #manage_browse = HTMLFile('browse',globals())
+
+ def __getitem__(self, name):
+ if name == 'tableNamed':
+ if not hasattr(self, '_v_tables'): self.tpValues()
+ return self._v_tables.__of__(self)
+ raise KeyError, name
+
+
+ ## old stuff from ZPsycopgDA 1.1 (never implemented) ##
+
+ def manage_wizard(self, tables):
+ "Wizard of what? Oozing?"
+
+ def manage_join(self, tables, select_cols, join_cols, REQUEST=None):
+ """Create an SQL join"""
+
+ def manage_insert(self, table, cols, REQUEST=None):
+ """Create an SQL insert"""
+
+ def manage_update(self, table, keys, cols, REQUEST=None):
+ """Create an SQL update"""
diff --git a/ZPsycopgDA/__init__.py b/ZPsycopgDA/__init__.py
new file mode 100644
index 0000000..b0e2a45
--- /dev/null
+++ b/ZPsycopgDA/__init__.py
@@ -0,0 +1,32 @@
+# ZPsycopgDA/__init__.py - ZPsycopgDA Zope product
+#
+# Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# Or, at your option this program (ZPsycopgDA) can be distributed under the
+# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
+# http://www.zope.org/Resources/ZPL.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# See the LICENSE file for details.
+
+__doc__ = "ZPsycopg Database Adalper Registration."
+__version__ = '2.0'
+
+import sys
+import string
+import DA
+
+methods = DA.folder_methods
+classes = DA.classes
+meta_types = DA.meta_types
+misc_ = DA.misc_
+
+__ac_permissions__=DA.__ac_permissions__
diff --git a/ZPsycopgDA/db.py b/ZPsycopgDA/db.py
new file mode 100644
index 0000000..c859535
--- /dev/null
+++ b/ZPsycopgDA/db.py
@@ -0,0 +1,209 @@
+# ZPsycopgDA/db.py - query execution
+#
+# Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# Or, at your option this program (ZPsycopgDA) can be distributed under the
+# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
+# http://www.zope.org/Resources/ZPL.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# See the LICENSE file for details.
+
+from Shared.DC.ZRDB.TM import TM
+from Shared.DC.ZRDB import dbi_db
+
+from ZODB.POSException import ConflictError
+
+import time
+import site
+import pool
+
+import psycopg
+from psycopg.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN
+from psycopg import NUMBER, STRING, ROWID, DATETIME
+
+
+
+# the DB object, managing all the real query work
+
+class DB(TM, dbi_db.DB):
+
+ _p_oid = _p_changed = _registered = None
+
+ def __init__(self, dsn, tilevel, enc='utf-8'):
+ self.dsn = dsn
+ self.tilevel = tilevel
+ self.encoding = enc
+ self.failures = 0
+ self.calls = 0
+
+ def getconn(self, create=True):
+ conn = pool.getconn(self.dsn)
+ conn.set_isolation_level(int(self.tilevel))
+ return conn
+
+ def putconn(self, close=False):
+ try:
+ conn = pool.getconn(self.dsn, False)
+ except AttributeError:
+ pass
+ pool.putconn(self.dsn, conn, close)
+
+ def getcursor(self):
+ conn = self.getconn()
+ return conn.cursor()
+
+ def _finish(self, *ignored):
+ try:
+ conn = self.getconn(False)
+ conn.commit()
+ self.putconn()
+ except AttributeError:
+ pass
+
+ def _abort(self, *ignored):
+ try:
+ conn = self.getconn(False)
+ conn.rollback()
+ self.putconn()
+ except AttributeError:
+ pass
+
+ def open(self):
+ # this will create a new pool for our DSN if not already existing,
+ # then get and immediately release a connection
+ self.getconn()
+ self.putconn()
+
+ def close(self):
+ # FIXME: if this connection is closed we flush all the pool associated
+ # with the current DSN; does this makes sense?
+ pool.flushpool(self.dsn)
+
+ def sortKey(self):
+ return 1
+
+ ## tables and rows ##
+
+ def tables(self, rdb=0, _care=('TABLE', 'VIEW')):
+ self._register()
+ c = self.getcursor()
+ c.execute(
+ "SELECT t.tablename AS NAME, 'TABLE' AS TYPE "
+ " FROM pg_tables t WHERE tableowner <> 'postgres' "
+ "UNION SELECT v.viewname AS NAME, 'VIEW' AS TYPE "
+ " FROM pg_views v WHERE viewowner <> 'postgres' "
+ "UNION SELECT t.tablename AS NAME, 'SYSTEM_TABLE\' AS TYPE "
+ " FROM pg_tables t WHERE tableowner = 'postgres' "
+ "UNION SELECT v.viewname AS NAME, 'SYSTEM_TABLE' AS TYPE "
+ "FROM pg_views v WHERE viewowner = 'postgres'")
+ res = []
+ for name, typ in c.fetchall():
+ if typ in _care:
+ res.append({'TABLE_NAME': name, 'TABLE_TYPE': typ})
+ self.putconn()
+ return res
+
+ def columns(self, table_name):
+ self._register()
+ c = self.getcursor()
+ try:
+ r = c.execute('SELECT * FROM "%s" WHERE 1=0' % table_name)
+ except:
+ return ()
+ res = []
+ for name, type, width, ds, p, scale, null_ok in c.description:
+ if type == NUMBER:
+ if type == INTEGER:
+ type = INTEGER
+ elif type == FLOAT:
+ type = FLOAT
+ else: type = NUMBER
+ elif type == BOOLEAN:
+ type = BOOLEAN
+ elif type == ROWID:
+ type = ROWID
+ elif type == DATETIME:
+ type = DATETIME
+ else:
+ type = STRING
+
+ res.append({'Name': name,
+ 'Type': type.name,
+ 'Precision': 0,
+ 'Scale': 0,
+ 'Nullable': 0})
+ self.putconn()
+ return res
+
+ ## query execution ##
+
+ def query(self, query_string, max_rows=None, query_data=None):
+ self._register()
+ self.calls = self.calls+1
+
+ desc = ()
+ res = []
+ nselects = 0
+
+ c = self.getcursor()
+
+ try:
+ for qs in [x for x in query_string.split('\0') if x]:
+ if type(qs) == unicode:
+ if self.encoding:
+ qs = qs.encode(self.encoding)
+ try:
+ if (query_data):
+ c.execute(qs, query_data)
+ else:
+ c.execute(qs)
+ except (psycopg.ProgrammingError, psycopg.IntegrityError), e:
+ if e.args[0].find("concurrent update") > -1:
+ raise ConflictError
+ raise e
+ if c.description is not None:
+ nselects += 1
+ if c.description != desc and nselects > 1:
+ raise psycopg.ProgrammingError(
+ 'multiple selects in single query not allowed')
+ if max_rows:
+ res = c.fetchmany(max_rows)
+ else:
+ res = c.fetchall()
+ desc = c.description
+ self.failures = 0
+
+ except StandardError, err:
+ self._abort()
+ raise err
+
+ items = []
+ for name, typ, width, ds, p, scale, null_ok in desc:
+ if typ == NUMBER:
+ if typ == INTEGER or typ == LONGINTEGER: typs = 'i'
+ else: typs = 'n'
+ elif typ == BOOLEAN:
+ typs = 'n'
+ elif typ == ROWID:
+ typs = 'i'
+ elif typ == DATETIME:
+ typs = 'd'
+ else:
+ typs = 's'
+ items.append({
+ 'name': name,
+ 'type': typs,
+ 'width': width,
+ 'null': null_ok,
+ })
+
+ return items, res
diff --git a/ZPsycopgDA/dtml/add.dtml b/ZPsycopgDA/dtml/add.dtml
new file mode 100644
index 0000000..d138779
--- /dev/null
+++ b/ZPsycopgDA/dtml/add.dtml
@@ -0,0 +1,96 @@
+<dtml-var manage_page_header>
+
+<dtml-var "manage_form_title(this(), _,
+ form_title='Add Z Psycopg Database Connection',
+ help_product='ZPsycopgDA',
+ help_topic='ZPsycopgDA-Method-Add.stx'
+ )">
+
+<p class="form-help">
+A Zope Psycopg Database Connection is used to connect and execute
+queries on a PostgreSQL database.
+</p>
+
+<p class="form-help">
+In the form below <em>Connection String</em> (also called the Data Source Name
+or DSN for short) is a string... (TODO: finish docs)
+</p>
+
+<form action="manage_addZPsycopgConnection" method="POST">
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Id
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="id" size="40"
+ value="Psycopg_database_connection" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-optional">
+ Title
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="title" size="40"
+ value="Z Psycopg Database Connection"/>
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Connection string
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="connection_string" size="40" value="" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Connect immediately
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="checkbox" name="check" value="YES" checked="YES" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Use Zope's internal DateTime
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="checkbox" name="zdatetime" value="YES" checked="YES" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Transaction isolation level
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <select name="tilevel:int">
+ <option value="1">Read committed</option>
+ <option value="2" selected="YES">Serializable</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top" colspan="2">
+ <div class="form-element">
+ <input class="form-element" type="submit" name="submit" value=" Add " />
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+<dtml-var manage_page_footer>
diff --git a/ZPsycopgDA/dtml/edit.dtml b/ZPsycopgDA/dtml/edit.dtml
new file mode 100644
index 0000000..45275ed
--- /dev/null
+++ b/ZPsycopgDA/dtml/edit.dtml
@@ -0,0 +1,67 @@
+<dtml-var manage_page_header>
+<dtml-var manage_tabs>
+
+<form action="manage_edit" method="POST">
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-optional">
+ Title
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="title" size="40"
+ value="&dtml-title;"/>
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Connection string
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="connection_string" size="40"
+ value="&dtml-connection_string;" />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Use Zope's internal DateTime
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="checkbox" name="zdatetime" value="YES"
+ <dtml-if expr="zdatetime">checked="YES"</dtml-if> />
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Transaction isolation level
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <select name="tilevel:int">
+ <option value="1"
+ <dtml-if expr="tilevel==1">selected="YES"</dtml-if">>
+ Read committed</option>
+ <option value="2"
+ <dtml-if expr="tilevel==2">selected="YES"</dtml-if">>
+ Serializable</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td align="left" valign="top" colspan="2">
+ <div class="form-element">
+ <input class="form-element" type="submit" name="submit"
+ value=" Save Changes " />
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+<dtml-var manage_page_footer>
diff --git a/ZPsycopgDA/icons/bin.gif b/ZPsycopgDA/icons/bin.gif
new file mode 100644
index 0000000..fa4fdd0
--- /dev/null
+++ b/ZPsycopgDA/icons/bin.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/date.gif b/ZPsycopgDA/icons/date.gif
new file mode 100644
index 0000000..0d88a57
--- /dev/null
+++ b/ZPsycopgDA/icons/date.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/datetime.gif b/ZPsycopgDA/icons/datetime.gif
new file mode 100644
index 0000000..faa540b
--- /dev/null
+++ b/ZPsycopgDA/icons/datetime.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/field.gif b/ZPsycopgDA/icons/field.gif
new file mode 100644
index 0000000..9bf8692
--- /dev/null
+++ b/ZPsycopgDA/icons/field.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/float.gif b/ZPsycopgDA/icons/float.gif
new file mode 100644
index 0000000..efc5c78
--- /dev/null
+++ b/ZPsycopgDA/icons/float.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/int.gif b/ZPsycopgDA/icons/int.gif
new file mode 100644
index 0000000..5ee3ced
--- /dev/null
+++ b/ZPsycopgDA/icons/int.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/stable.gif b/ZPsycopgDA/icons/stable.gif
new file mode 100644
index 0000000..acdd37d
--- /dev/null
+++ b/ZPsycopgDA/icons/stable.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/table.gif b/ZPsycopgDA/icons/table.gif
new file mode 100644
index 0000000..4fb32d9
--- /dev/null
+++ b/ZPsycopgDA/icons/table.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/text.gif b/ZPsycopgDA/icons/text.gif
new file mode 100644
index 0000000..c9d5365
--- /dev/null
+++ b/ZPsycopgDA/icons/text.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/time.gif b/ZPsycopgDA/icons/time.gif
new file mode 100644
index 0000000..6d08915
--- /dev/null
+++ b/ZPsycopgDA/icons/time.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/view.gif b/ZPsycopgDA/icons/view.gif
new file mode 100644
index 0000000..71b30de
--- /dev/null
+++ b/ZPsycopgDA/icons/view.gif
Binary files differ
diff --git a/ZPsycopgDA/icons/what.gif b/ZPsycopgDA/icons/what.gif
new file mode 100644
index 0000000..0214a4d
--- /dev/null
+++ b/ZPsycopgDA/icons/what.gif
Binary files differ
diff --git a/ZPsycopgDA/pool.py b/ZPsycopgDA/pool.py
new file mode 100644
index 0000000..8cc7fa7
--- /dev/null
+++ b/ZPsycopgDA/pool.py
@@ -0,0 +1,51 @@
+# ZPsycopgDA/pool.py - ZPsycopgDA Zope product: connection pooling
+#
+# Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version.
+#
+# Or, at your option this program (ZPsycopgDA) can be distributed under the
+# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
+# http://www.zope.org/Resources/ZPL.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# See the LICENSE file for details.
+
+# all the connections are held in a pool of pools, directly accessible by the
+# ZPsycopgDA code in db.py
+
+import threading
+import psycopg.pool
+
+_connections_pool = {}
+_connections_lock = threading.Lock()
+
+def getpool(dsn, create=True):
+ _connections_lock.acquire()
+ try:
+ if not _connections_pool.has_key(dsn) and create:
+ _connections_pool[dsn] = \
+ psycopg.pool.ThreadedConnectionPool(4, 200, dsn)
+ finally:
+ _connections_lock.release()
+ return _connections_pool[dsn]
+
+def flushpool(dsn):
+ _connections_lock.acquire()
+ try:
+ _connections_pool[dsn].closeall()
+ del _connections_pool[dsn]
+ finally:
+ _connections_lock.release()
+
+def getconn(dsn, create=True):
+ return getpool(dsn, create=create).getconn()
+
+def putconn(dsn, conn, close=False):
+ getpool(dsn).putconn(conn, close=close)