1
##############################################################################
3
# Zope Public License (ZPL) Version 1.0
4
# -------------------------------------
6
# Copyright (c) Digital Creations. All rights reserved.
8
# This license has been certified as Open Source(tm).
10
# Redistribution and use in source and binary forms, with or without
11
# modification, are permitted provided that the following conditions are
14
# 1. Redistributions in source code must retain the above copyright
15
# notice, this list of conditions, and the following disclaimer.
17
# 2. Redistributions in binary form must reproduce the above copyright
18
# notice, this list of conditions, and the following disclaimer in
19
# the documentation and/or other materials provided with the
22
# 3. Digital Creations requests that attribution be given to Zope
23
# in any manner possible. Zope includes a "Powered by Zope"
24
# button that is installed by default. While it is not a license
25
# violation to remove this button, it is requested that the
26
# attribution remain. A significant investment has been put
27
# into Zope, and this effort will continue if the Zope community
28
# continues to grow. This is one way to assure that growth.
30
# 4. All advertising materials and documentation mentioning
31
# features derived from or use of this software must display
32
# the following acknowledgement:
34
# "This product includes software developed by Digital Creations
35
# for use in the Z Object Publishing Environment
36
# (http://www.zope.org/)."
38
# In the event that the product being advertised includes an
39
# intact Zope distribution (with copyright and license included)
40
# then this clause is waived.
42
# 5. Names associated with Zope or Digital Creations must not be used to
43
# endorse or promote products derived from this software without
44
# prior written permission from Digital Creations.
46
# 6. Modified redistributions of any form whatsoever must retain
47
# the following acknowledgment:
49
# "This product includes software developed by Digital Creations
50
# for use in the Z Object Publishing Environment
51
# (http://www.zope.org/)."
53
# Intact (re-)distributions of any official Zope release do not
54
# require an external acknowledgement.
56
# 7. Modifications are encouraged but must be packaged separately as
57
# patches to official Zope releases. Distributions that do not
58
# clearly separate the patches from the original work must be clearly
59
# labeled as unofficial distributions. Modifications which do not
60
# carry the name Zope may be packaged in any form, as long as they
61
# conform to all of the clauses above.
66
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
67
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
68
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
69
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
70
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
71
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
72
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
73
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
74
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
75
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
76
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80
# This software consists of contributions made by Digital Creations and
81
# many individuals on behalf of Digital Creations. Specific
82
# attributions are listed in the accompanying credits file.
84
##############################################################################
85
database_type='Psycopg'
86
__doc__='''%s Database Connection
88
$Id: DA.py 531 2004-09-18 09:54:40Z fog $''' % database_type
89
__version__='$Revision: 1.20.2.14 $'[11:-2]
90
__psycopg_versions__ = ('1.1.12', '1.1.13', '1.1.14', '1.1.15', '1.1.16')
1
# ZPsycopgDA/DA.py - ZPsycopgDA Zope product: Database Connection
3
# Copyright (C) 2004 Federico Di Gregorio <fog@initd.org>
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by the
7
# Free Software Foundation; either version 2, or (at your option) any later
10
# Or, at your option this program (ZPsycopgDA) can be distributed under the
11
# Zope Public License (ZPL) Version 1.0, as published on the Zope web site,
12
# http://www.zope.org/Resources/ZPL.
14
# This program is distributed in the hope that it will be useful, but
15
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY
16
# or FITNESS FOR A PARTICULAR PURPOSE.
18
# See the LICENSE file for details.
21
ALLOWED_PSYCOPG_VERSIONS = ('1.99.9',)
26
import Shared.DC.ZRDB.Connection
94
import Shared.DC.ZRDB.Connection, sys, DABase, time
95
from Globals import HTMLFile, ImageFile
29
from Globals import DTMLFile
30
from Globals import HTMLFile
31
from ImageFile import ImageFile
96
32
from ExtensionClass import Base
97
from string import find, join, split, rindex
100
from psycopg import new_type, register_type, DATETIME, TIME, DATE, INTERVAL
101
except StandardError, err:
104
from DateTime import DateTime
105
except StandardError, err:
108
from App.Dialogs import MessageDialog
113
manage_addZPsycopgConnectionForm = HTMLFile('connectionAdd', globals())
114
def manage_addZPsycopgConnection(self, id, title,
115
connection_string, zdatetime=None,
116
tilevel=2, check=None, REQUEST=None):
117
"""Add a DB connection to a folder"""
118
self._setObject(id, Connection(id, title, connection_string, zdatetime,
120
if REQUEST is not None: return self.manage_main(self,REQUEST)
123
# Convert an ISO timestamp string from postgres to a DateTime (zope version)
125
def cast_DateTime(str):
127
# this will split us into [date, time, GMT/AM/PM(if there)]
130
# we now should split out any timezone info
131
dt[1] = split(dt[1], '-')[0]
132
dt[1] = split(dt[1], '+')[0]
133
t = time.mktime(time.strptime(join(dt[:2], ' '), '%Y-%m-%d %H:%M:%S'))
135
t = time.mktime(time.strptime(dt[0], '%Y-%m-%d %H:%M:%S'))
138
# Convert an ISO date string from postgres to a DateTime(zope version)
142
return DateTime(time.mktime(time.strptime(str, '%Y-%m-%d')))
144
# Convert a time string from postgres to a DateTime(zope version) object.
145
# WARNING: We set the day as today before feeding to DateTime so
146
# that it has the same DST settings.
149
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
150
time.localtime(time.time())[:3]+
151
time.strptime(str[:8], "%H:%M:%S")[3:]))
153
# Convert a time string from postgres to a DateTime(zope version) object.
154
# WARNING: We set the day as the epoch day (1970-01-01) since this
155
# DateTime does not support time deltas. (EXPERIMENTAL USE WITH CARE!)
156
def cast_Interval(str):
33
from DateTime import DateTime
35
# import psycopg and functions/singletons needed for date/time conversions
38
from psycopg import DATETIME
39
from psycopg.extensions import TIME, DATE, INTERVAL
40
from psycopg.extensions import new_type, register_type
44
# add a new connection to a folder
46
manage_addZPsycopgConnectionForm = DTMLFile('dtml/add',globals())
48
def manage_addZPsycopgConnection(self, id, title, connection_string,
49
zdatetime=None, tilevel=2,
50
check=None, REQUEST=None):
51
"""Add a DB connection to a folder."""
52
self._setObject(id, Connection(id, title, connection_string,
53
zdatetime, check, tilevel))
54
if REQUEST is not None: return self.manage_main(self, REQUEST)
58
# the connection object
160
60
class Connection(DABase.Connection):
161
"The connection class."
162
database_type = database_type
163
id = '%s_database_connection' % database_type
164
meta_type = title = 'Z %s Database Connection' % database_type
165
icon = 'misc_/Z%sDA/conn' % database_type
61
"""ZPsycopg Connection."""
62
id = 'Psycopg_database_connection'
63
database_type = 'Psycopg'
64
meta_type = title = 'Z Psycopg Database Connection'
65
icon = 'misc_/ZPsycopg/conn'
167
def __init__(self, id, title, connection_string, zdatetime,
168
check=None, tilevel=2, encoding='UTF-8'):
169
self.zdatetime=zdatetime
67
def __init__(self, id, title, connection_string,
68
zdatetime, check=None, tilevel=2, encoding=''):
69
self.zdatetime = zdatetime
171
71
self.edit(title, connection_string, zdatetime,
172
72
check=check, tilevel=tilevel, encoding=encoding)
174
def edit(self, title, connection_string, zdatetime,
175
check=1, tilevel=2, encoding='UTF-8'):
177
self.connection_string=connection_string
178
self.zdatetime=zdatetime
180
self.encoding=encoding
78
return self._v_database_connection.table_info()
80
def edit(self, title, connection_string,
81
zdatetime, check=None, tilevel=2, encoding=''):
83
self.connection_string = connection_string
84
self.zdatetime = zdatetime
85
self.tilevel = tilevel
86
self.encoding = encoding
181
88
self.set_type_casts()
182
if check: self.connect(connection_string)
90
if check: self.connect(self.connection_string)
184
manage_properties=HTMLFile('connectionEdit', globals())
92
manage_properties = DTMLFile('dtml/edit', globals())
186
94
def manage_edit(self, title, connection_string,
187
95
zdatetime=None, check=None, tilevel=2, encoding='UTF-8',
97
"""Edit the DB connection."""
191
98
self.edit(title, connection_string, zdatetime,
192
99
check=check, tilevel=tilevel, encoding=encoding)
193
100
if REQUEST is not None:
194
return MessageDialog(
196
message='<strong>%s</strong> has been edited.' % self.id,
197
action ='./manage_main',
101
msg = "Connection edited."
102
return self.manage_main(self,REQUEST,manage_tabs_message=msg)
104
def connect(self, s):
106
self._v_database_connection.close()
110
# check psycopg version and raise exception if does not match
111
if psycopg.__version__ not in ALLOWED_PSYCOPG_VERSIONS:
112
raise ImportError("psycopg version mismatch (imported %s)" +
115
self.set_type_casts()
116
self._v_connected = ''
119
# TODO: let the psycopg exception propagate, or not?
120
self._v_database_connection = dbf(
121
self.connection_string, self.tilevel, self.encoding)
122
self._v_database_connection.open()
123
self._v_connected = DateTime()
200
127
def set_type_casts(self):
201
"Make changes to psycopg default typecast list"
128
# note that in both cases order *is* important
202
129
if self.zdatetime:
203
#use zope internal datetime routines
204
ZDATETIME=new_type((1184,1114), "ZDATETIME", cast_DateTime)
205
ZDATE=new_type((1082,), "ZDATE", cast_Date)
206
ZTIME=new_type((1083,), "ZTIME", cast_Time)
207
ZINTERVAL=new_type((1186,), "ZINTERVAL", cast_Interval)
130
# use zope internal datetime routines
208
131
register_type(ZDATETIME)
209
132
register_type(ZDATE)
210
133
register_type(ZTIME)
211
134
register_type(ZINTERVAL)
213
#use the standard. WARN: order is important!
214
137
register_type(DATETIME)
215
138
register_type(DATE)
216
139
register_type(TIME)
217
140
register_type(INTERVAL)
222
def table_info(self):
223
return self._v_database_connection.table_info()
226
try: self._v_database_connection.close()
229
# check psycopg version and raise exception if does not match
230
if psycopg.__version__ not in __psycopg_versions__:
231
raise ImportError("psycopg version mismatch: " +
234
self.set_type_casts()
239
# this is necessary when upgrading from old installs without
240
# having to recreate the connection object
241
if not hasattr(self, 'tilevel'):
243
if not hasattr(self, 'encoding'):
244
self.encoding = 'UTF-8'
245
self._v_database_connection=DB(s, self.tilevel, self.encoding)
247
t, v, tb = sys.exc_info()
248
raise 'BadRequest', (
249
'<strong>Could not open connection.<br>'
250
'Connection string: </strong><CODE>%s</CODE><br>\n'
251
'<pre>\n%s\n%s\n</pre>\n'
254
self._v_connected=DateTime()
258
def sql_quote__(self, v):
260
quote_dict = {"\'": "''", "\\": "\\\\"}
261
for dkey in quote_dict.keys():
262
if find(v, dkey) >= 0:
263
v=join(split(v,dkey),quote_dict[dkey])
267
classes = ('DA.Connection',)
270
{'name':'Z %s Database Connection' % database_type,
271
'action':'manage_addZ%sConnectionForm' % database_type},)
142
# database connection registration data
144
classes = (Connection,)
146
meta_types = ({'name':'Z Psycopg Database Connection',
147
'action':'manage_addZPsycopgConnectionForm'},)
274
150
'manage_addZPsycopgConnection': manage_addZPsycopgConnection,
275
151
'manage_addZPsycopgConnectionForm': manage_addZPsycopgConnectionForm}
153
__ac_permissions__ = (
278
154
('Add Z Psycopg Database Connections',
279
155
('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),)
282
'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')}
284
for icon in ('table', 'view', 'stable', 'what',
285
'field', 'text','bin','int','float',
286
'date','time','datetime'):
159
misc_={'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')}
161
for icon in ('table', 'view', 'stable', 'what', 'field', 'text', 'bin',
162
'int', 'float', 'date', 'time', 'datetime'):
287
163
misc_[icon] = ImageFile('icons/%s.gif' % icon, globals())
165
# zope-specific psycopg typecasters
167
# convert an ISO timestamp string from postgres to a Zope DateTime object
168
def _cast_DateTime(str):
170
# this will split us into [date, time, GMT/AM/PM(if there)]
173
# we now should split out any timezone info
174
dt[1] = split(dt[1], '-')[0]
175
dt[1] = split(dt[1], '+')[0]
176
return DateTime(join(dt[:2], ' '))
178
return DateTime(dt[0])
180
# convert an ISO date string from postgres to a Zope DateTime object
185
# Convert a time string from postgres to a Zope DateTime object.
186
# NOTE: we set the day as today before feeding to DateTime so
187
# that it has the same DST settings.
190
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
191
time.localtime(time.time())[:3]+
192
time.strptime(str[:8], "%H:%M:%S")[3:]))
194
# TODO: DateTime does not support intervals: what's the best we can do?
195
def _cast_Interval(str):
198
ZDATETIME = new_type((1184, 1114), "ZDATETIME", _cast_DateTime)
199
ZINTERVAL = new_type((1186,), "ZINTERVAL", _cast_Interval)
200
ZDATE = new_type((1082,), "ZDATE", _cast_Date)
201
ZTIME = new_type((1083,), "ZTIME", _cast_Time)