|
/
Zope
/
gocept svn checkins
/
Archive
/
2006
/
2006-10
/
SVN: r4338 - in tcm2sql/trunk: . tests
[
SVN: r4335 - AlphaFlow/branches/wosc-aspects / ... ]
[
SVN: r4349 - lms/branches/mac_postgres_branch/lib/... ]
SVN: r4338 - in tcm2sql/trunk: . tests
Michael Howitz <mh(at)gocept.com> |
2006-10-10 11:53:30 |
[ FULL ]
|
Author: mac
Date: Tue Oct 10 11:53:26 2006
New Revision: 4338
Modified:
tcm2sql/trunk/SSDReader.py
tcm2sql/trunk/tcm2sql.py
tcm2sql/trunk/tests/test_ssdreader.py
Log:
fixed tests because global optCreateLoggingTables did not exist in test
Modified: tcm2sql/trunk/SSDReader.py
==============================================================================
--- tcm2sql/trunk/SSDReader.py (original)
+++ tcm2sql/trunk/SSDReader.py Tue Oct 10 11:53:26 2006
(at)(at) -58,12 +58,11 (at)(at)
# mapping child -> parent
self.parent = {}
- def build(self):
+ def build(self, optCreateLoggingTables):
self.read_all()
self.build_tables()
self.build_relations()
self.build_generalizations()
- global optCreateLoggingTables
if optCreateLoggingTables:
self.build_logtables()
Modified: tcm2sql/trunk/tcm2sql.py
==============================================================================
--- tcm2sql/trunk/tcm2sql.py (original)
+++ tcm2sql/trunk/tcm2sql.py Tue Oct 10 11:53:26 2006
(at)(at) -93,13 +93,13 (at)(at)
if oldStateFile is not None:
oldState = SSDReader(oldStateFile)
- oldState.build()
+ oldState.build(__builtins__.optCreateLoggingTables)
if newStateFile is None:
usage()
sys.exit()
newState = SSDReader(newStateFile)
-newState.build()
+newState.build(__builtins__.optCreateLoggingTables)
if rendererName is None:
sys.stderr.write("Note: using RenderPostgres\n")
Modified: tcm2sql/trunk/tests/test_ssdreader.py
==============================================================================
--- tcm2sql/trunk/tests/test_ssdreader.py (original)
+++ tcm2sql/trunk/tests/test_ssdreader.py Tue Oct 10 11:53:26 2006
(at)(at) -1,7 +1,7 (at)(at)
# Copyright (c) 2003 gocept gmbh & co. kg, http://www.gocept.com
# Christian Zagrodnick, cz(at)gocept.com
# See also LICENSE.txt
-# $Id: test_ssdreader.py,v 1.2 2003/08/14 08:42:26 zagy Exp $
+# $Id$
import os
import unittest
(at)(at) -18,7 +18,7 (at)(at)
def test_read(self):
self.assertRaises(IOError, SSDReader, 'does-not-exist')
ssd = SSDReader(self.ssd_filename)
- ssd.build()
+ ssd.build(1)
pet = ssd.tables['Pet']
self.assertEquals(len(pet.attrlist), 4)
self.assertEquals(len(pet.pklist), 1)
|
SVN: r4339 - tcm2sql/trunk/doc
Michael Howitz <mh(at)gocept.com> |
2006-10-10 11:55:18 |
[ FULL ]
|
Author: mac
Date: Tue Oct 10 11:55:16 2006
New Revision: 4339
Modified:
tcm2sql/trunk/doc/Example-1.ssd
Log:
fixed constraint definition
Modified: tcm2sql/trunk/doc/Example-1.ssd
==============================================================================
--- tcm2sql/trunk/doc/Example-1.ssd (original)
+++ tcm2sql/trunk/doc/Example-1.ssd Tue Oct 10 11:55:16 2006
(at)(at) -1,9 +1,9 (at)(at)
Storage
{
- { Format 1.31 }
- { GeneratedFrom TSSD-version-2.01 }
- { WrittenBy zagy }
- { WrittenOn "Mon Feb 4 14:49:41 2002" }
+ { Format 1.33 }
+ { GeneratedFrom TSSD-version-2.20 }
+ { WrittenBy mac }
+ { WrittenOn "" }
}
Document
(at)(at) -13,6 +13,7 (at)(at)
{ Author zagy }
{ CreatedOn "Mon Feb 4 09:16:02 2002" }
{ Annotation "" }
+ { Hierarchy False }
}
Page
(at)(at) -34,7 +35,7 (at)(at)
SSDClassNode 1
{
{ Name "Pet" }
- { Annotation "This is a nice Pet.\r\rBut be aware that\r? invalidGender:
check gender in ('m','f')\ris a constraint, whereas the <ext> is beeing
ignored." }
+ { Annotation "This is a nice Pet.\r\rBut be aware that\r? invalidGender:
check(gender in ('m','f'))\ris a constraint, whereas the <ext> is beeing
ignored." }
{ Parent 0 }
{ Index "" }
{ Attributes 4 }
(at)(at) -370,7 +371,7 (at)(at)
{ End2 WhiteTriangle }
{ Points 2 }
{ Point 107 237 }
- { Point 128 148 }
+ { Point 128 149 }
{ NamePosition 104 190 }
{ Color "black" }
{ LineWidth 1 }
(at)(at) -393,7 +394,7 (at)(at)
{ End2 WhiteTriangle }
{ Points 2 }
{ Point 230 237 }
- { Point 175 148 }
+ { Point 175 149 }
{ NamePosition 213 187 }
{ Color "black" }
{ LineWidth 1 }
|
SVN: r4340 - tcm2sql/trunk
Michael Howitz <mh(at)gocept.com> |
2006-10-10 11:57:28 |
[ FULL ]
|
Author: mac
Date: Tue Oct 10 11:57:27 2006
New Revision: 4340
Modified:
tcm2sql/trunk/README (contents, props changed)
Log:
corrected Composition relation documentation
Modified: tcm2sql/trunk/README
==============================================================================
--- tcm2sql/trunk/README (original)
+++ tcm2sql/trunk/README Tue Oct 10 11:57:27 2006
(at)(at) -5,7 +5,7 (at)(at)
Author: Christian Zagrodnick
Email: cz+gocept.com
Valid for: tcm2sql 0.9.1
- CVS: $Id: README,v 1.9 2005/03/31 11:31:49 zagy Exp $
+ CVS: $Id$
Copying
(at)(at) -142,7 +142,7 (at)(at)
* Composition (black diamond)
- results in an `on delete cascade'
+ results in an `on delete cascade on update cascade'
The diamond has to be connected to the table
with the referenced PRIMARY KEY.
|
SVN: r4341 - tcm2sql/trunk
Michael Howitz <mh(at)gocept.com> |
2006-10-10 11:58:58 |
[ FULL ]
|
Author: mac
Date: Tue Oct 10 11:58:54 2006
New Revision: 4341
Modified:
tcm2sql/trunk/Render.py
Log:
reniced whitespace usage for readability
Modified: tcm2sql/trunk/Render.py
==============================================================================
--- tcm2sql/trunk/Render.py (original)
+++ tcm2sql/trunk/Render.py Tue Oct 10 11:58:54 2006
(at)(at) -1,6 +1,7 (at)(at)
-# Copyright (C) 2002 gocept gmbh & co.kg, 06366 Koethen/Anahlt, Germany
+# Copyright (C) 2002-2006 gocept gmbh & co.kg, 06112 Halle(Saale), Germany
# Christian Zagrodnick, cz(at)gocept.com
-# $Id: Render.py,v 1.4 2003/08/14 09:50:39 zagy Exp $
+# Michael Howitz, mh(at)gocept.com
+# $Id$
#
# 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
(at)(at) -16,10 +17,11 (at)(at)
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+import copy
class Render:
- def __init__(self,new,old=None):
+ def __init__(self, new, old=None):
self.new=new
self.old=old
(at)(at) -55,7 +57,7 (at)(at)
def _remainingTables(self):
return [t
- for t in self._oldTables()+self._newTables()
+ for t in self._oldTables() + self._newTables()
if t not in self._removedTables()
if t not in self._addedTables()
]
(at)(at) -116,60 +118,50 (at)(at)
if r not in self._oldRelations()
]
-
-
def _getOrder(self, state):
- import copy
-
- TABLES=state.tables
- PARENT=state.parent
-
- k=TABLES.keys()
- dim=len(TABLES.keys())
- matrix=dim*[dim*[0]]
+ TABLES = state.tables
+ PARENT = state.parent
+ k = TABLES.keys()
+ dim = len(TABLES.keys())
+ matrix = dim*[dim*[0]]
+
# adjazenzmatrix aufbauen und reflexive huelle bilden
- for i in range(0,len(matrix)):
- matrix[i]=copy.deepcopy(matrix[i])
- for j in range (0,len(matrix)):
- if (PARENT.get(k[i],0)==k[j]) or i==j:
- matrix[i][j]=1
+ for i in xrange(0, len(matrix)):
+ matrix[i] = copy.deepcopy(matrix[i])
+ for j in xrange (0, len(matrix)):
+ if (PARENT.get(k[i], 0) == k[j]) or i == j:
+ matrix[i][j] = 1
- # transitive Huelle bilden
+ # transitive Huelle bilden
# Algorithmus nach Warshall
# http://www.informatik.uni-frankfurt.de/~zinndorf/haskell/mathe.htm
- for k in range(0,len(matrix)):
- for zeile in range(0,len(matrix)):
- for spalte in range(0,len(matrix)):
+ for k in xrange(0, len(matrix)):
+ for zeile in xrange(0, len(matrix)):
+ for spalte in xrange(0, len(matrix)):
if not matrix[zeile][spalte]:
- matrix[zeile][spalte]=\
- (matrix[zeile][k] and
- matrix[k][spalte])
-
-
+ matrix[zeile][spalte] = (matrix[zeile][k] and
+ matrix[k][spalte])
# Die Antisymetrie zu ueberpruefen spar ich mir; wenn der user nicht
# ganz doof ist passt das schon mit der halbordnungsrelation
-
# sortierung
- sorted=[]
+ sorted = []
- for k in range(0,len(matrix)):
- max=0
- maxid=0
-
- for i in range(0,len(matrix)):
- sum=0
- for j in range(0,len(matrix)):
- sum=sum+matrix[j][i]
- if sum>max:
- max=sum
- maxid=i
-
- sorted=sorted+[TABLES.keys()[maxid]]
- for j in range(0,len(matrix)):
- matrix[j][maxid]=0
+ for k in xrange(0, len(matrix)):
+ max = 0
+ maxid = 0
+
+ for i in xrange(0, len(matrix)):
+ sum = 0
+ for j in xrange(0, len(matrix)):
+ sum = sum + matrix[j][i]
+ if sum > max:
+ max = sum
+ maxid = i
+
+ sorted = sorted + [TABLES.keys()[maxid]]
+ for j in xrange(0, len(matrix)):
+ matrix[j][maxid] = 0
return sorted
-
-
|
SVN: r4342 - tcm2sql/trunk
Michael Howitz <mh(at)gocept.com> |
2006-10-10 12:00:07 |
[ FULL ]
|
Author: mac
Date: Tue Oct 10 12:00:04 2006
New Revision: 4342
Added:
tcm2sql/trunk/RenderDB.py (contents, props changed)
Modified:
tcm2sql/trunk/RenderPostgres.py
Log:
Moved most functionality from RenderPostgress to RenderDB to make support of
other DBMS like MySQL easier
Added: tcm2sql/trunk/RenderDB.py
==============================================================================
--- (empty file)
+++ tcm2sql/trunk/RenderDB.py Tue Oct 10 12:00:04 2006
(at)(at) -0,0 +1,388 (at)(at)
+# Copyright (C) 2006 gocept gmbh & co.kg, 06112 Halle(Saale), Germany
+# Christian Zagrodnick, cz(at)gocept.com
+# Michael Howitz, mh(at)gocept.com
+# $Id$
+#
+# 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 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# python
+import re
+
+# sibling
+from Render import Render as RenderBase
+
+class Render(RenderBase):
+ """Abstract renderer class for databases."""
+
+ _abstract = True # set it to false on concrete classes
+
+ ### the following methods may have to be overwritten for concrete DBMS ###
+
+ def startTransaction(self):
+ """Return the command to start a transaction."""
+ return "BEGIN;\n"
+
+ def commitTransaction(self):
+ """Return the command to commit a transaction."""
+ return "COMMIT;\n"
+
+ def createTable(self, tablename, column_list):
+ result = ["\nCREATE TABLE %s (" % tablename]
+ result.extend(column_list)
+ result.append(")")
+ return "\n".join(result)
+
+ def dropTable(self, tablename):
+ return 'DROP TABLE %s;\n' % tablename
+
+ def renderInheritenceTableFooter(self, tablename, parents, all_tables):
+ if tablename in parents.keys():
+ return (" INHERITS (%s)" %
+ all_tables[parents[tablename]].name)
+ else:
+ return ""
+
+ def renderTableFooter(self):
+ return ""
+
+ def renderAttribute(self, attr):
+ """Render one attribute."""
+ return " %s %s," % (attr[0], attr[1])
+
+ def renderSerialType(self, tablename, columnname):
+ return ("INTEGER NOT NULL DEFAULT "
+ "NEXTVAL('\"%s_%s_seq\"'::text)" %
+ (tablename.lower(), columnname.lower()))
+
+ def renderConstraint(self, name, rule):
+ return "CONSTRAINT %s %s," % (name, rule)
+
+ def copyToTemporaryTable(self, tablename):
+ return 'CREATE TEMPORARY TABLE "TMP%s" AS SELECT * FROM %s;\n' % \
+ (tablename.replace('"', ''), tablename)
+
+ def copyFromTemporaryTable(self, tablename, fields):
+ return ('INSERT INTO %s (%s)\n'
+ ' SELECT %s FROM "TMP%s";\n' %
+ (tablename, fields, fields, tablename.replace('"', '')))
+
+ def createView(self, tablename, columnlist):
+ result = ['CREATE VIEW "sv%s" AS' % tablename,
+ ' SELECT',
+ ' ' + ','.join(columnlist),
+ ' FROM %s;' % tablename,
+ '', ]
+ return "\n".join(result)
+
+ def dropView(self, tablename):
+ return 'DROP VIEW "sv%s";\n' % tablename
+
+ def createSequence(self, tablename, columnname):
+ return "CREATE SEQUENCE %s_%s_seq;\n" % (tablename, columnname)
+
+ def dropSequence(self, tablename, columnname):
+ return "DROP SEQUENCE %s_%s_seq;\n" % (tablename, columnname)
+
+ def renderRelation(self, rel, TABLES):
+ """Create foreign key constraint."""
+ table1name = TABLES[rel.table1].name
+ table2name = TABLES[rel.table2].name
+ result = ["ALTER TABLE %s" % table1name,
+ "ADD CONSTRAINT %s" % self._get_foreign_key(table2name,
+ rel.field2),
+ "FOREIGN KEY (%s)" % rel.field1,
+ "REFERENCES %s (%s)" % (table2name, rel.field2),
+ ]
+ if rel.kind == 1: # aggregation
+ result.append("ON DELETE SET NULL")
+ elif rel.kind == 2: # composition
+ result.extend(["ON DELETE CASCADE",
+ "ON UPDATE CASCADE"])
+ elif rel.kind == 3: # binary
+ pass # XXX
+ result.append(";\n")
+ return "\n".join(result)
+
+ def dropRelation(self, rel, TABLES):
+ "Drop foreign key constraint."""
+ table1name = TABLES[rel.table1].name
+ table2name = TABLES[rel.table2].name
+ result = ["\nALTER TABLE %s" % table1name,
+ "DROP CONSTRAINT %s" % self._get_foreign_key(table2name,
+ rel.field2),
+ ";"]
+ return "\n".join(result)
+
+ def logRules(self, TABLES, table, PARENT):
+ """Create triggers for logging tables. """
+ tn = table.name
+ log_table = table.getLoggingTable()
+ log_fields = ', '.join(
+ map(lambda x: x[0],
+ self._inheritedFields(log_table.name, TABLES, PARENT,
+ fields=[])))
+ table_fields = ', '.join(
+ map(lambda x: 'new.%s' % (x[0], ),
+ self._inheritedFields(tn, TABLES, PARENT, fields=[])))
+
+ result = ["""\nCREATE or REPLACE FUNCTION "trig_%s"() """
+ """RETURNS TRIGGER AS '""" % tn,
+ " BEGIN",
+ " INSERT INTO %s (%s)" % (log_table.name,
log_fields),
+ " VALUES (now(), %s);" % table_fields,
+ " RETURN NULL;",
+ " END;'",
+ "LANGUAGE 'plpgsql';",
+ "CREATE TRIGGER I%s AFTER INSERT OR UPDATE ON %s" % (tn,
tn),
+ 'FOR EACH ROW EXECUTE PROCEDURE "trig_%s"();' % tn,
+ 'CREATE RULE "U%s" AS ON UPDATE TO %s DO INSTEAD NOTHING;'
%\
+ (tn, log_table.name),
+ 'CREATE RULE "D%s" AS ON DELETE TO %s DO INSTEAD NOTHING;'
%\
+ (tn, log_table.name),
+ '']
+ return "\n".join(result)
+
+ def fixup_logging_helper(self, ssd):
+ global optCreateLoggingTables
+ for table in ssd.tables.values():
+ # add LOGUser if logging is on
+ if optCreateLoggingTables:
+ table.attrlist.insert(0, ('"LOGUser"', 'VARCHAR(32) NOT
NULL'))
+ table.flaglist.insert(0, ('"LOGUser"', ''))
+
+ # the rest here is only for logging tables
+ if not table.isLoggingTable():
+ continue
+
+ # add LOGTime to logging tables
+ table.attrlist.insert(0, ('"LOGTime"',
+ 'TIMESTAMP NOT NULL DEFAULT now()'))
+ table.flaglist.insert(0, ('"LOGTime"', ''))
+
+ # set serials to integer in logging tables
+ for i in range(0, len(table.attrlist)):
+ name, type = table.attrlist[i]
+ if self._serial_pattern.match(type):
+ table.attrlist[i] = (name, 'integer')
+
+
+ ### The following methods are independent from DBMS. ###
+
+ _serial_pattern = re.compile(r"^\s*serial\s*$")
+
+ def __init__(self, *cwd, **kw):
+ RenderBase.__init__(self, *cwd, **kw)
+ self._foreign_keys = []
+ self._fixup_logging()
+ if self._abstract:
+ raise SystemError('%s is an abstract class, you can not use it '
+ 'as a renderer.' % self.__class__.__name__)
+
+ def _layoutFull(self):
+ """Returns a string with the table layout."""
+
+ TABLES = self.new.tables
+ TABLES_VALUES = TABLES.values()
+ RELATIONS = self.new.relations
+ PARENT = self.new.parent
+
+ ret = self.startTransaction()
+
+ # create tables
+ for tableid in self._getOrder(self.new):
+ table = TABLES[tableid]
+ ret += self._renderTable(table, TABLES, RELATIONS, PARENT)
+ ret += "\n\n"
+
+ # create sequences for tables
+ for (tablename, colname) in self._get_serials(TABLES_VALUES):
+ ret += self.createSequence(tablename, colname)
+ ret += "\n\n"
+
+ # create relations
+ for rel in RELATIONS:
+ ret += self.renderRelation(rel, TABLES)
+ ret += "\n\n"
+
+ # create logging tables if requested
+ if optCreateLoggingTables:
+ non_logging_tables = [ table
+ for table in TABLES_VALUES
+ if not table.isLoggingTable()
+ ]
+ for table in non_logging_tables:
+ ret += self.logRules(TABLES, table, PARENT)
+
+ ret += self.commitTransaction()
+
+ return ret
+
+ def _layoutDiff(self):
+ """Returns a string with the diff layout."""
+ global optCreateViews
+
+ ret = self.startTransaction()
+
+ # drop the foreign key constraints, so tables may be freely dropped
+ for rel in self.old.relations:
+ ret += self.dropRelation(rel, self.old.tables)
+
+ # clean foreign key cache so that numbering if their ids stays
constant
+ self._foreign_keys = []
+
+ # copy table contents to temporary tables, drop old tables
+ dropOrder=self._getOrder(self.old)
+ dropOrder.reverse()
+ for tid in dropOrder:
+ t = self.old.tables[tid]
+ ret += self.copyToTemporaryTable(t.name)
+ if not t.isLoggingTable() and optCreateViews:
+ ret += self.dropView(t.name)
+ ret += self.dropTable(t.name)
+ ret += "\n"
+
+ # create the new tables
+ for tableid in self._getOrder(self.new):
+ ret += self._renderTable(self.new.tables[tableid],
self.new.tables,
+ self.new.relations, self.new.parent)
+
+ # copy data back
+ dropedFields=self._dropedFields()
+ for t in [t
+ for t in self._oldTables()
+ for t2 in self._newTables()
+ if t == t2
+ ]:
+ dfThis=\
+ map((lambda x: x[1]),
+ filter((lambda x: x[0]==t),
+ dropedFields))
+ fields=','.join(
+ filter(lambda x: x not in dfThis,
+ map(lambda x: x[0],
+ t.attrlist)))
+ if fields > '':
+ ret += self.copyFromTemporaryTable(t.name, fields)
+ ret += "\n\n"
+
+ # drop sequences of deleted tables
+ for (tablename, colname) in self._get_serials(self._removedTables()):
+ ret += self.dropSequence(tablename, colname)
+ ret += "\n\n"
+
+ # create sequences for new tables
+ for (tablename, colname) in self._get_serials(self._addedTables()):
+ ret += self.createSequence(tablename, colname)
+ ret += "\n\n"
+
+ # create the foreign key constraints
+ for rel in self.new.relations:
+ ret += self.renderRelation(rel, self.new.tables)
+
+ # create log rules
+ global optCreateLoggingTables
+ if optCreateLoggingTables:
+ for table in [t
+ for t in self.new.tables.values()
+ if not t.isLoggingTable()]:
+ ret += self.logRules(self.new.tables, table, self.new.parent)
+
+ ret += self.commitTransaction()
+ return ret
+
+
+ def _renderTable(self, table, TABLES, RELATIONS, PARENT):
+ """Render a table."""
+ global optCreateViews
+
+ # transforms Attributes with type 'serial'
+ attrs = []
+ for (name, type) in table.attrlist:
+ if self._serial_pattern.match(type) is not None:
+ type = self.renderSerialType(table.name, name)
+ attrs.append((name, type))
+
+ # render Attributes
+ lines = [self.renderAttribute(attr) for attr in attrs]
+
+ # constraints
+ lines.extend([self.renderConstraint(cs.name, cs.rule)
+ for cs in table.clist])
+
+ if len(lines):
+ # if there are lines remove the komma on the end of the last line
+ lines[-1] = lines[-1][:-1]
+
+ ret = self.createTable(table.name, lines)
+
+ # inheritance (generalization)
+ ret += self.renderInheritenceTableFooter(table.name, PARENT, TABLES)
+
+ ret += self.renderTableFooter()
+
+ if not table.isLoggingTable():
+ attrlist=map(lambda x: x[0],
+ filter(lambda x: '-' not in x[1],
+ self._inheritedFields(table.name, TABLES, PARENT, fields=[])))
+
+ if optCreateViews and len(attrlist) > 0:
+ ret += "\n"
+ ret += self.createView(table.name, attrlist)
+ return ret
+
+
+ def _inheritedFields(self,tableid,TABLES,PARENT,fields=[]):
+ #print "in: %s: %s" %(tableid, fields)
+ f = []
+ if tableid in PARENT.keys():
+ f = self._inheritedFields(PARENT[tableid], TABLES, PARENT,
+ fields=fields)
+
+ for x in TABLES[tableid].flaglist + f:
+ if x not in fields:
+ fields += [x, ]
+
+ #print "out: %s: %s" %(tableid,fields)
+ return fields
+
+ def _get_foreign_key(self, table, field):
+ postfix = ''
+ field_name = '_'.join([x.strip() for x in field.split(',')])
+ while 1:
+ fk_name = 'FK%s_%s%s' % (table, field_name, postfix)
+ if fk_name not in self._foreign_keys:
+ break
+ if postfix == '':
+ postfix = 0
+ postfix += 1
+ self._foreign_keys.append(fk_name)
+ return fk_name
+
+ def _fixup_logging(self):
+ self.fixup_logging_helper(self.new)
+ if self.old:
+ self.fixup_logging_helper(self.old)
+
+ def _get_serials(self, tables):
+ """Get the columns which are of type 'serial'.
+
+ Returns list of tuples (tablename, columnname).
+ """
+ result = []
+ for table in tables:
+ for (name, type) in table.attrlist:
+ if self._serial_pattern.match(type) is not None:
+ result.append((table.name, name))
+ return result
Modified: tcm2sql/trunk/RenderPostgres.py
==============================================================================
--- tcm2sql/trunk/RenderPostgres.py (original)
+++ tcm2sql/trunk/RenderPostgres.py Tue Oct 10 12:00:04 2006
(at)(at) -17,311 +17,16 (at)(at)
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-# python
-import string # XXX phase out
-import re
-import copy
-import random
-
-# sibling
-from Render import Render as RenderBase
+from RenderDB import Render as RenderBase
class Render(RenderBase):
- """ Postgres renderer """
-
- _serial_pattern = re.compile(r"^\s*serial\s*$")
-
- def __init__(self, *cwd, **kw):
- RenderBase.__init__(self, *cwd, **kw)
- self._foreign_keys = []
- self._fixup_logging()
-
- def _layoutFull(self):
- """ returns a string with the table layout """
-
- TABLES = self.new.tables
- RELATIONS = self.new.relations
- PARENT = self.new.parent
-
- ret="BEGIN;\n"
-
- for tableid in self._getOrder(self.new):
- table = TABLES[tableid]
- ret += self._renderTable(table, TABLES, RELATIONS, PARENT)
-
- for rel in RELATIONS:
- ret+=self._renderRelation(rel,TABLES)
-
- if optCreateLoggingTables:
- non_logging_tables = [ table
- for table in self.new.tables.values()
- if not table.isLoggingTable()
- ]
- for table in non_logging_tables:
- ret += self._logRules(self.new.tables, table, PARENT)
-
- ret += "COMMIT;\n"
-
- return ret
-
- def _layoutDiff(self):
- """ returns a string with the diff layout """
- global optCreateViews
-
- random.seed()
- ret="begin;\n"
-
-
- # copy tables, drop tables
- # this will drop all the foreign key constrains
- dropOrder=self._getOrder(self.old)
- dropOrder.reverse()
- for tid in dropOrder:
- t = self.old.tables[tid]
- ret += 'create temporary table "TMP%s" ' \
- 'as select * from %s;\n' % (t.name.replace('"',''), t.name)
- ret += "drop table %s;\n" % (t.name, )
- if not t.isLoggingTable() and optCreateViews:
- ret += 'drop view "sv%s";\n' % t.name
- ret += "\n"
-
-
- # create the new tables
- for tableid in self._getOrder(self.new):
- table=self.new.tables[tableid]
- nattr=[]
- for (name,type) in table.attrlist:
- if self._serial_pattern.match(type) is not None:
- type="integer not null default "+\
- "nextval('\"%s_%s_seq\"'::text)" %\
- (table.name.lower(),name.lower())
- nattr.append((name,type))
-
- oldattr = table.attrlist
- table.attrlist = nattr
- ret += self._renderTable(table, self.new.tables,
- self.new.relations, self.new.parent)
- table.attrlist = oldattr
-
-
- # copy data back
- dropedFields=self._dropedFields()
- for t in [t
- for t in self._oldTables()
- for t2 in self._newTables()
- if t==t2
- ]:
- dfThis=\
- map((lambda x: x[1]),
- filter((lambda x: x[0]==t),
- dropedFields))
- fields=string.join(
- filter(lambda x: x not in dfThis,
- map(lambda x: x[0],
- t.attrlist)),',')
- if fields>'':
- ret+="insert into %s (%s)\n" % (t.name,fields)
- ret+=" select %s from \"TMP%s\";\n" %\
- (fields,t.name.replace('"',''))
-
- ret += "\n\n"
-
- # drop sequences of deleted tables
- for table in self._removedTables():
- for (name,type) in table.attrlist:
- if self._serial_pattern.match(type) is not None:
- ret += "DROP SEQUENCE %s_%s_seq;\n" % (table.name, name)
-
- ret += "\n\n"
-
- # create sequences for new tables
- for table in self._addedTables():
- for (name,type) in table.attrlist:
- if self._serial_pattern.match(type) is not None:
- ret += "CREATE SEQUENCE %s_%s_seq;\n" % (table.name, name)
-
- ret += "\n\n"
-
- # create the foreign key constraints
- for rel in self.new.relations:
- ret+=self._renderRelation(rel,self.new.tables)
-
-
- for table in [t
- for t in self.new.tables.values()
- if not t.isLoggingTable()]:
- ret += self._logRules(self.new.tables, table, self.new.parent)
-
- ret += "commit;\n"
-
- return ret
-
-
-
-
-
- def _renderTable(self,table,TABLES,RELATIONS,PARENT):
- """ render table """
- global optCreateViews
-
- ret=""
-
- ret+= "CREATE TABLE %s (\n" % table.name
- count=0
-
- # Attributes
- for attr in table.attrlist:
- if count>0:
- ret+= ",\n"
- count=count+1
- ret+=self._renderAttribute(table,attr,RELATIONS)
-
-
-
- # constraints
- for cs in table.clist:
- if count>0:
- ret+= ",\n "
- ret+=self._renderConstraint(cs.name,cs.rule)
- count=count+1
-
- ret+= "\n)"
-
- # inheritance (generalization)
- if table.name in PARENT.keys():
- ret+= (" INHERITS (%s)" %
- TABLES[PARENT[table.name]].name)
-
- ret+= " WITHOUT OIDS;\n\n"
-
- if not table.isLoggingTable():
- attrlist=map(lambda x: x[0],
- filter(lambda x: '-' not in x[1],
- self._inheritedFields(table.name, TABLES, PARENT, fields=[])))
-
- if optCreateViews and len(attrlist)>0:
- ret+='CREATE VIEW "sv%s" AS\n' %(table.name,)
- ret+=' SELECT\n '
- ret+=string.join(attrlist,',')
- ret+='\n FROM %s;\n\n' % (table.name,)
- return ret
-
-
-
- def _renderAttribute(self,table,attr,RELATIONS):
- """ render one attribute """
-
- ret=""
-
- ret+= (" %s %s" % (attr[0],attr[1]))
- return ret
-
- def _renderConstraint(self,name,rule):
- return ("CONSTRAINT %s %s" % (name,rule))
-
-
- def _renderRelation(self,rel,TABLES):
- ret=""
-
- ret+= ("ALTER TABLE %s\n" % TABLES[rel.table1].name)
- ret+= ("ADD CONSTRAINT %s\n" % (self._get_foreign_key(
- TABLES[rel.table2].name, rel.field2)))
- ret+= ("FOREIGN KEY (%s)\n" % rel.field1)
- ret+= ("REFERENCES %s (%s)\n" % (TABLES[rel.table2].name,
- rel.field2))
-
- if rel.kind==1:
- # aggregation
- ret+= "ON DELETE SET NULL\n"
- pass
- elif rel.kind==2:
- # composition
- ret+= "ON DELETE CASCADE\nON UPDATE CASCADE\n"
- elif rel.kind==3:
- # binary
- pass # XXX
- ret+=";\n"
- return ret
-
-
- def _logRules(self, TABLES, table, PARENT):
- """create triggers for logging tables
- """
- log_table = table.getLoggingTable()
- log_fields =', '.join(
- map(lambda x: x[0],
-
self._inheritedFields(log_table.name,TABLES,PARENT,fields=[])))
- table_fields = ', '.join(
- map(lambda x: 'new.%s' % (x[0], ),
- self._inheritedFields(table.name,TABLES,PARENT,fields=[])))
- ret = ""
- ret += 'CREATE or REPLACE FUNCTION "trig_%s"() RETURNS ' % (
- table.name, )
- ret += "TRIGGER AS '\n"
- ret += " BEGIN\n"
- ret += ' INSERT INTO %s (%s)\n' % (log_table.name, log_fields)
- ret += " VALUES (now(), %s);\n" % (table_fields, )
- ret += ' RETURN NULL;\n'
- ret += " END;'\n"
- ret += "LANGUAGE 'plpgsql';\n"
- ret += 'CREATE TRIGGER I%s AFTER INSERT OR UPDATE ON %s\n' % (
- table.name, table.name)
- ret += 'FOR EACH ROW EXECUTE PROCEDURE "trig_%s"();\n' % (
- table.name, )
- ret += 'CREATE RULE "U%s" AS ON UPDATE TO %s DO INSTEAD NOTHING;\n' %
(
- table.name, log_table.name)
- ret += 'CREATE RULE "D%s" AS ON DELETE TO %s DO INSTEAD NOTHING;\n\n'
% (
- table.name, log_table.name)
-
- return ret
-
- def _inheritedFields(self,tableid,TABLES,PARENT,fields=[]):
- #print "in: %s: %s" %(tableid, fields)
- f=[]
- if tableid in PARENT.keys():
-
f=self._inheritedFields(PARENT[tableid],TABLES,PARENT,fields=fields)
-
- for x in TABLES[tableid].flaglist+f:
- if x not in fields: fields+=[x,]
-
- #print "out: %s: %s" %(tableid,fields)
+ """Postgres renderer."""
- return fields
-
- def _get_foreign_key(self, table, field):
- postfix = ''
- field_name = '_'.join([x.strip() for x in field.split(',')])
- fk_name = None
- while 1:
- fk_name = 'FK%s_%s%s' % (table, field_name, postfix)
- if fk_name not in self._foreign_keys:
- break
- if postfix == '':
- postfix = 0
- postfix += 1
- self._foreign_keys.append(fk_name)
- return fk_name
+ _abstract = False
- def _fixup_logging(self):
- self._fixup_logging_helper(self.new)
- if self.old:
- self._fixup_logging_helper(self.old)
+ def renderTableFooter(self):
+ return " WITHOUT OIDS;\n"
- def _fixup_logging_helper(self, ssd):
- global optCreateLoggingTables
- for table in ssd.tables.values():
- if optCreateLoggingTables:
- table.attrlist.insert(0, ('"LOGUser"', 'varchar(32) not
null'))
- table.flaglist.insert(0, ('"LOGUser"', ''))
- if not table.isLoggingTable():
- continue
- table.attrlist.insert(0, ('"LOGTime"',
- 'timestamp not null default now()'))
- table.flaglist.insert(0, ('"LOGTime"', ''))
- for i in range(0, len(table.attrlist)):
- name, type = table.attrlist[i]
- if self._serial_pattern.match(type):
- table.attrlist[i] = (name, 'integer')
|
SVN: r4347 - tcm2sql/trunk
Michael Howitz <mh(at)gocept.com> |
2006-10-11 09:30:05 |
[ FULL ]
|
Author: mac
Date: Wed Oct 11 09:30:02 2006
New Revision: 4347
Modified:
tcm2sql/trunk/RenderDB.py
Log:
made constraints line up with columns in table definition
Modified: tcm2sql/trunk/RenderDB.py
==============================================================================
--- tcm2sql/trunk/RenderDB.py (original)
+++ tcm2sql/trunk/RenderDB.py Wed Oct 11 09:30:02 2006
(at)(at) -67,7 +67,7 (at)(at)
(tablename.lower(), columnname.lower()))
def renderConstraint(self, name, rule):
- return "CONSTRAINT %s %s," % (name, rule)
+ return " CONSTRAINT %s %s," % (name, rule)
def copyToTemporaryTable(self, tablename):
return 'CREATE TEMPORARY TABLE "TMP%s" AS SELECT * FROM %s;\n' % \
|
SVN: r4356 - in tcm2sql/trunk: . doc
Michael Howitz <mh(at)gocept.com> |
2006-10-18 14:13:01 |
[ FULL ]
|
Author: mac
Date: Wed Oct 18 14:12:54 2006
New Revision: 4356
Modified:
tcm2sql/trunk/CHANGELOG
tcm2sql/trunk/RenderDB.py
tcm2sql/trunk/doc/Example-1.ssd
tcm2sql/trunk/tcm2sql.py
Log:
implemented handling of bigserial like serial types + reniced help screen
Modified: tcm2sql/trunk/CHANGELOG
==============================================================================
--- tcm2sql/trunk/CHANGELOG (original)
+++ tcm2sql/trunk/CHANGELOG Wed Oct 18 14:12:54 2006
(at)(at) -1,10 +1,19 (at)(at)
-$Id: CHANGELOG,v 1.5 2005/03/31 11:31:49 zagy Exp $
+$Id$
+
+0.9.2 (2006-10-18)
+ - Restructured renderer classes to make it easier to write
+ renderers for other database managenemt systems.
+ - Better handling for serials and bigserials: Now they are always
+ written as integer with default + creation of sequence. (This
+ makes updating of tables possible which have serial columns.)
+ - Added commandline option --no_views to not generate views for the
tables.
+ - Made usage help a bit nicer.
0.9.1 (2005-03-31)
- Multi column foreign keys
0.9 (2003-09-13)
- - splitting database to several diagrams (see README for documentataion)
+ - splitting database to several diagrams (see README for documentation)
- requires Python 2.2
- complete rewrite of ssd file reader
- large changes on internal data structures
Modified: tcm2sql/trunk/RenderDB.py
==============================================================================
--- tcm2sql/trunk/RenderDB.py (original)
+++ tcm2sql/trunk/RenderDB.py Wed Oct 18 14:12:54 2006
(at)(at) -61,10 +61,26 (at)(at)
"""Render one attribute."""
return " %s %s," % (attr[0], attr[1])
- def renderSerialType(self, tablename, columnname):
- return ("INTEGER NOT NULL DEFAULT "
- "NEXTVAL('\"%s_%s_seq\"'::text)" %
- (tablename.lower(), columnname.lower()))
+ def renderSerialType(self, tablename, columnname, datatype):
+ datatype = self.convertType(datatype)
+ return ("%s NOT NULL DEFAULT "
+ "NEXTVAL('%s_%s_seq'::text)" %
+ (datatype, tablename.lower(), columnname.lower()))
+
+ def convertType(self, type):
+ "Convert the type to the correct value for the DBMS."
+ serial_type = self._serial_pattern.match(type)
+ if serial_type is None:
+ return type
+ serial_type = serial_type.groups()[0]
+ if serial_type == "serial":
+ serial_type = "INTEGER"
+ elif serial_type == "bigserial":
+ serial_type = "BIGINT"
+ else:
+ raise ValueError("Don't know how to convert %s." % serial_type)
+ return serial_type
+
def renderConstraint(self, name, rule):
return " CONSTRAINT %s %s," % (name, rule)
(at)(at) -90,10 +106,12 (at)(at)
return 'DROP VIEW "sv%s";\n' % tablename
def createSequence(self, tablename, columnname):
- return "CREATE SEQUENCE %s_%s_seq;\n" % (tablename, columnname)
+ return "CREATE SEQUENCE %s_%s_seq;\n" % (tablename.lower(),
+ columnname.lower())
def dropSequence(self, tablename, columnname):
- return "DROP SEQUENCE %s_%s_seq;\n" % (tablename, columnname)
+ return "DROP SEQUENCE %s_%s_seq;\n" % (tablename.lower(),
+ columnname.lower())
def renderRelation(self, rel, TABLES):
"""Create foreign key constraint."""
(at)(at) -174,13 +192,12 (at)(at)
# set serials to integer in logging tables
for i in range(0, len(table.attrlist)):
name, type = table.attrlist[i]
- if self._serial_pattern.match(type):
- table.attrlist[i] = (name, 'integer')
+ table.attrlist[i] = (name, self.convertType(type))
### The following methods are independent from DBMS. ###
- _serial_pattern = re.compile(r"^\s*serial\s*$")
+ _serial_pattern = re.compile(r"^\s*(serial|bigserial)\s*$")
def __init__(self, *cwd, **kw):
RenderBase.__init__(self, *cwd, **kw)
(at)(at) -310,8 +327,10 (at)(at)
# transforms Attributes with type 'serial'
attrs = []
for (name, type) in table.attrlist:
- if self._serial_pattern.match(type) is not None:
- type = self.renderSerialType(table.name, name)
+ serial_type = self._serial_pattern.match(type)
+ if serial_type is not None:
+ type = self.renderSerialType(table.name, name,
+ serial_type.groups()[0])
attrs.append((name, type))
# render Attributes
(at)(at) -376,7 +395,7 (at)(at)
self.fixup_logging_helper(self.old)
def _get_serials(self, tables):
- """Get the columns which are of type 'serial'.
+ """Get the columns which are of type 'serial' or 'bigserial'.
Returns list of tuples (tablename, columnname).
"""
Modified: tcm2sql/trunk/doc/Example-1.ssd
==============================================================================
--- tcm2sql/trunk/doc/Example-1.ssd (original)
+++ tcm2sql/trunk/doc/Example-1.ssd Wed Oct 18 14:12:54 2006
(at)(at) -56,7 +56,7 (at)(at)
{ Parent 0 }
{ Index "" }
{ Attributes 5 }
- { Attribute "#id: serial" }
+ { Attribute "#id: bigserial" }
{ Attribute "~Family_id: integer" }
{ Attribute "name: varchar not null" }
{ Attribute "firstname: varchar not null" }
Modified: tcm2sql/trunk/tcm2sql.py
==============================================================================
--- tcm2sql/trunk/tcm2sql.py (original)
+++ tcm2sql/trunk/tcm2sql.py Wed Oct 18 14:12:54 2006
(at)(at) -30,15 +30,15 (at)(at)
availableRenderers = ('Postgres', )
def usage():
- print """Usage: tcm2sql [options]
- -n <file> new SSD file [required]
- -o <file> old SSD file (enables DIFF)
- -r <renderer> select renderer [Postgres]
- -w <file> write to file [required]
- --logtables enable creation of logging tables
- --no_views disable creation of views for tables
- -h, --help this message
-"""
+ print """\
+Usage: tcm2sql -n <file> -w <file> [other_options]
+ -n <file> new SSD file [required]
+ -w <file> write to file [required]
+ -o <file> old SSD file (enables DIFF)
+ -r <renderer> select renderer [currently only Postgres, which is the
default]
+ --logtables enable creation of logging tables
+ --no_views disable creation of views for tables
+ -h, --help this message"""
oldState = None
oldStateFile = None
(at)(at) -89,13 +89,13 (at)(at)
print "Unknown Option %s" % (o,)
usage()
sys.exit()
-
-
+
+
if oldStateFile is not None:
oldState = SSDReader(oldStateFile)
oldState.build(__builtins__.optCreateLoggingTables)
-if newStateFile is None:
+if newStateFile is None or outFile is None:
usage()
sys.exit()
newState = SSDReader(newStateFile)
|
SVN: r4357 - tcm2sql/trunk
Michael Howitz <mh(at)gocept.com> |
2006-10-18 14:13:27 |
[ FULL ]
|
Author: mac
Date: Wed Oct 18 14:13:26 2006
New Revision: 4357
Modified:
tcm2sql/trunk/version.txt
Log:
releasing version 0.9.2
Modified: tcm2sql/trunk/version.txt
==============================================================================
--- tcm2sql/trunk/version.txt (original)
+++ tcm2sql/trunk/version.txt Wed Oct 18 14:13:26 2006
(at)(at) -1 +1 (at)(at)
-0.9.1
+0.9.2
|
SVN: r4358 - tcm2sql/tags/0.9.2
Michael Howitz <mh(at)gocept.com> |
2006-10-18 14:14:41 |
[ FULL ]
|
Author: mac
Date: Wed Oct 18 14:14:39 2006
New Revision: 4358
Added:
tcm2sql/tags/0.9.2/
- copied from r4357, tcm2sql/trunk/
Log:
Releasing 0.9.2
|
|