[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r7610 - in trunk/gnue-common: scripts src src/datasources src/dat
From: |
johannes |
Subject: |
[gnue] r7610 - in trunk/gnue-common: scripts src src/datasources src/datasources/drivers/Base src/datasources/drivers/DBSIG2 src/datasources/drivers/adodbapi src/datasources/drivers/appserver src/datasources/drivers/interbase src/datasources/drivers/interbase/interbase src/datasources/drivers/maxdb src/datasources/drivers/maxdb/maxdb src/datasources/drivers/mysql src/datasources/drivers/mysql/mysql src/datasources/drivers/oracle src/datasources/drivers/postgresql src/datasources/drivers/postgresql/Base src/datasources/drivers/sqlite src/datasources/drivers/sqlite/sqlite src/definitions |
Date: |
Fri, 17 Jun 2005 07:32:35 -0500 (CDT) |
Author: johannes
Date: 2005-06-17 07:32:33 -0500 (Fri, 17 Jun 2005)
New Revision: 7610
Removed:
trunk/gnue-common/src/datasources/drivers/Base/Schema/
trunk/gnue-common/src/datasources/drivers/DBSIG2/Schema/
trunk/gnue-common/src/datasources/drivers/adodbapi/Schema/
trunk/gnue-common/src/datasources/drivers/appserver/Schema/
trunk/gnue-common/src/datasources/drivers/interbase/Schema/
trunk/gnue-common/src/datasources/drivers/maxdb/Schema/
trunk/gnue-common/src/datasources/drivers/mysql/Schema/
trunk/gnue-common/src/datasources/drivers/oracle/Schema/
trunk/gnue-common/src/datasources/drivers/postgresql/Schema/
trunk/gnue-common/src/datasources/drivers/sqlite/Schema/
trunk/gnue-common/src/schema/
Modified:
trunk/gnue-common/scripts/gnue-schema
trunk/gnue-common/src/datasources/GDataSource.py
trunk/gnue-common/src/datasources/GSchema.py
trunk/gnue-common/src/datasources/drivers/Base/Behavior.py
trunk/gnue-common/src/datasources/drivers/Base/Connection.py
trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py
trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py
trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py
trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py
trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py
trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py
trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py
trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py
trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py
trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py
trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py
trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py
trunk/gnue-common/src/definitions/GObjects.py
trunk/gnue-common/src/definitions/GParserHelpers.py
Log:
Implemented writeSchema (), removed old Schema/Creation/*
Modified: trunk/gnue-common/scripts/gnue-schema
===================================================================
--- trunk/gnue-common/scripts/gnue-schema 2005-06-17 12:17:51 UTC (rev
7609)
+++ trunk/gnue-common/scripts/gnue-schema 2005-06-17 12:32:33 UTC (rev
7610)
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2001-2003 Free Software Foundation
+# Copyright 2001-2005 Free Software Foundation
#
# This file is part of GNU Enterprise.
#
@@ -20,12 +20,14 @@
# - Suite 330, Boston, MA 02111-1307, USA.
#
# $Id$
-
-import os, sys
-if hasattr(sys, 'frozen'):
- sys.path.append(os.path.abspath(os.path.dirname(sys.argv[0])))
-from gnue.common.schema.scripter.Scripter import Scripter
+import os
+import sys
+if hasattr (sys, 'frozen'):
+ sys.path.append (os.path.abspath (os.path.dirname (sys.argv[0])))
+
+from gnue.common.datasources.readgsd import gsdClient
+
if __name__ == "__main__":
- Scripter ().run ()
+ gsdClient ().run ()
Modified: trunk/gnue-common/src/datasources/GDataSource.py
===================================================================
--- trunk/gnue-common/src/datasources/GDataSource.py 2005-06-17 12:17:51 UTC
(rev 7609)
+++ trunk/gnue-common/src/datasources/GDataSource.py 2005-06-17 12:32:33 UTC
(rev 7610)
@@ -1068,13 +1068,7 @@
self._datasourceDictionary={}
self._toplevelParent = self._type
- def getIntrospector (self):
- return self._connection.behavior
- def getSchemaCreator (self):
- return self._connection.getSchemaCreator ()
-
-
# =============================================================================
# Load AppServer specific resources
# =============================================================================
Modified: trunk/gnue-common/src/datasources/GSchema.py
===================================================================
--- trunk/gnue-common/src/datasources/GSchema.py 2005-06-17 12:17:51 UTC
(rev 7609)
+++ trunk/gnue-common/src/datasources/GSchema.py 2005-06-17 12:32:33 UTC
(rev 7610)
@@ -21,11 +21,9 @@
#
# $Id$
-import sets
-import copy
-
-from gnue.common.definitions.GObjects import GObj
+from gnue.common.definitions.GObjects import GObj, GUndividedCollection
from gnue.common.definitions.GRootObj import GRootObj
+from gnue.common.definitions.GParserHelpers import GLeafNode
from gnue.common.formatting import GTypecast
from gnue.common.definitions import GParser
@@ -42,210 +40,13 @@
# Constructor
# ---------------------------------------------------------------------------
- def __init__ (self, parent, objType, leafNode = False, **kwargs):
+ def __init__ (self, parent, objType, **kwargs):
- global xmlElements
-
GObj.__init__ (self, parent, objType)
- self.isLeafNode = leafNode
+ self.buildObject (**kwargs)
- # All remaining keyword arguments are incorporated as own attributes.
- self.__dict__.update (kwargs)
- # Get the sequence of 'assignable' members
- if xmlElements is None:
- xmlElements = getXMLelements ()
- okey = objType [2:].lower ()
- if okey in xmlElements:
- self.MEMBERS = xmlElements [okey].get ('Attributes', {}).keys ()
- else:
- self.MEMBERS = []
-
-
- # ---------------------------------------------------------------------------
- # Assign a given set of attributes from another instance
- # ---------------------------------------------------------------------------
-
- def assign (self, source, recursive = False):
- """
- """
-
- if self.__class__ != source.__class__:
- raise AssignmentTypeError, (self, source)
-
- for item in self.MEMBERS:
- if hasattr (source, item):
- setattr (self, item, getattr (source, item))
-
- if recursive:
- self._children = []
-
- for child in source._children:
- new = child.__class__ (None)
- self.addChild (new)
- new.setParent (self)
-
- new.assign (child, recursive)
-
-
- def _setAction (self, obj, newAction):
- obj._action = newAction
-
-
- # ---------------------------------------------------------------------------
- #
- # ---------------------------------------------------------------------------
-
- def diff (self, goal, maxIdLength = None):
-
- result = None
-
- mine = {}
- others = {}
-
- # Build a mapping of our children
- for child in self._children:
- mine [child._id_ (maxIdLength)] = child
-
- # find the counterpart of this instance
- buddy = goal.findChildOfType (self._type, True, True)
-
- # If there is no such object, all items in self are 'old' then
- if buddy is None:
- pass
- else:
- for child in buddy._children:
- others [child._id_ (maxIdLength)] = child
-
- # Find out new and changed items
- for (key, item) in others.items ():
- childDiff = None
-
- if not key in mine:
- if item._children or item.isLeafNode:
- childDiff = item.__class__ (None)
- childDiff.assign (item, True)
- childDiff.walk (self._setAction, "add")
-
- else:
- # we need to find out wether the instances are changed then
- childDiff = mine [key].diff (item, maxIdLength)
- if childDiff is not None:
- childDiff._action = "change"
-
- if childDiff is not None:
- if result is None:
- result = self.__class__ (None)
- result.assign (self)
-
- result.addChild (childDiff)
- childDiff.setParent (result)
-
- # Finally find out all 'obsolete' ones
- for (key, item) in mine.items ():
- if not key in others:
- if result is None:
- result = self.__class__ (None)
- result.assign (self)
-
- child = item.__class__ (None)
- child.assign (item, True)
- child.walk (self._setAction, "remove")
-
- result.addChild (child)
- child.setParent (result)
-
- if result is not None:
- result._action = "change"
-
- return result
-
-
- # ---------------------------------------------------------------------------
- # Return a 'unique' and 'compareable' representation of an instance
- # ---------------------------------------------------------------------------
-
- def _id_ (self, maxIdLength = None):
-
- if hasattr (self, 'name'):
- result = self.name.lower ()
- if maxIdLength is not None:
- result = result [:maxIdLength]
- else:
- result = self._type
-
- return result
-
-
- # ---------------------------------------------------------------------------
- # Merge another object tree with this tree
- # ---------------------------------------------------------------------------
-
- def merge (self, other):
- """
- Incorporate all subtrees from the given object tree of this instances type.
- """
-
- # First find objects of the same type in the other tree
- candidates = other.findChildrenOfType (self._type, True, True)
-
- # We keep a mapping of all our children
- mine = {}
- for mc in self._children:
- mine [mc._id_ ()] = mc
-
- # Iterate over all elements in the other tree having the same type
- for item in candidates:
- # and observe all their children ...
- for otherChild in item._children:
- # ... wether we have to start a recursive merge ...
- if otherChild._id_ () in mine:
- mine [otherChild._id_ ()].merge (otherChild)
- # ... or we can copy the subtree
- else:
- new = otherChild.__class__ (self)
- new.assign (otherChild, True)
-
-
# =============================================================================
-#
-# =============================================================================
-
-class GSImmutableCollection (GSObject):
-
- # ---------------------------------------------------------------------------
- #
- # ---------------------------------------------------------------------------
-
- def diff (self, goal, maxIdLength = None):
-
- result = GSObject.diff (self, goal, maxIdLength)
-
- if result is not None:
- for item in result._children [:]:
- # We cannot change a child of an immutable collection directly, instead
- # we remove the original and add the changed one.
- if item._action == 'change':
- result._children.remove (item)
-
- for old in self._children:
- if old._id_ (maxIdLength) == item._id_ (maxIdLength):
- add = old.__class__ (result)
- add.assign (old, True)
- add.walk (self._setAction, "remove")
- break
-
- for new in goal._children:
- if new._id_ (maxIdLength) == item._id_ (maxIdLength):
- add = new.__class__ (result)
- add.assign (new, True)
- add.walk (self._setAction, "add")
- break
-
- return result
-
-
-# =============================================================================
# This class implements the object tree for schema definitions
# =============================================================================
@@ -256,6 +57,7 @@
GRootObj.__init__(self, 'schema', getXMLelements, __name__)
GSObject.__init__(self, parent, 'GSSchema')
+# =============================================================================
class GSTables (GSObject):
def __init__(self, parent, **params):
@@ -266,6 +68,8 @@
return "%s" % self.type
+# =============================================================================
+
class GSTable (GSObject):
def __init__(self, parent, **params):
GSObject.__init__(self, parent, 'GSTable', **params)
@@ -277,225 +81,132 @@
else:
yield field
+# =============================================================================
+
class GSFields (GSObject):
def __init__(self, parent, **params):
GSObject.__init__(self, parent, 'GSFields', **params)
+# =============================================================================
-class GSField (GSObject):
+class GSField (GSObject, GLeafNode):
def __init__(self, parent, **params):
- GSObject.__init__(self, parent, 'GSField', True, **params)
+ GSObject.__init__(self, parent, 'GSField', **params)
-class GSPrimaryKey (GSImmutableCollection):
- def __init__ (self, parent, **params):
- GSImmutableCollection.__init__(self, parent, 'GSPrimaryKey', **params)
+# =============================================================================
-class GSPKField (GSObject):
+class GSPrimaryKey (GUndividedCollection):
def __init__ (self, parent, **params):
- GSObject.__init__(self, parent, 'GSPKField', True, **params)
+ GUndividedCollection.__init__(self, parent, 'GSPrimaryKey', **params)
-class GSConstraints (GSImmutableCollection):
- def __init__ (self, parent, **params):
- GSImmutableCollection.__init__(self, parent, 'GSConstraints', **params)
-class GSConstraint(GSObject):
- def __init__ (self, parent, **params):
- GSObject.__init__ (self, parent, 'GSConstraint', **params)
- self.__tables = None
+# =============================================================================
-class GSConstraintField (GSObject):
+class GSPKField (GSObject, GLeafNode):
def __init__ (self, parent, **params):
- GSObject.__init__(self, parent, 'GSConstraintField', True, **params)
+ GSObject.__init__(self, parent, 'GSPKField', **params)
-class GSConstraintRef (GSObject):
- def __init__ (self, parent, **params):
- GSObject.__init__(self, parent, 'GSConstraintRef', True, **params)
-class GSIndexes (GSImmutableCollection):
- def __init__ (self, parent, **params):
- GSImmutableCollection.__init__(self, parent, 'GSIndexes', **params)
+# =============================================================================
-class GSIndex (GSObject):
+class GSConstraints (GUndividedCollection):
def __init__ (self, parent, **params):
- GSObject.__init__(self, parent, 'GSIndex', **params)
+ GUndividedCollection.__init__(self, parent, 'GSConstraints', **params)
-class GSIndexField (GSObject):
- def __init__ (self, parent, **params):
- GSObject.__init__(self, parent, 'GSIndexField', True, **params)
+# =============================================================================
-class GSData(GSObject):
- def __init__(self, parent):
- GSObject.__init__(self, parent, 'GSData')
+class GSForeignKey (GSObject):
+ def __init__ (self, parent, **params):
+ GSObject.__init__ (self, parent, 'GSForeignKey', **params)
-class GSTableData(GSObject):
- def __init__(self, parent):
- GSObject.__init__(self, parent, 'GSTableData')
-class GSRows(GSObject):
- def __init__(self, parent):
- GSObject.__init__(self, parent, 'GSRows')
-
-class GSRow(GSObject):
- def __init__(self, parent):
- GSObject.__init__(self, parent, 'GSRow')
-
# =============================================================================
-# Field-Values
-# =============================================================================
-class GSValue(GSObject):
- """
- This class implements a single data value of a row-collection. On
- Phase-I-init the values' datatype is determined - either by a matching
- column-definition, or by a direct type-argument - and a native python object
- is created for it.
- """
- def __init__(self, parent):
- GSObject.__init__(self, parent, 'GSValue', True)
- self.dataType = None
- self.length = None
- self.precision = None
- self.value = None
+class GSFKField (GSObject, GLeafNode):
+ def __init__ (self, parent, **params):
+ GSObject.__init__(self, parent, 'GSFKField', **params)
- self._inits.append (self._validate)
+# =============================================================================
- def _validate (self):
- if hasattr (self, "field"):
- column = self._findColumn (self.field)
- else:
- column = self._findColumn (self._getIndex ())
+class GSIndexes (GUndividedCollection):
+ def __init__ (self, parent, **params):
+ GUndividedCollection.__init__(self, parent, 'GSIndexes', **params)
- try:
- self.value = valueToNative (self, column)
- except Exception, message:
- self.value = None
+# =============================================================================
- print message
- setErrorFlag (self)
+class GSIndex (GSObject):
+ def __init__ (self, parent, **params):
+ GSObject.__init__(self, parent, 'GSIndex', **params)
- # ---------------------------------------------------------------------------
- # Find a column definition either by it's index or by it's fieldname
- # ---------------------------------------------------------------------------
+# =============================================================================
- def _findColumn (self, fieldSpec):
- """
- This function searches for a given field in a GSTableData's column
- definition. If @fieldSpec is an integer this number will be used as index
- to the column-definition collection. Ohterwise @fieldSpec is treated as the
- field name of the column to be returned.
- """
- tableData = self.findParentOfType ('GSTableData')
- if tableData is not None:
- colDefs = tableData.findChildOfType ('GSDefinition')
- if colDefs is not None:
- return colDefs.getColumn (fieldSpec)
+class GSIndexField (GSObject, GLeafNode):
+ def __init__ (self, parent, **params):
+ GSObject.__init__(self, parent, 'GSIndexField', **params)
- return None
- # ---------------------------------------------------------------------------
- # get the index of an instance in it's parent's child-collection
- # ---------------------------------------------------------------------------
+# =============================================================================
- def _getIndex (self):
- """
- This function get's the objects index in it's parents child-collection
- """
- parent = self.getParent ()
- if parent is not None:
- for index in range (0, len (parent._children)):
- if parent._children [index] == self:
- return index
+class GSData (GSObject):
+ def __init__ (self, parent, **params):
+ GSObject.__init__ (self, parent, 'GSData', **params)
- raise errors.ApplicationError, \
- u_("GSD-Error: can't find myself in the XML tree?!")
+# =============================================================================
+class GSTableData (GSObject):
+ def __init__ (self, parent, **params):
+ GSObject.__init__ (self, parent, 'GSTableData', **params)
-class GSDescription(GSObject):
- def __init__(self, parent):
- GSObject.__init__(self, parent, 'GSDescription', True)
-
-
# =============================================================================
-# Column definitions
-# =============================================================================
-class GSDefinition (GSObject):
- """
- GSDefinition holds a collection of column definition instances. In
- Phase-I-init a dictionary with all columns is created as well as a sequence
- of columns (for index-based access).
- """
- def __init__ (self, parent):
- GSObject.__init__ (self, parent, "GSDefinition")
- self.columns = {}
- self.collist = []
- self._inits.append (self.__buildColumnDict)
+class GSRows (GSObject):
+ def __init__ (self, parent, **params):
+ GSObject.__init__ (self, parent, 'GSRows', **params)
- def __buildColumnDict (self):
- self.collist = self.findChildrenOfType ('GSColumn')
- self.columns = {}
+ # ---------------------------------------------------------------------------
+ # Merge a rows collection with another one
+ # ---------------------------------------------------------------------------
- for col in self.collist:
- self.columns [col.field] = col
-
-
- def getColumn (self, fieldSpec):
+ def merge (self, other, maxIdLength = None):
"""
- If @fieldSpec is an integer type '@fieldSpec' is treated as an index to the
- columns-sequence, otherwise @fieldSpec is used as key into the
- columns-dictionary.
+ Merge all rows of another rows collection into this one. Since we cannot
+ determine a primary key here we have no chance to detect duplicate rows.
+ That's why we just copy all of the others' rows.
"""
- if isinstance (fieldSpec, types.IntType) and fieldSpec < len
(self.collist):
- return self.collist [fieldSpec]
- elif self.columns.has_key (fieldSpec):
- return self.columns [fieldSpec]
+ for row in other.findChildrenOfType ('GSRow', False, True):
+ new = GSRow (self)
+ new.assign (row, True)
- return None
-
# =============================================================================
-# Column definitions
-# =============================================================================
-class GSColumn (GSObject):
- """
- This class implements a column definition. Phase-I-init verifies the datatype
- of the column definition and set's the properties 'typename', 'length' and
- 'precision'.
- """
- def __init__ (self, parent):
- GSObject.__init__ (self, parent, "GSColumn", True)
- self.typename = None
- self.length = None
- self.precision = None
- self._inits.append (self._validate)
+class GSRow (GSObject):
+ def __init__ (self, parent, **params):
+ GSObject.__init__ (self, parent, 'GSRow', **params)
- def _validate (self):
- (self.typename, self.length, self.precision) = verifyDataType (self)
+# =============================================================================
-# -----------------------------------------------------------------------------
-# recursively set an error flag in a object hierarchy
-# -----------------------------------------------------------------------------
+class GSValue (GSObject, GLeafNode):
+ def __init__ (self, parent, **params):
+ GSObject.__init__ (self, parent, 'GSValue', **params)
-def setErrorFlag (aObject):
- """
- This function sets the property 'foundErrors' in an object and all its
- parents.
- """
- if aObject is not None:
- aObject.foundErrors = True
- setErrorFlag (aObject.getParent ())
+# =============================================================================
+class GSDescription (GSObject, GLeafNode):
+ def __init__ (self, parent, **params):
+ GSObject.__init__ (self, parent, 'GSDescription', **params)
+
+
# =============================================================================
# load an XML object tree from a given stream and return it's root object
# =============================================================================
@@ -615,7 +326,7 @@
'name': {
'Required': 1,
'Typecast': GTypecast.name } },
- 'ParentTags': ('table',) },
+ 'ParentTags': ('table', 'tabledata') },
'pkfield': {
'BaseClass': GSPKField,
@@ -630,34 +341,26 @@
'SingleInstance': 1,
'ParentTags': ('table',) },
- 'constraint': {
- 'BaseClass': GSConstraint,
+ 'foreignkey': {
+ 'BaseClass': GSForeignKey,
'Attributes': {
'name': {
'Required': 1,
'Typecast': GTypecast.name },
- 'type': {
+ 'references': {
'Typecast': GTypecast.name } },
'ParentTags': ('constraints',) },
- 'constraintfield': {
- 'BaseClass': GSConstraintField,
+ 'fkfield': {
+ 'BaseClass': GSFKField,
'Attributes': {
'name': {
'Required': 1,
- 'Typecast': GTypecast.name } },
- 'ParentTags': ('constraint',) },
-
- 'constraintref': {
- 'BaseClass': GSConstraintRef,
- 'Attributes': {
- 'name': {
- 'Required': 1,
'Typecast': GTypecast.name },
- 'table': {
+ 'references': {
'Required': 1,
'Typecast': GTypecast.name } },
- 'ParentTags': ('constraint',) },
+ 'ParentTags': ('foreignkey',) },
'indexes': {
'BaseClass': GSIndexes,
@@ -699,26 +402,6 @@
'Typecast': GTypecast.name } },
'ParentTags': ('data',) },
- 'definition': {
- 'BaseClass': GSDefinition,
- 'SingleInstance': True,
- 'ParentTags': ('tabledata',) },
-
- 'column': {
- 'BaseClass': GSColumn,
- 'Attributes': {
- 'field': {
- 'Required': True,
- 'Typecast': GTypecast.name },
- 'type': {
- 'Required': True,
- 'Typecast': GTypecast.name },
- 'key': {
- 'Typecast': GTypecast.boolean,
- 'Default' : False},
- },
- 'ParentTags': ('definition',)},
-
'rows': {
'BaseClass': GSRows,
'SingleInstance': 1,
@@ -738,10 +421,6 @@
'Required': 0,
'Typecast': GTypecast.name,
'Default': 'text' },
- 'key': {
- 'Required': 0,
- 'Typecast': GTypecast.boolean,
- 'Default' : 0}
},
'ParentTags': ('row',),
'MixedContent': 1,
@@ -773,5 +452,3 @@
GParser.xmlHandler.__init__(self)
self.xmlElements = getXMLelements ()
-
-
Modified: trunk/gnue-common/src/datasources/drivers/Base/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/Behavior.py 2005-06-17
12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/Base/Behavior.py 2005-06-17
12:32:33 UTC (rev 7610)
@@ -83,6 +83,9 @@
"""
result = GSchema.GSSchema ()
+ author = self.__module__.replace ('gnue.common.datasources.drivers.', '')
+ title = u_("DB-Export of %s") % self.__connection.name
+ result.buildAndInitObject (**{'author': author, 'title': title})
self._readSchema_ (result)
@@ -93,26 +96,28 @@
# Update the current connection's schema with the given schema
# ---------------------------------------------------------------------------
- def writeSchema (self, schema):
+ def writeSchema (self, schema, simulation = False):
"""
Generate a command sequence to integrate the given schema tree into the
connection's current schema.
@param schema: GSchema object tree to be integrated in the connection's
current schema
+ @param simulation: if True, do not create the schema. Instead only the code
+ should be generated.
@return: sequence of statements to be executed on the connection in order
to create/update the schema
"""
self._current = self.readSchema ()
- self._diff = current.diff (schema, self._maxIdLength)
+ self._diff = self._current.diff (schema, self._maxIdLength)
self._new = schema
self._lookups = self.__getLookups (self._current)
self._elements = {}
- return self._writeSchema_ (self._current, self._new, self._diff)
+ return self._writeSchema_ (self._current, self._new, self._diff,
simulation)
# ---------------------------------------------------------------------------
@@ -194,7 +199,7 @@
# Create code for merging the backend's schema to fit the given tree
# ---------------------------------------------------------------------------
- def _writeSchema_ (self, current, new, diff):
+ def _writeSchema_ (self, current, new, diff, simulation = False):
raise NotImplementedError
@@ -302,7 +307,7 @@
def __getLookups (self, schema):
result = {}.fromkeys (["CONSTRAINT_%s" % c.name for c in \
- schema.findChildrenOfType ('GSConstraint', False,
True)])
+ schema.findChildrenOfType ('GSForeignKey', False, True)])
result.update ({}.fromkeys (["INDEX_%s" % i.name for i in \
- schema.findChildrenOfType ('GSIndex', False, True)]))
+ schema.findChildrenOfType ('GSIndex', False, True)]))
return result
Modified: trunk/gnue-common/src/datasources/drivers/Base/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/Connection.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/Base/Connection.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -22,7 +22,6 @@
# $Id$
import copy
-import string
from gnue.common.apps import GDebug
@@ -72,7 +71,7 @@
self.name = name
self.parameters = parameters
self.__pending = False
- self.behavior = self._getBehavior ()
+ self.behavior = self._getBehavior_ ()
# ---------------------------------------------------------------------------
@@ -313,169 +312,6 @@
# ---------------------------------------------------------------------------
- # Create a new instance of the associated schema creator
- # ---------------------------------------------------------------------------
-
- def getSchemaCreator (self):
- """
- Create a new instance of the schema creator associated with this driver or
- None if no creator is available.
- """
-
- if self.defaultCreator:
- return self.defaultCreator (self)
- else:
- return None
-
-
- # ---------------------------------------------------------------------------
- # update the schema definition
- # ---------------------------------------------------------------------------
-
- def updateSchema (self, definition, codeOnly = False):
- """
- Modify the database schema according to the given definition.
-
- @param definition: Sequence of table definitions.
- See L{Schema.Creation.Creation}.
- @param codeOnly: If True, only the code will be generated to modify the
- schema, no actions take place.
- @return: a tuple of three sequences (prologue, body, epilogue) holding the
- code to perform all schema modifications needed. These sequences should
- be executed in this order to successfully create the schema.
- """
-
- result = ([], [], [])
-
- schemaCreator = self.getSchemaCreator ()
-
- if schemaCreator is None:
- return result
-
- try:
- current = self.behavior.readSchema ()
- workingSet = copy.copy (definition)
- constraintSet = {}
-
- # before any actions are performed, validate the given definitions
- for table in definition:
- schemaCreator.validate (table)
-
- # in a first run we remove all constraint definitions from the tables, so
- # we can add or alter all tables without having troubles with order of
- # occurence.
- for table in workingSet:
- # Do we have already a table with that name?
- res = None
- for item in current.findChildrenOfType ('GSTable', False, True):
- if item.name.lower () == table ['name'].lower ():
- res = item
- break
-
- if res is not None:
- method = schemaCreator.modifyTable
- # Please note: we keep existingFields sequence in all lowercase
- existingFields = [f.name.lower () for f in \
- res.findChildrenOfType ('GSField', False, True)]
-
- # keep only new fields
- keep = []
- for field in table ['fields']:
- if not field ['name'].lower () in existingFields:
- keep.append (field)
-
- table ['fields'] = keep
-
- # on updates of a table we cannot use a primary key
- if table.has_key ('primarykey'):
- del table ['primarykey']
-
- # keep modified or new indices only
- if table.has_key ('indices'):
- keep = []
-
- # if driver supports index-introspection we'll use it
- if res.findChildOfType ('GSIndexes') is not None:
- for index in table ['indices']:
- oldIndex = None
- for item in res.findChildrenOfType ('GSIndex', False, True):
- if item.name.lower () == index ['name'].lower ():
- oldIndex = value
-
- if oldIndex is None:
- keep.append (index)
- else:
- old = [f.lower () for f in \
- oldIndex.findChildrenOfType ('GSIndexField', False,
True)]
- new = [f.lower () for f in index ['fields']]
-
- if oldIndex.unique != index ['unique'] or old != new:
- # make sure the backend has a possibility to remove the old
- # index before changing it
- if not table.has_key ('old_indices'):
- table ['old_indices'] = []
- table ['old_indices'].append (index ['name'])
-
- keep.append (index)
- else:
- # if no index-introspection available we only keep an index, if
it
- # has new fields
- for index in table ['indices']:
- for field in index ['fields']:
- if not field.lower () in existingFields:
- # make sure the backend has a possibility to remove the old
- # index before changing it
- if not table.has_key ('old_indices'):
- table ['old_indices'] = []
- table ['old_indices'].append (index ['name'])
-
- keep.append (index)
- break
-
- table ['indices'] = keep
-
- # we create a constraint on a table update only if it contains new
- # fields
- if table.has_key ('constraints'):
- keep = []
-
- for constraint in table ['constraints']:
- for field in constraint ['fields']:
- if not field.lower () in existingFields:
- keep.append (constraint)
- break
-
- table ['constraints'] = keep
-
- else:
- method = schemaCreator.createTable
-
- if table.has_key ('constraints'):
- constraintSet [table ['name']] = {'name': table ['name'],
- 'constraints': table ['constraints']}
- del table ['constraints']
-
- # before we execute the planned action, have a look if there's still
- # work to be done
- perform = table.has_key ('fields') and len (table ['fields'])
- perform = perform or table.has_key ('primarykey')
- perform = perform or (table.has_key ('indices') and \
- len (table ['indices']))
-
- if perform:
- schemaCreator.mergeTuple (result, method (table, codeOnly))
-
- # on the second run we process all constraints
- for table in constraintSet.values ():
- schemaCreator.mergeTuple (result,
- schemaCreator.createTable (table, codeOnly))
- return result
-
- finally:
- schemaCreator.close ()
-
-
- # ---------------------------------------------------------------------------
# Return the current schema information of the connection's backend
# ---------------------------------------------------------------------------
@@ -497,23 +333,24 @@
# Write a given schema to the connection's backend
# ---------------------------------------------------------------------------
- def writeSchema (self, schema, codeOnly = False):
+ def writeSchema (self, schema, simulate = False):
"""
Update the connection's backend database schema with the given schema
object tree.
@param schema: GSchema object tree defining the schema to be integrated
- @param codeOnly: if True, create only the command sequence. No integration
+ @param simulate: if True, create only the command sequence. No integration
takes place.
@return: command sequence which could be used to integrate the given schema
"""
+ commands = []
+
if self.behavior is not None:
- commands = self.behavior.writeSchema (schema)
+ commands = self.behavior.writeSchema (schema, simulate)
- else:
- return []
+ return commands
# ---------------------------------------------------------------------------
@@ -712,7 +549,7 @@
# ---------------------------------------------------------------------------
- def _getBehavior (self):
+ def _getBehavior_ (self):
"""
Create an apropriate behavior instance. If the connection defines a
'_behavior' attribute this class will be instanciated. If the connection's
Modified: trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/DBSIG2/Behavior.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -65,14 +65,17 @@
# Generate a code sequence to match the requested schema
# ---------------------------------------------------------------------------
- def _writeSchema_ (self, current, new, diff):
+ def _writeSchema_ (self, current, new, diff, simulation = False):
"""
- Generate a command sequence to integrate the given schema tree into the
- connection's current schema.
+ Integrate the given schema into the current connection's schema and return
+ the commands used to achive this. Optionally a simulation for the
+ integration is possible. In that case no real change will take place in the
+ backend.
@param current: GSchema tree with the current schema at the backend
@param new: GSchema tree with the schema to be achieved
@param diff: GSchema tree with the differences between current and new
+ @param simulation: if True, only create the command sequence
@return: sequence of commands to be executed for changing the current
schema into the new one
@@ -89,9 +92,17 @@
if table._action in ['add', 'change']:
self.mergeTriple (result, self._createTable_ (table))
- return prolog + main + epilog
+ code = prolog + main + epilog
+ if not simulation:
+ for command in code:
+ self.__connection.sql0 (command)
+ self.__connection.commit ()
+
+ return code
+
+
# ---------------------------------------------------------------------------
# Create the command sequence for table creation or modification
# ---------------------------------------------------------------------------
@@ -113,7 +124,7 @@
return result
# Do we have some constraints or indices to be dropped ?
- for constraint in table.findChildrenOfType ('GSConstraint', False, True):
+ for constraint in table.findChildrenOfType ('GSForeignKey', False, True):
if constraint._action == "remove":
csKey = "CONSTRAINT_%s" % constraint.name
if csKey in self._lookups:
@@ -166,7 +177,7 @@
self.mergeTriple (result, self._createIndex_ (index))
# build all constraints
- for constraint in table.findChildrenOfType ('GSConstraint', False, True):
+ for constraint in table.findChildrenOfType ('GSForeignKey', False, True):
if constraint._action == 'add':
self.mergeTriple (result, self._createConstraint_ (constraint))
@@ -370,7 +381,7 @@
epilogue, the order of processing related tables does not matter, since all
new tables are created in the body-part of the code-triples.
- @param constraint: GSConstraint instance to be processed
+ @param constraint: GSForeignKey instance to be processed
@return: code triple with the command sequences
"""
@@ -388,13 +399,13 @@
elements [csKey] = None
csName = self._getSafeName_ (constraint.name, "CONSTRAINT")
- fields = constraint.findChildrenOfType ('GSConstraintField', False, True)
- rfields = constraint.findChildrenOfType ('GSConstraintRef', False, True)
+ rfName = self.shortenName (constraint.references)
+ fields = constraint.findChildrenOfType ('GSFKField', False, True)
code = u"ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) " \
"REFERENCES %s (%s)" \
% (table.name, csName, ", ".join ([f.name for f in fields]),
- rfields [0].table, ", ".join ([r.name for r in rfields]))
+ rfName, ", ".join ([f.references for f in fields]))
post.append (code)
@@ -409,11 +420,12 @@
"""
Create a command sequence for dropping the given constraint.
- @param constraint: GSConstraint instance to be dropped
+ @param constraint: GSForeignKey instance to be dropped
@return: command sequence
"""
- return [u"DROP CONSTRAINT %s" % constraint.name]
+ table = constraint.findParentOfType ('GSTable').name
+ return [u"ALTER TABLE %s DROP CONSTRAINT %s" % (table, constraint.name)]
# ---------------------------------------------------------------------------
Modified: trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/appserver/Behavior.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -118,13 +118,12 @@
if '_' in field.nativetype:
master = table.findChildOfType ('GSConstraints') or \
GSchema.GSConstraints (table)
- constraint = GSchema.GSConstraint (master,
+ constraint = GSchema.GSForeignKey (master,
name = "fk_%s_%s" % (table.name, field.nativetype),
- type = 'foreignkey')
+ references = field.nativetype)
- GSchema.GSConstraintField (constraint, name = field.name)
- GSchema.GSConstraintRef (constraint, name = u"gnue_id",
- table = field.nativetype)
+ GSchema.GSFKField (constraint, name = field.name,
+ references = u"gnue_id")
# ---------------------------------------------------------------------------
Modified: trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/interbase/Behavior.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -50,7 +50,7 @@
_alterMultiple = False
_maxVarchar = 10921
_numbers = [[(4, 'SMALLINT'), (9, 'INTEGER')], "NUMERIC(%s)",
- "NUMERIC (%(length)s,%(scale)s"]
+ "NUMERIC (%(length)s,%(scale)s)"]
# ---------------------------------------------------------------------------
@@ -269,7 +269,7 @@
else:
cons = table.findChildOfType ('GSConstraints') or \
GSchema.GSConstraints (table)
- item = GSchema.GSConstraint (cons, name = name, type = 'foreignkey')
+ item = GSchema.GSForeignKey (cons, name = name)
result ["%s.%s" % (tname, index)] = item
@@ -332,19 +332,15 @@
for field in fields [iname]:
GSchema.GSPKField (constraint, name = field)
else:
- for field in fields [iname]:
- GSchema.GSConstraintField (constraint, name = field)
+ for (field, reffield) in zip (fields [iname], fields [fkey]):
+ GSchema.GSFKField (constraint, name = field,
+ references = reffield)
+ update.setdefault (fkey, []).append (constraint)
- for field in fields [fkey]:
- item = GSchema.GSConstraintRef (constraint, name = field)
+ for (fkey, constraints) in update.items ():
+ for item in constraints:
+ item.references = relmap [fkey]
- update.setdefault (fkey, []).append (item)
-
- # Finally make sure all constraint reference fields pointing to a table
- for (fkey, crefs) in update.items ():
- for item in crefs:
- item.table = relmap [fkey]
-
finally:
cursor.close ()
Modified:
trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/interbase/interbase/Connection.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
__all__ = ['Connection']
from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.interbase.Schema.Creation.Creation import
Creation
from gnue.common.datasources.drivers.interbase import Behavior
@@ -38,11 +37,10 @@
"""
_drivername = 'kinterbasdb'
+ _behavior = Behavior.Behavior
_broken_rowcount = True
- defaultCreator = Creation
- _behavior = Behavior.Behavior
# ---------------------------------------------------------------------------
Modified: trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py 2005-06-17
12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/maxdb/Behavior.py 2005-06-17
12:32:33 UTC (rev 7610)
@@ -320,16 +320,16 @@
master = table.findChildOfType ('GSConstraints') or \
GSchema.GSConstraints (table)
cs = None
- for item in master.findChildrenOfType ('GSConstraint', False, True):
+ for item in master.findChildrenOfType ('GSForeignKey', False, True):
if item.name == fkname:
cs = item
break
if cs is None:
- cs = GSchema.GSConstraint (master, name = fkname, type =
'foreignkey')
+ cs = GSchema.GSForeignKey (master, name = fkname,
+ references = reftable)
- GSchema.GSConstraintField (cs, name = cname)
- GSchema.GSConstraintRef (cs, name = refcol, table = reftable)
+ GSchema.GSFKField (cs, name = cname, references = refcol)
finally:
cursor.close ()
Modified: trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/maxdb/maxdb/Connection.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
__all__ = ['Connection']
from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.maxdb.Schema.Creation.Creation import
Creation
from gnue.common.datasources.drivers.maxdb import Behavior
@@ -38,11 +37,10 @@
"""
_drivername = 'sapdb.dbapi'
+ _behavior = Behavior.Behavior
_named_as_sequence = True
- _behavior = Behavior.Behavior
- defaultCreator = Creation
# ---------------------------------------------------------------------------
Modified: trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/mysql/mysql/Connection.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
__all__ = ['Connection']
from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.mysql.Schema.Creation.Creation import
Creation
from gnue.common.datasources.drivers.mysql import Behavior
@@ -38,13 +37,12 @@
"""
_drivername = 'MySQLdb'
+ _behavior = Behavior.Behavior
+
_boolean_true = 1
_boolean_false = 0
- defaultCreator = Creation
- _behavior = Behavior.Behavior
-
# ---------------------------------------------------------------------------
# Get connection parameters
# ---------------------------------------------------------------------------
Modified: trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/oracle/Behavior.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -44,8 +44,23 @@
'all_view' : {'type': 'allview', 'name': _('System Views')},
'all_synonym' : {'type': 'allsynonym', 'name': _('System Synonyms')}}
+ _pkPrecision = 10
+ _maxIdLength = 31
+ _alterMultiple = False
+ _numbers = [[], "number (%s)", "number (%(length)s,%(scale)s)"]
+
# ---------------------------------------------------------------------------
+ # Constructor
+ # ---------------------------------------------------------------------------
+
+ def __init__ (self, *args, **kwargs):
+
+ DBSIG2.Behavior.__init__ (self, *args, **kwargs)
+ self._type2native.update ({'datetime': 'date', 'time': 'date'})
+
+
+ # ---------------------------------------------------------------------------
# Read the current connection's schema
# ---------------------------------------------------------------------------
@@ -154,3 +169,113 @@
finally:
cursor.close ()
+
+
+ # ---------------------------------------------------------------------------
+ # Create a new database
+ # ---------------------------------------------------------------------------
+
+ def createDatabase (self):
+ """
+ There's no support for creating databases atm, so a NotImplementedError
+ will be raised.
+ """
+
+ raise NotImplementedError
+
+
+ # ---------------------------------------------------------------------------
+ # Handle sepcial defaults
+ # ---------------------------------------------------------------------------
+
+ def _defaultwith_ (self, code, field):
+ """
+ Creates a sequence for 'serials' and set the default for 'timestamps' to
+ 'now ()'
+
+ @param code: code-triple to get the result
+ @param field: GSField instance of the field having the default
+ """
+
+ tablename = field.findParentOfType ('GSTable').name
+ if field.defaultwith == 'serial':
+ seq = self._getSequenceName_ (field)
+ code [0].append (u"CREATE SEQUENCE %s MAXVALUE %s NOCYCLE" \
+ % (seq, "9" * self._pkPrecision))
+
+ body = u"IF :new.%(field)s IS NULL THEN" \
+ " SELECT %(seq)s.nextval INTO :new.%(field)s FROM dual;" \
+ "END IF;" \
+ % {'field': field.name, 'seq': seq}
+
+ self.__addTrigger (tablename, field.name, code, body)
+
+
+ elif field.defaultwith == 'timestamp':
+ if field.type == 'date':
+ sysdate = "TRUNC (sysdate)"
+ else:
+ sysdate = "sysdate"
+
+ body = u"IF :new.%(field)s IS NULL THEN" \
+ " :new.%(field)s := %(date)s;" \
+ "END IF;" \
+ % {'field': field.name,
+ 'date' : sysdate}
+
+ self.__addTrigger (tablename, field.name, code, body)
+
+
+ # ---------------------------------------------------------------------------
+ # Create a trigger code and add it to the epilogue of the given code
+ # ---------------------------------------------------------------------------
+
+ def __addTrigger (self, tablename, fieldname, code, body):
+
+ code [2].append (u"CREATE OR REPLACE TRIGGER t__%(table)s_%(field)s_pre"
+ " BEFORE INSERT ON %(table)s"
+ " FOR EACH ROW WHEN (new.%(field)s IS NULL)"
+ " BEGIN %(body)s END; /"
+ % {'table': tablename,
+ 'field': fieldname,
+ 'body': body})
+
+
+ # ---------------------------------------------------------------------------
+ # String becomes varchar2
+ # ---------------------------------------------------------------------------
+
+ def string (self, field):
+ """
+ Return the native type for a string-field.
+
+ @param field: GSField instance to get a native type for
+ @return: string with the native datatype
+ """
+
+ length = hasattr (field, 'length') and field.length or 99999
+ if length <= 2000:
+ return "varchar2 (%s) % length"
+ else:
+ return "blob"
+
+
+ # ---------------------------------------------------------------------------
+ # There's no native boolean type
+ # ---------------------------------------------------------------------------
+
+ def boolean (self, field):
+ """
+ Return a native data type for a boolean
+
+ @param field: GSField instance to get a native type for
+ @return: string with the native datatype
+ """
+
+ nullable = hasattr (field, 'nullable') and field.nullable or True
+
+ if nullable:
+ return "number (1) CHECK (%(field)s IS NULL OR %(field)s IN (0,1))" \
+ % {'field': field.name}
+ else:
+ return "number (1) CHECK (%s IN (0,1))" % field.name
Modified:
trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/postgresql/Base/Connection.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,8 +24,6 @@
__all__ = ['Connection']
from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.postgresql.Schema.Creation.Creation
import Creation
-
from gnue.common.datasources.drivers.postgresql import Behavior
@@ -38,8 +36,6 @@
Generic Connection class for PostgreSQL databases.
"""
- defaultCreator = Creation
-
_rowidField = 'oid'
_behavior = Behavior.Behavior
Modified: trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/postgresql/Behavior.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -39,7 +39,7 @@
_maxIdLength = 31
_alterMultiple = False
_numbers = [[(4, 'smallint'), (9, 'integer'), (18, 'bigint')],
- "numeric (%s,0)", "numberic (%(length)s,%(scale)s)"]
+ "numeric (%s,0)", "numeric (%(length)s,%(scale)s)"]
# ---------------------------------------------------------------------------
@@ -137,7 +137,7 @@
fields = self.__readFields (tables)
self.__readDefaults (fields)
self.__readKeys (tables)
- self.__readConstraints (tables)
+ self.__readConstraints (tables, fields)
# ---------------------------------------------------------------------------
@@ -336,7 +336,7 @@
# Read all constraints
# ---------------------------------------------------------------------------
- def __readConstraints (self, tables):
+ def __readConstraints (self, tables, fields):
cmd = u"SELECT conname, conrelid, confrelid, conkey, confkey " \
"FROM pg_constraint WHERE contype = 'f'"
@@ -344,7 +344,7 @@
cursor = self.__connection.makecursor (cmd)
try:
for (name, relid, fkrel, key, fkey) in cursor.fetchall ():
- table = tables.get (relid)
+ table = tables.get (relid)
fktable = tables.get (fkrel)
# We need both ends of a relation to be a valid constraint
@@ -355,27 +355,18 @@
if parent is None:
parent = GSchema.GSConstraints (table)
- constr = GSchema.GSConstraint (parent, name = name, type =
'foreignkey')
+ constr = GSchema.GSForeignKey (parent, name = name,
+ references = fktable.name)
- if isinstance (key, basestring):
- keyparts = [int (i) - 1 for i in key [1:-1].split (',')]
- else:
- keyparts = [int (item) - 1 for item in key]
+ kp = isinstance (key, basestring) and key [1:-1].split (',') or key
+ fkp = isinstance (fkey, basestring) and fkey [1:-1].split (',') or fkey
- if isinstance (fkey, basestring):
- fkeyparts = [int (i) - 1 for i in fkey [1:-1].split (',')]
- else:
- fkeyparts = [int (item) - 1 for item in fkey]
+ k = [fields ["%s.%s" % (relid, i)].name for i in kp]
+ f = [fields ["%s.%s" % (fkrel, i)].name for i in fkp]
- keyfields = table.findChildrenOfType ('GSField', False, True)
- for ix in keyparts:
- GSchema.GSConstraintField (constr, name = keyfields [ix].name)
+ for (name, refname) in zip (k, f):
+ GSchema.GSFKField (constr, name = name, references = refname)
- fkfields = fktable.findChildrenOfType ('GSField', False, True)
- for ix in fkeyparts:
- GSchema.GSConstraintRef (constr, name = fkfields [ix].name,
- table = fktable.name)
-
finally:
cursor.close ()
Modified: trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/sqlite/Behavior.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -228,9 +228,9 @@
attrs ['nativetype'] = nativetype
if length:
- attrs ['length'] = length
+ attrs ['length'] = int (length)
if scale:
- attrs ['precision'] = scale
+ attrs ['precision'] = int (scale)
attrs ['nullable'] = _NOTNULL.match (item) is None
Modified: trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py
2005-06-17 12:17:51 UTC (rev 7609)
+++ trunk/gnue-common/src/datasources/drivers/sqlite/sqlite/Connection.py
2005-06-17 12:32:33 UTC (rev 7610)
@@ -24,7 +24,6 @@
__all__ = ['Connection']
from gnue.common.datasources.drivers import DBSIG2
-from gnue.common.datasources.drivers.sqlite.Schema.Creation.Creation import
Creation
from gnue.common.datasources.drivers.sqlite import Behavior
@@ -35,15 +34,13 @@
class Connection (DBSIG2.Connection):
_drivername = 'sqlite'
+ _behavior = Behavior.Behavior
# SQLite doesn't like boolean type in SQL parameters
_boolean_true = 1
_boolean_false = 0
- defaultCreator = Creation
- _behavior = Behavior.Behavior
-
# ---------------------------------------------------------------------------
# Constructor
# ---------------------------------------------------------------------------
Modified: trunk/gnue-common/src/definitions/GObjects.py
===================================================================
--- trunk/gnue-common/src/definitions/GObjects.py 2005-06-17 12:17:51 UTC
(rev 7609)
+++ trunk/gnue-common/src/definitions/GObjects.py 2005-06-17 12:32:33 UTC
(rev 7610)
@@ -530,3 +530,54 @@
def getClass(self):
raise "Virtual method not implemented"
+
+# =============================================================================
+# Collection class where the children in a diff won't get divided
+# =============================================================================
+
+class GUndividedCollection (GObj):
+ """
+ """
+
+ #
----------------------------------------------------------------------------
+ # Constructor
+ #
----------------------------------------------------------------------------
+
+ def __init__ (self, *args, **kwargs):
+
+ GObj.__init__ (self, *args)
+ self.buildObject (**kwargs)
+
+
+ #
----------------------------------------------------------------------------
+ # Build a difference-tree to the given object tree
+ #
----------------------------------------------------------------------------
+
+ def diff (self, goal, maxIdLength):
+
+ result = ParserObj.diff (self, goal, maxIdLength)
+
+ if result is not None:
+ for item in result._children [:]:
+ # We cannot change a child of an immutable collection directly, instead
+ # we remove the original and add the changed one.
+ if item._action == 'change':
+ result._children.remove (item)
+
+ # Add a copy of the 'old' item to be 'removed'
+ for old in self._children:
+ if old._id_ (maxIdLength) == item._id_ (maxIdLength):
+ add = old.__class__ (result)
+ add.assign (old, True)
+ add.walk (self._diffActionWalker_, "remove")
+ break
+
+ # and one copy of the 'new' item to be 'added'
+ for new in goal._children:
+ if new._id_ (maxIdLength) == item._id_ (maxIdLength):
+ add = new.__class__ (result)
+ add.assign (new, True)
+ add.walk (self._diffActionWalker_, "add")
+ break
+
+ return result
Modified: trunk/gnue-common/src/definitions/GParserHelpers.py
===================================================================
--- trunk/gnue-common/src/definitions/GParserHelpers.py 2005-06-17 12:17:51 UTC
(rev 7609)
+++ trunk/gnue-common/src/definitions/GParserHelpers.py 2005-06-17 12:32:33 UTC
(rev 7610)
@@ -1,6 +1,9 @@
+# GNU Enterprise Common Library - GParser - Helper classes
#
-# This file is part of GNU Enterprise.
+# Copyright 2001-2005 Free Software Foundation
#
+# This file is part of GNU Enterprise
+#
# GNU Enterprise 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
@@ -16,31 +19,24 @@
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
-# Copyright 2001-2005 Free Software Foundation
-#
-# FILE:
-# GParserHelpers.py
-#
-# DESCRIPTION:
-# Class that holds GNUe Parser helper classes
-#
-# NOTES:
-#
-# HISTORY:
-#
+# $Id: $
-import weakref
-
from xml.sax import saxutils
from types import StringType
-#
-# Class ParserObj
-#
-# Common initialization for GParser objects
-#
+
+# =============================================================================
+# Base class for GParser objects
+# =============================================================================
+
class ParserObj:
- def __init__(self, parent=None, type='_NotSet_'):
+
+ # ---------------------------------------------------------------------------
+ # Constructor
+ # ---------------------------------------------------------------------------
+
+ def __init__ (self, parent = None, type = '_NotSet_'):
+
self._type = type
self._children = [] # The objects contained by this object
self._attributes = {}
@@ -50,7 +46,7 @@
self._xmlnamespaces = {} # If attributes are namespace-qualified, a map
self.setParent (parent)
- if parent :
+ if parent:
parent.addChild (self)
@@ -66,10 +62,7 @@
@rtype: any
"""
- if self.__parent is not None:
- return self.__parent ()
- else:
- return None
+ return self.__parent
# ---------------------------------------------------------------------------
@@ -83,57 +76,262 @@
@param newParent: instance to be set as parent
"""
- if newParent is None:
- self.__parent = None
+ self.__parent = newParent
+
+
+ # ---------------------------------------------------------------------------
+ # Return a compareable id of an object
+ # ---------------------------------------------------------------------------
+
+ def _id_ (self, maxIdLength = None):
+ """
+ Return a compareable and identifying id of an object within a tree. Usually
+ this is it's name (if available) or it's object type (as given in the
+ constructor).
+
+ @param maxIdLength: if not None only return up to maxIdLength characters.
+ @return: id for the instance
+ """
+
+ if hasattr (self, 'name'):
+ result = self.name.lower ()
+ if maxIdLength is not None:
+ result = result [:maxIdLength]
else:
- self.__parent = weakref.ref (newParent)
+ result = self._type
+ return result
-#
-# Class GContent
-#
+
+ # ---------------------------------------------------------------------------
+ # Assign a given set of attributes from another instance
+ # ---------------------------------------------------------------------------
+
+ def assign (self, source, recursive = False):
+ """
+ """
+
+ if self.__class__ != source.__class__:
+ raise AssignmentTypeError, (self, source)
+
+ # Assign everything except the parent and the children
+ for (name, value) in source.__dict__.items ():
+ if name in ['_ParserObj__parent', '_children']:
+ continue
+
+ self.__dict__ [name] = value
+
+ if recursive:
+ self._children = []
+
+ for child in source._children:
+ new = child.__class__ (None)
+ new.assign (child, recursive)
+
+ self.addChild (new)
+ new.setParent (self)
+
+
+ # ---------------------------------------------------------------------------
+ # Merge another object tree with this tree
+ # ---------------------------------------------------------------------------
+
+ def merge (self, other, maxIdLength = None):
+ """
+ Incorporate all subtrees from the given object tree of this instances type.
+ """
+
+ # First find objects of the same type in the other tree
+ candidates = other.findChildrenOfType (self._type, True, True)
+
+ # We keep a mapping of all our children
+ mine = {}
+ for mc in self._children:
+ mine [mc._id_ (maxIdLength)] = mc
+
+ # Iterate over all elements in the other tree having the same type
+ for item in candidates:
+ # and observe all their children ...
+ for otherChild in item._children:
+ # ... wether we have to start a recursive merge ...
+ if otherChild._id_ (maxIdLength) in mine:
+ mine [otherChild._id_ (maxIdLength)].merge (otherChild)
+ # ... or we can copy the subtree
+ else:
+ new = otherChild.__class__ (self)
+ new.assign (otherChild, True)
+
+
+ # ---------------------------------------------------------------------------
+ # Build a difference-tree from two given object trees
+ # ---------------------------------------------------------------------------
+
+ def diff (self, goal, maxIdLength = None):
+ """
+ """
+
+ result = None
+
+ mine = {}
+ others = {}
+
+ # Build a mapping of our children
+ for child in self._children:
+ mine [child._id_ (maxIdLength)] = child
+
+ # find the counterpart of this instance
+ buddy = goal.findChildOfType (self._type, True, True)
+
+ if buddy is not None:
+ for child in buddy._children:
+ others [child._id_ (maxIdLength)] = child
+
+ # Find out new and changed items
+ for (key, item) in others.items ():
+ childDiff = None
+
+ if not key in mine:
+ if item._children or isinstance (item, GLeafNode):
+ childDiff = item.__class__ (None)
+ childDiff.assign (item, True)
+ childDiff.walk (self._diffActionWalker_, "add")
+
+ else:
+ # we need to find out wether the instances are changed then
+ childDiff = mine [key].diff (item, maxIdLength)
+ if childDiff is not None:
+ childDiff._action = "change"
+
+ if childDiff is not None:
+ if result is None:
+ result = self.__class__ (None)
+ result.assign (self)
+
+ result.addChild (childDiff)
+ childDiff.setParent (result)
+
+ # Finally find out all 'obsolete' ones
+ for (key, item) in mine.items ():
+ if not key in others:
+ if result is None:
+ result = self.__class__ (None)
+ result.assign (self)
+
+ child = item.__class__ (None)
+ child.assign (item, True)
+ child.walk (self._diffActionWalker_, "remove")
+
+ result.addChild (child)
+ child.setParent (result)
+
+ if result is not None:
+ result._action = "change"
+
+ return result
+
+
+ # ---------------------------------------------------------------------------
+ # Set the diff-action for a given object
+ # ---------------------------------------------------------------------------
+
+ def _diffActionWalker_ (self, obj, action):
+
+ obj._action = action
+
+
+# =============================================================================
+# Mixin-class for leaf node objects
+# =============================================================================
+
+class GLeafNode:
+ """
+ This is a I{mixin}-class for parser objects which are leaf nodes. This will
+ be a relevant information on building difference-trees between two object
+ trees. To add this class to another class do something like this::
+
+ class Foobar (ParserObj, GLeafNode): ...
+ class Barbaz (SomeOtherClass, GLeafNode): ...
+
+ There is nothing more to do if you want to flag a class as leaf node.
+ """
+
+ pass
+
+
+# =============================================================================
# Base class for xml content
-#
-class GContent(ParserObj):
+# =============================================================================
- def __init__(self, parent, content):
- ParserObj.__init__(self, parent, '_content_')
+class GContent (ParserObj):
+
+ # ---------------------------------------------------------------------------
+ # Constructor
+ # ---------------------------------------------------------------------------
+
+ def __init__ (self, parent, content = None):
+
+ ParserObj.__init__ (self, parent, '_content_')
self._content = content
- def getEscapedContent(self):
- return saxutils.escape(self._content)
- def getContent(self):
+ # ---------------------------------------------------------------------------
+ # Return the escaped contents
+ # ---------------------------------------------------------------------------
+
+ def getEscapedContent (self):
+
+ return saxutils.escape (self._content)
+
+
+ # ---------------------------------------------------------------------------
+ # Return the contents
+ # ---------------------------------------------------------------------------
+
+ def getContent (self):
+
return self._content
- def dumpXML(self, lookupDict, treeDump=None, gap=None,
- escape=1, textEncoding='<locale>', xmlnamespaces={},
- stripPrefixes = None):
- if textEncoding=='<locale>':
- textEncoding=gConfig('textEncoding')
- if type(self._content) == StringType:
- xmlString = '%s' % unicode(self._content, textEncoding)
+ # ---------------------------------------------------------------------------
+ # Return a xml representation of the object
+ # ---------------------------------------------------------------------------
+
+ def dumpXML (self, lookupDict, treeDump = None, gap = None,
+ escape = 1, textEncoding = '<locale>', xmlnamespaces = {},
+ stripPrefixes = None):
+
+ if textEncoding == '<locale>':
+ textEncoding = gConfig ('textEncoding')
+
+ if type (self._content) == StringType:
+ xmlString = '%s' % unicode (self._content, textEncoding)
else:
xmlString = self._content
- if escape:
- return saxutils.escape(xmlString)
- else:
- return xmlString
+ return escape and saxutils.escape (xmlString) or xmlString
- def showTree(self, indent=0):
- print ' '*indent + 'GContent ' + `self._content`
+ # ---------------------------------------------------------------------------
+ # Show a contents element within an (indented) tree
+ # ---------------------------------------------------------------------------
- #def _type(self):
- # return "_content_"
+ def showTree (self, indent = 0):
- #
- # getDescription
- #
- # Return a useful description of this object
- # Used by designer clients
- #
- def getDescription(self):
+ print ' ' * indent + 'GContent ' + `self._content`
+
+
+ # ---------------------------------------------------------------------------
+ # Return a useful description of this object (used by designer clients)
+ # ---------------------------------------------------------------------------
+
+ def getDescription (self):
+
return "(Content)"
+
+
+ # ---------------------------------------------------------------------------
+ # Don't merge contents instances
+ # ---------------------------------------------------------------------------
+
+ def merge (self, other):
+ return
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r7610 - in trunk/gnue-common: scripts src src/datasources src/datasources/drivers/Base src/datasources/drivers/DBSIG2 src/datasources/drivers/adodbapi src/datasources/drivers/appserver src/datasources/drivers/interbase src/datasources/drivers/interbase/interbase src/datasources/drivers/maxdb src/datasources/drivers/maxdb/maxdb src/datasources/drivers/mysql src/datasources/drivers/mysql/mysql src/datasources/drivers/oracle src/datasources/drivers/postgresql src/datasources/drivers/postgresql/Base src/datasources/drivers/sqlite src/datasources/drivers/sqlite/sqlite src/definitions,
johannes <=