Bug 77377

Summary: SQL code generator generates "circular reference" foreign keys
Product: [Applications] umbrello Reporter: Maciej J . Woloszyk <matofesi>
Component: generalAssignee: Umbrello Development Group <umbrello-devel>
Status: RESOLVED FIXED    
Severity: normal CC: holster
Priority: NOR    
Version: 1.2   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: Patch to allow tables to have self-references

Description Maciej J . Woloszyk 2004-03-12 13:04:24 UTC
Version:           1.2 (using KDE 3.2.0, Gentoo)
Compiler:          gcc version 3.3.2 20031218 (Gentoo Linux 3.3.2-r5, propolice-3.3-7)
OS:          Linux (i686) release 2.4.22-gentoo-r7

When you use Umbrello to design SQL scheme using agregations to simulate foreign keys constraints the code generators creates foreign key constarint in both tables instead of the "source" (role B - as I assume looking at the arrowhead of the aggregation connection - which is a bit misleading) table. Below is the simple patch - it makes code generator to check the objects of the aggregations and only create constraint in one table. In the other table generator also places the constraint, but only as an SQL comment. I'm not sure how well will it work, but at least it works for me.

M.

----------------- umbrello-sqlwriter.patch ---------------------------
--- kdesdk-3.2.0-orig/umbrello/umbrello/codegenerators/sqlwriter.cpp    2003-09-21 10:41:52.000000000 +0200
+++ kdesdk-3.2.0/umbrello/umbrello/codegenerators/sqlwriter.cpp 2004-03-12 12:15:23.000000000 +0100
@@ -89,8 +89,14 @@
        UMLAssociationList aggregations = c->getAggregations();
        if( forceSections() || !aggregations.isEmpty() ) {
                for(UMLAssociation* a = aggregations.first(); a; a = aggregations.next()) {
-                       sql << ",\n\tCONSTRAINT " << a->getName() << " FOREIGN KEY (" << a->getMultiB() <<
-                              ") REFERENCES " <<   a->getObjectA()->getName() << "(" << a->getMultiA() << ")";
+                       if( a->getObjectA()->getID()==c->getID() ) {
+                               sql << "\n-- CONSTRAINT " << a->getName() << " FOREIGN KEY (" << a->getMultiB() <<
+                                       ") REFERENCES " <<   a->getObjectA()->getName() << "(" << a->getMultiA() << ")";
+                       } else {
+                               sql << ",\n\tCONSTRAINT " << a->getName() << " FOREIGN KEY (" << a->getMultiB() <<
+                                       ") REFERENCES " <<   a->getObjectA()->getName() << "(" << a->getMultiA() << ")";
+
+                       }
                }
        }
Comment 1 Jonathan Riddell 2004-03-15 23:31:39 UTC
I've applied the patch, thanks for your contribution.
Comment 2 Jonathan Riddell 2004-03-15 23:32:50 UTC
*** Bug 76877 has been marked as a duplicate of this bug. ***
Comment 3 Sebastian Stein 2004-07-29 17:47:02 UTC
- foreign key constraint fixed
- comma adding fixed for different scopes
Comment 4 Sebastian Stein 2004-07-29 17:50:08 UTC
Ah, I added the wrong comment a minute ago. This bug was already mostly fixed. I just removed the commented foreign key constraint, because it is nonsense and makes the code easier to read.
Comment 5 Alexey Parshin 2006-11-20 08:29:16 UTC
Created attachment 18621 [details]
Patch to allow tables to have self-references

Sometimes, you need something like this:
create table t1 (
  id int primary key,
  parent int references t1(id)
);
The proposed patch allows it.
Also, Umbrello sometimes tries to create (in the export file) the empty foreign
keys with no table name and fields. These declarations come as a result of
deleting associations and not accessible through the Umbrello interface.
However, they are presented in the XMI file. This patch offers a primitive
workaround for this problem, too, by ignoring such associations during export.
Comment 6 Alexey Parshin 2006-11-20 08:30:36 UTC
Forgot to tell: Umbrello version I'm reporting about is a part of KDE 3.5.5.
Comment 7 Oliver Kellogg 2006-11-20 20:29:26 UTC
In attachment id=18621, Alexey Parshin wrote:
+ if ( a->getRoleName(Uml::B) != "" && a->getRoleName(Uml::B) != "") {

Hmm, twice the same expression? Please check.
Comment 8 Oliver Kellogg 2006-11-20 22:36:55 UTC
SVN commit 606555 by okellogg:

Apply attachment 18621 [details] by Alexey Parshin with slight modification.
Thanks Alexey for contributing.
CCBUG:77377


 M  +12 -8     sqlwriter.cpp  


--- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/sqlwriter.cpp #606554:606555
@@ -86,14 +86,18 @@
     UMLAssociationList aggregations = c->getAggregations();
     if( forceSections() || !aggregations.isEmpty() ) {
         for(UMLAssociation* a = aggregations.first(); a; a = aggregations.next()) {
-            if( a->getObject(Uml::A)->getID() != c->getID() ) {
-
-                sql << m_indentation << "," << m_endl << m_indentation
-                << "CONSTRAINT " << a->getName() << " FOREIGN KEY ("
-                << a->getRoleName(Uml::B) << ") REFERENCES "
-                << a->getObject(Uml::A)->getName()
-                << " (" << a->getRoleName(Uml::A) << ")";
-            }
+            UMLObject *objA = a->getObject(Uml::A);
+            UMLObject *objB = a->getObject(Uml::B);
+            if (objA->getID() == c->getID() && objB->getID() != c->getID())
+                continue;
+            QString roleNameA = a->getRoleName(Uml::A);
+            QString roleNameB = a->getRoleName(Uml::B);
+            if (roleNameA.isEmpty() || roleNameB.isEmpty())
+                continue;
+            sql << m_indentation << "," << m_endl;
+            sql << m_indentation << "CONSTRAINT " << a->getName()
+                << " FOREIGN KEY (" << roleNameB << ") REFERENCES "
+                << objA->getName() << " (" << roleNameA << ")";
         }
     }