Skip to content

Commit 2c086dc

Browse files
author
Richard Jones
committed
make mysql / postgresql work again. beginnings of otk/session store in rdbmses
1 parent 243806e commit 2c086dc

File tree

9 files changed

+220
-124
lines changed

9 files changed

+220
-124
lines changed

roundup/backends/back_mysql.py

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,68 @@
1515
import os, shutil
1616
from MySQLdb.constants import ER
1717

18-
# Database maintenance functions
18+
1919
def db_nuke(config):
2020
"""Clear all database contents and drop database itself"""
21-
db = Database(config, 'admin')
22-
try:
23-
db.sql_commit()
24-
db.sql("DROP DATABASE %s" % config.MYSQL_DBNAME)
25-
db.sql("CREATE DATABASE %s" % config.MYSQL_DBNAME)
26-
finally:
27-
db.close()
21+
if db_exists(config):
22+
conn = MySQLdb.connect(config.MYSQL_DBHOST, config.MYSQL_DBUSER,
23+
config.MYSQL_DBPASSWORD)
24+
try:
25+
conn.select_db(config.MYSQL_DBNAME)
26+
except:
27+
# no, it doesn't exist
28+
pass
29+
else:
30+
cursor = conn.cursor()
31+
cursor.execute("SHOW TABLES")
32+
tables = cursor.fetchall()
33+
for table in tables:
34+
if __debug__:
35+
print >>hyperdb.DEBUG, 'DROP TABLE %s'%table[0]
36+
cursor.execute("DROP TABLE %s"%table[0])
37+
if __debug__:
38+
print >>hyperdb.DEBUG, "DROP DATABASE %s"%config.MYSQL_DBNAME
39+
cursor.execute("DROP DATABASE %s"%config.MYSQL_DBNAME)
40+
conn.commit()
41+
conn.close()
42+
2843
if os.path.exists(config.DATABASE):
2944
shutil.rmtree(config.DATABASE)
3045

46+
def db_create(config):
47+
"""Create the database."""
48+
conn = MySQLdb.connect(config.MYSQL_DBHOST, config.MYSQL_DBUSER,
49+
config.MYSQL_DBPASSWORD)
50+
cursor = conn.cursor()
51+
if __debug__:
52+
print >>hyperdb.DEBUG, "CREATE DATABASE %s"%config.MYSQL_DBNAME
53+
cursor.execute("CREATE DATABASE %s"%config.MYSQL_DBNAME)
54+
conn.commit()
55+
conn.close()
56+
3157
def db_exists(config):
32-
"""Check if database already exists"""
33-
# Yes, this is a hack, but we must must open connection without
34-
# selecting a database to prevent creation of some tables
35-
config.MYSQL_DATABASE = (config.MYSQL_DBHOST, config.MYSQL_DBUSER,
36-
config.MYSQL_DBPASSWORD)
37-
db = Database(config, 'admin')
58+
"""Check if database already exists."""
59+
conn = MySQLdb.connect(config.MYSQL_DBHOST, config.MYSQL_DBUSER,
60+
config.MYSQL_DBPASSWORD)
61+
# tables = None
3862
try:
39-
db.conn.select_db(config.MYSQL_DBNAME)
40-
config.MYSQL_DATABASE = (config.MYSQL_DBHOST, config.MYSQL_DBUSER,
41-
config.MYSQL_DBPASSWORD, config.MYSQL_DBNAME)
42-
db.sql("SHOW TABLES")
43-
tables = db.sql_fetchall()
63+
try:
64+
conn.select_db(config.MYSQL_DBNAME)
65+
# cursor = conn.cursor()
66+
# cursor.execute("SHOW TABLES")
67+
# tables = cursor.fetchall()
68+
# if __debug__:
69+
# print >>hyperdb.DEBUG, "tables %s"%(tables,)
70+
except MySQLdb.OperationalError:
71+
if __debug__:
72+
print >>hyperdb.DEBUG, "no database '%s'"%config.MYSQL_DBNAME
73+
return 0
4474
finally:
45-
db.close()
46-
if tables or os.path.exists(config.DATABASE):
47-
return 1
48-
return 0
75+
conn.close()
76+
if __debug__:
77+
print >>hyperdb.DEBUG, "database '%s' exists"%config.MYSQL_DBNAME
78+
return 1
79+
4980

5081
class Database(Database):
5182
arg = '%s'
@@ -57,6 +88,10 @@ class Database(Database):
5788
#mysql_backend = 'BDB'
5889

5990
def sql_open_connection(self):
91+
# make sure the database actually exists
92+
if not db_exists(self.config):
93+
db_create(self.config)
94+
6095
db = getattr(self.config, 'MYSQL_DATABASE')
6196
try:
6297
self.conn = MySQLdb.connect(*db)
@@ -75,7 +110,7 @@ def sql_open_connection(self):
75110
except MySQLdb.ProgrammingError, message:
76111
if message[0] != ER.NO_SUCH_TABLE:
77112
raise DatabaseError, message
78-
self.database_schema = {}
113+
self.init_dbschema()
79114
self.sql("CREATE TABLE schema (schema TEXT) TYPE=%s"%
80115
self.mysql_backend)
81116
# TODO: use AUTO_INCREMENT for generating ids:
@@ -86,12 +121,12 @@ def sql_open_connection(self):
86121
self.create_version_2_tables()
87122

88123
def create_version_2_tables(self):
89-
self.cursor.execute('CREATE TABLE otks (key VARCHAR(255), '
90-
'value VARCHAR(255), __time FLOAT(20))')
91-
self.cursor.execute('CREATE INDEX otks_key_idx ON otks(key)')
92-
self.cursor.execute('CREATE TABLE sessions (key VARCHAR(255), '
93-
'last_use FLOAT(20), user VARCHAR(255))')
94-
self.cursor.execute('CREATE INDEX sessions_key_idx ON sessions(key)')
124+
self.cursor.execute('CREATE TABLE otks (otk_key VARCHAR(255), '
125+
'otk_value VARCHAR(255), otk_time FLOAT(20))')
126+
self.cursor.execute('CREATE INDEX otks_key_idx ON otks(otk_key)')
127+
self.cursor.execute('CREATE TABLE sessions (s_key VARCHAR(255), '
128+
's_last_use FLOAT(20), s_user VARCHAR(255))')
129+
self.cursor.execute('CREATE INDEX sessions_key_idx ON sessions(s_key)')
95130

96131
def __repr__(self):
97132
return '<myroundsql 0x%x>'%id(self)

roundup/backends/back_postgresql.py

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,86 @@
99
__docformat__ = 'restructuredtext'
1010

1111

12+
import os, shutil, popen2, time
13+
import psycopg
14+
1215
from roundup import hyperdb, date
1316
from roundup.backends import rdbms_common
14-
import psycopg
15-
import os, shutil, popen2
17+
18+
def db_create(config):
19+
"""Clear all database contents and drop database itself"""
20+
if __debug__:
21+
print >> hyperdb.DEBUG, '+++ create database +++'
22+
name = config.POSTGRESQL_DATABASE['database']
23+
n = 0
24+
while n < 10:
25+
cout,cin = popen2.popen4('createdb %s'%name)
26+
cin.close()
27+
response = cout.read().split('\n')[0]
28+
if response.find('FATAL') != -1:
29+
raise RuntimeError, response
30+
elif response.find('ERROR') != -1:
31+
if not response.find('is being accessed by other users') != -1:
32+
raise RuntimeError, response
33+
if __debug__:
34+
print >> hyperdb.DEBUG, '+++ SLEEPING +++'
35+
time.sleep(1)
36+
n += 1
37+
continue
38+
return
39+
raise RuntimeError, '10 attempts to create database failed'
40+
41+
def db_nuke(config, fail_ok=0):
42+
"""Clear all database contents and drop database itself"""
43+
if __debug__:
44+
print >> hyperdb.DEBUG, '+++ nuke database +++'
45+
name = config.POSTGRESQL_DATABASE['database']
46+
n = 0
47+
if os.path.exists(config.DATABASE):
48+
shutil.rmtree(config.DATABASE)
49+
while n < 10:
50+
cout,cin = popen2.popen4('dropdb %s'%name)
51+
cin.close()
52+
response = cout.read().split('\n')[0]
53+
if response.endswith('does not exist') and fail_ok:
54+
return
55+
elif response.find('FATAL') != -1:
56+
raise RuntimeError, response
57+
elif response.find('ERROR') != -1:
58+
if not response.find('is being accessed by other users') != -1:
59+
raise RuntimeError, response
60+
if __debug__:
61+
print >> hyperdb.DEBUG, '+++ SLEEPING +++'
62+
time.sleep(1)
63+
n += 1
64+
continue
65+
return
66+
raise RuntimeError, '10 attempts to nuke database failed'
67+
68+
def db_exists(config):
69+
"""Check if database already exists"""
70+
db = getattr(config, 'POSTGRESQL_DATABASE')
71+
try:
72+
conn = psycopg.connect(**db)
73+
conn.close()
74+
if __debug__:
75+
print >> hyperdb.DEBUG, '+++ database exists +++'
76+
return 1
77+
except:
78+
if __debug__:
79+
print >> hyperdb.DEBUG, '+++ no database +++'
80+
return 0
1681

1782
class Database(rdbms_common.Database):
1883
arg = '%s'
1984

2085
def sql_open_connection(self):
86+
if not db_exists(self.config):
87+
db_create(self.config)
88+
89+
if __debug__:
90+
print >>hyperdb.DEBUG, '+++ open database connection +++'
91+
2192
db = getattr(self.config, 'POSTGRESQL_DATABASE')
2293
try:
2394
self.conn = psycopg.connect(**db)
@@ -30,19 +101,19 @@ def sql_open_connection(self):
30101
self.load_dbschema()
31102
except:
32103
self.rollback()
33-
self.database_schema = {}
104+
self.init_dbschema()
34105
self.sql("CREATE TABLE schema (schema TEXT)")
35106
self.sql("CREATE TABLE ids (name VARCHAR(255), num INT4)")
36107
self.sql("CREATE INDEX ids_name_idx ON ids(name)")
37108
self.create_version_2_tables()
38109

39110
def create_version_2_tables(self):
40-
self.cursor.execute('CREATE TABLE otks (key VARCHAR(255), '
41-
'value VARCHAR(255), __time NUMERIC)')
42-
self.cursor.execute('CREATE INDEX otks_key_idx ON otks(key)')
43-
self.cursor.execute('CREATE TABLE sessions (key VARCHAR(255), '
44-
'last_use NUMERIC, user VARCHAR(255))')
45-
self.cursor.execute('CREATE INDEX sessions_key_idx ON sessions(key)')
111+
self.cursor.execute('CREATE TABLE otks (otk_key VARCHAR(255), '
112+
'otk_value VARCHAR(255), otk_time FLOAT(20))')
113+
self.cursor.execute('CREATE INDEX otks_key_idx ON otks(otk_key)')
114+
self.cursor.execute('CREATE TABLE sessions (s_key VARCHAR(255), '
115+
's_last_use FLOAT(20), s_user VARCHAR(255))')
116+
self.cursor.execute('CREATE INDEX sessions_key_idx ON sessions(s_key)')
46117

47118
def __repr__(self):
48119
return '<roundpsycopgsql 0x%x>' % id(self)

roundup/backends/back_sqlite.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: back_sqlite.py,v 1.14 2004-03-05 00:08:09 richard Exp $
1+
# $Id: back_sqlite.py,v 1.15 2004-03-12 04:08:59 richard Exp $
22
'''Implements a backend for SQLite.
33
44
See https://pysqlite.sourceforge.net/ for pysqlite info
@@ -34,19 +34,19 @@ def sql_open_connection(self):
3434
except sqlite.DatabaseError, error:
3535
if str(error) != 'no such table: schema':
3636
raise
37-
self.database_schema = {}
37+
self.init_dbschema()
3838
self.cursor.execute('create table schema (schema varchar)')
3939
self.cursor.execute('create table ids (name varchar, num integer)')
4040
self.cursor.execute('create index ids_name_idx on ids(name)')
4141
self.create_version_2_tables()
4242

4343
def create_version_2_tables(self):
44-
self.cursor.execute('create table otks (key varchar, '
45-
'value varchar, __time varchar)')
46-
self.cursor.execute('create index otks_key_idx on otks(key)')
47-
self.cursor.execute('create table sessions (key varchar, '
48-
'last_use varchar, user varchar)')
49-
self.cursor.execute('create index sessions_key_idx on sessions(key)')
44+
self.cursor.execute('create table otks (otk_key varchar, '
45+
'otk_value varchar, otk_time varchar)')
46+
self.cursor.execute('create index otks_key_idx on otks(otk_key)')
47+
self.cursor.execute('create table sessions (s_key varchar, '
48+
's_last_use varchar, s_user varchar)')
49+
self.cursor.execute('create index sessions_key_idx on sessions(s_key)')
5050

5151
def sql_close(self):
5252
''' Squash any error caused by us already having closed the

roundup/backends/rdbms_common.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.76 2004-03-05 00:08:09 richard Exp $
1+
# $Id: rdbms_common.py,v 1.77 2004-03-12 04:08:59 richard Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -23,7 +23,7 @@
2323
The schema of the hyperdb being mapped to the database is stored in the
2424
database itself as a repr()'ed dictionary of information about each Class
2525
that maps to a table. If that information differs from the hyperdb schema,
26-
then we update it. We also store in the schema dict a __version__ which
26+
then we update it. We also store in the schema dict a version which
2727
allows us to upgrade the database schema when necessary. See upgrade_db().
2828
'''
2929
__docformat__ = 'restructuredtext'
@@ -114,11 +114,21 @@ def sql_stringquote(self, value):
114114
'''
115115
return re.sub("'", "''", str(value))
116116

117+
def init_dbschema(self):
118+
self.database_schema = {
119+
'version': self.current_db_version,
120+
'tables': {}
121+
}
122+
117123
def load_dbschema(self):
118124
''' Load the schema definition that the database currently implements
119125
'''
120126
self.cursor.execute('select schema from schema')
121-
self.database_schema = eval(self.cursor.fetchone()[0])
127+
schema = self.cursor.fetchone()
128+
if schema:
129+
self.database_schema = eval(schema[0])
130+
else:
131+
self.database_schema = {}
122132

123133
def save_dbschema(self, schema):
124134
''' Save the schema definition that the database currently implements
@@ -132,25 +142,25 @@ def post_init(self):
132142
We should now confirm that the schema defined by our "classes"
133143
attribute actually matches the schema in the database.
134144
'''
135-
self.upgrade_db()
145+
save = self.upgrade_db()
136146

137147
# now detect changes in the schema
138-
save = 0
148+
tables = self.database_schema['tables']
139149
for classname, spec in self.classes.items():
140-
if self.database_schema.has_key(classname):
141-
dbspec = self.database_schema[classname]
150+
if tables.has_key(classname):
151+
dbspec = tables[classname]
142152
if self.update_class(spec, dbspec):
143-
self.database_schema[classname] = spec.schema()
153+
tables[classname] = spec.schema()
144154
save = 1
145155
else:
146156
self.create_class(spec)
147-
self.database_schema[classname] = spec.schema()
157+
tables[classname] = spec.schema()
148158
save = 1
149159

150-
for classname, spec in self.database_schema.items():
160+
for classname, spec in tables.items():
151161
if not self.classes.has_key(classname):
152-
self.drop_class(classname, spec)
153-
del self.database_schema[classname]
162+
self.drop_class(classname, tables[classname])
163+
del tables[classname]
154164
save = 1
155165

156166
# update the database version of the schema
@@ -170,14 +180,19 @@ def post_init(self):
170180
current_db_version = 2
171181
def upgrade_db(self):
172182
''' Update the SQL database to reflect changes in the backend code.
183+
184+
Return boolean whether we need to save the schema.
173185
'''
174-
version = self.database_schema.get('__version', 1)
186+
version = self.database_schema.get('version', 1)
175187
if version == 1:
176188
# version 1 doesn't have the OTK, session and indexing in the
177189
# database
178190
self.create_version_2_tables()
191+
else:
192+
return 0
179193

180-
self.database_schema['__version'] = self.current_db_version
194+
self.database_schema['version'] = self.current_db_version
195+
return 1
181196

182197

183198
def refresh_database(self):
@@ -950,6 +965,8 @@ def pack(self, pack_before):
950965
def sql_commit(self):
951966
''' Actually commit to the database.
952967
'''
968+
if __debug__:
969+
print >>hyperdb.DEBUG, '+++ commit database connection +++'
953970
self.conn.commit()
954971

955972
def commit(self):
@@ -1011,6 +1028,8 @@ def doSaveNode(self, classname, nodeid, node):
10111028
return (classname, nodeid)
10121029

10131030
def sql_close(self):
1031+
if __debug__:
1032+
print >>hyperdb.DEBUG, '+++ close database connection +++'
10141033
self.conn.close()
10151034

10161035
def close(self):

0 commit comments

Comments
 (0)