Initial code for SQLFairy UML profile for the XMI parser. The name may need
Mark Addison [Fri, 10 Oct 2003 20:03:24 +0000 (20:03 +0000)]
changing but I wanted to get it in cvs so its safe and I can work on it and
worry about the name later.

lib/SQL/Translator/Parser/XML/XMI/SQLFairy.pm [new file with mode: 0644]
t/28xml-xmi-parser-sqlfairy.t [new file with mode: 0644]
t/data/xmi/OrderDB.sqlfairy.poseidon2.xmi [new file with mode: 0644]

diff --git a/lib/SQL/Translator/Parser/XML/XMI/SQLFairy.pm b/lib/SQL/Translator/Parser/XML/XMI/SQLFairy.pm
new file mode 100644 (file)
index 0000000..db87f3f
--- /dev/null
@@ -0,0 +1,308 @@
+package SQL::Translator::Parser::XML::XMI::SQLFairy;
+
+# -------------------------------------------------------------------
+# $Id: SQLFairy.pm,v 1.1 2003-10-10 20:03:24 grommit Exp $
+# -------------------------------------------------------------------
+# Copyright (C) 2003 Mark Addison <mark.addison@itn.co.uk>,
+#
+# 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; version 2.
+#
+# 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
+# -------------------------------------------------------------------
+
+=head1 NAME
+
+SQL::Translator::Parser::XML::XMI::SQLFairy - Create Schema from UML Models.
+
+=cut
+
+use strict;
+
+use vars qw[ $DEBUG $VERSION @EXPORT_OK ];
+$VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/;
+$DEBUG   = 0 unless defined $DEBUG;
+use Exporter;
+use base qw(Exporter);
+@EXPORT_OK = qw(parse);
+
+use Data::Dumper;
+use SQL::Translator::Parser::XML::XMI;
+use SQL::Translator::Utils 'debug';
+
+# Set the parg for the conversion sub then use the XMI parser
+sub parse {
+    my ( $translator ) = @_;
+    local $DEBUG  = $translator->debug;
+    my $pargs = $translator->parser_args;
+       $pargs->{classes2schema} = \&classes2schema;
+       return SQL::Translator::Parser::XML::XMI::parse(@_);
+}
+
+
+
+# TODO We could make the tag names a parser arg so people can use their own.
+my %TAGS;
+$TAGS{data_type} = "sqlfDataType";
+$TAGS{size} = "sqlfSize";
+$TAGS{is_nullable} = "sqlfIsNullable";
+$TAGS{required} = "sqlfRequired";
+$TAGS{is_auto_increment} = "sqlfIsAutoIncrement";
+$TAGS{default_value} = "sqlfDefaultValue";
+
+sub _parameters_in {
+       my $params = shift;
+       return grep {$_->{kind} ne "return"} @$params;
+}
+
+sub _resolve_tag {
+    my ($tag, $things) = @_;
+    foreach (@$things) {
+        return $_->{_map_taggedValues}{$tag}{dataValue}
+        if exists $_->{_map_taggedValues}{$tag}{dataValue}; 
+    }
+    return;
+}
+
+
+sub classes2schema {
+       my ($schema, $classes) = @_;
+
+    my %associations;
+       foreach my $class (@$classes) {
+               # Add the table
+        debug "Adding class: $class->{name}";
+        my $table = $schema->add_table( name => $class->{name} )
+            or die "Schema Error: ".$schema->error;
+
+        # Only collect the associations for classes that are tables. Use a hash
+        # so we only get them once
+        $associations{$_->{"xmi.id"}} = $_
+        foreach map $_->{association}, @{$class->{associationEnds}};
+
+        #
+        # Fields from Class attributes
+        #
+        my @flds;
+        push @flds, attr2field($_) for @{$class->{attributes}};
+            # TODO Filter this e.g no abstract attr or stereotype check
+        foreach (@flds) {
+            my $extra = delete $_->{extra};
+            my $field = $table->add_field( %$_ ) or die $schema->error;
+            $field->extra(%$extra) if $extra;
+        }
+
+        #
+        # Primary key
+        #
+        my @pkeys;
+        @pkeys = map $_->{name},
+            grep($_->{stereotype} eq "PK", @{$class->{attributes}});
+        # if none set with steretype, use first attrib
+        @pkeys = $class->{attributes}[0]{name} unless @pkeys;
+        $table->add_constraint(
+            type   => "PRIMARY KEY",
+            fields => [@pkeys],
+        ) or die $schema->error;
+    }
+
+    #
+    # Relationships from Associations
+    #
+    foreach my $assoc (values %associations) {
+        my @end = @{$assoc->{associationEnds}};
+        if (
+            $end[0]->{multiplicity}{rangeUpper} == 1 
+            && $end[1]->{multiplicity}{rangeUpper} == 1 
+        ) {
+            # 1:1 or 0:1
+            warn "Sorry, 1:1 associations not yet implimented for xmi.id".$assoc->{"xmi.id"}."\n";
+        }
+        elsif (
+            $end[0]->{multiplicity}{rangeUpper} == 1 
+            || $end[1]->{multiplicity}{rangeUpper} == 1 
+        ) {
+            # 1:m or 0:m
+            one2many($schema,$assoc);
+        }
+        else
+        {
+            # m:n
+            warn "Sorry, n:m associations not yet implimented for xmi.id".$assoc->{"xmi.id"}."\n";
+        }
+
+    }    
+
+}
+
+sub attr2field {
+    my $attr = shift;
+    my $dataType = $attr->{dataType};
+
+    my %data = ( name => $attr->{name} );
+
+    $data{data_type}
+        = _resolve_tag($TAGS{data_type},[$attr,$dataType])
+        || $dataType->{name};
+
+    $data{size} = _resolve_tag($TAGS{size},[$attr,$dataType]);
+
+    $data{default_value} 
+        = $attr->{initialValue}
+        || _resolve_tag($TAGS{default_value},[$attr,$dataType]);
+
+    my $is_nullable = _resolve_tag($TAGS{is_nullable},[$attr,$dataType]);
+    my $required    = _resolve_tag($TAGS{required},[$attr,$dataType]);
+    $data{is_nullable} 
+        = defined $is_nullable ? $is_nullable 
+        : ( defined $required ? ($required ? 0 : 1) : undef);
+
+    $data{is_auto_increment}
+        =  $attr->{_map_taggedValues}{$TAGS{is_auto_increment}}{dataValue}
+        || $dataType->{_map_taggedValues}{$TAGS{is_auto_increment}}{dataValue}
+        || undef;
+
+    #
+    # Extras
+    # 
+    my %tagnames;
+    foreach ( keys %{$attr->{_map_taggedValues}} ) {$tagnames{$_}++; }
+    delete @tagnames{@TAGS{qw/data_type size default_value is_nullable required is_auto_increment/}}; # Remove the tags we have already done
+    my %extra = map { 
+        my $val = $attr->{_map_taggedValues}{$_}{dataValue};
+        s/^sqlf//;
+        ($_,$val);
+    } keys %tagnames;
+    $data{extra} = \%extra;
+
+    return \%data;
+}
+
+# Maps a 1:M association into the schema
+sub one2many {
+    my ($scma,$assoc) = @_;
+    my @ends = @{$assoc->{associationEnds}};
+    my ($end1) = grep $_->{multiplicity}{rangeUpper} == 1, @ends;
+    my $endm = $end1->{otherEnd};
+    my $table1 = $scma->get_table($end1->{participant}{name});
+    my $tablem = $scma->get_table($endm->{participant}{name});
+
+    #
+    # Export 1end pkey to many end
+    # 
+    my $con = $table1->primary_key;
+    my @flds = $con->fields;
+    foreach (@flds) {
+        my $fld = $table1->get_field($_);
+        my %data;
+        $data{$_} = $fld->$_()
+        foreach (qw/name size data_type default_value is_nullable/); 
+        $data{extra} = { $fld->extra }; # Copy extra hash
+        $data{is_unique} = 0; # FKey on many join so not unique
+        $data{is_nullable} = $end1->{multiplicity}{rangeLower} == 0 ? 1 : 0;
+            # 0:m - allow nulluable on fkey
+            # 1:m - dont allow nullable
+
+        $tablem->add_field(%data) or die $scma->error;
+        # Export the pkey if full composite (ie identity) relationship
+        $tablem->primary_key($_) if $end1->{aggregation} eq "composite";
+    }
+
+    #
+    # Add fkey constraint to many end
+    # 
+    $tablem->add_constraint(
+        type   => "FOREIGN_KEY",
+        fields => [@flds],
+        reference_table => $table1->{name},
+        reference_fields => [@flds],
+    ) or die $scma->error;
+}
+
+1; #---------------------------------------------------------------------------
+
+__END__
+
+=pod
+
+=head1 SYNOPSIS
+
+  use SQL::Translator;
+  use SQL::Translator::Parser::XML::XMI;
+
+  my $translator     = SQL::Translator->new(
+      from           => 'XML-XMI-SQLFairy',
+      to             => 'MySQL',
+      filename       => 'schema.xmi',
+  );
+
+  print $obj->translate;
+
+=head1 DESCRIPTION
+
+Converts Class diagrams to Schema trying to use standard UML features as much
+as possible, with the minimum use of extension mechanisms (tagged values and
+stereotypes) for the database details. The idea is to treat the object model 
+like a logical database model and map that to a physical model (the sql). Also
+tries to make this mapping as configurable as possible and support all the
+schema features that SQLFairy does.
+
+=head2 Tables
+
+Classes, all of them! (TODO More control over which tables to do.)
+
+=head2 Fields
+
+=head3 Datatypes 
+
+Database datatypes are modeled using tagged values; sqlfDataType,
+sqlfSize, sqlfIsNullable and sqlfIsAutoIncrement. These can be added either
+to the UML datatype or directly on the attribute where they override the value
+from the datatype. If no sqlfDataType is given then the name of the UMLDataType
+is used. If no default value is found then the UML initialValue is used (even 
+if a tag is set on the UMLDataType - do we want to do it this way?.
+
+=head3 Primary Keys
+
+Primary keys are attributes marked with <<PK>>. Add to multiple attribs to make
+multi column keys. If none are marked will use the 1st attribute. 
+
+=head2 Relationships
+
+Modeled using UML associations. Currently only handles 0:m and 1:m joins. That
+is associations where one ends multiplicty is '1' or '0..1' and the other end's
+multplicity is '0..*' or '1..*' or >1 (e.g '0..3' '1..23' '4..42') etc. 
+
+The pkey from the 1 end is added to the table for the class at the many end as
+a foreign key. is_unique is forced to false for the new field. 
+
+If the 1 end is multiplicity '0..1' (ie a 0:m join) then the the fkey is made
+nullable, if its multiplicity '1' (1:m) then its made not nullable.
+
+If the association is a composition then the created fkey is made part of the 
+many ends pkey. ie It exports the pkey to create an identity join. 
+
+=head1 ARGS
+
+=head1 BUGS
+
+=head1 TODO
+
+=head1 AUTHOR
+
+Mark D. Addison E<lt>mark.addison@itn.co.ukE<gt>.
+
+=head1 SEE ALSO
+
+perl(1), SQL::Translator::Parser::XML::XMI
+
+=cut
diff --git a/t/28xml-xmi-parser-sqlfairy.t b/t/28xml-xmi-parser-sqlfairy.t
new file mode 100644 (file)
index 0000000..359f6a6
--- /dev/null
@@ -0,0 +1,297 @@
+#!/usr/bin/perl -w 
+# vim:filetype=perl
+
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+use strict;
+use FindBin qw/$Bin/;
+use Data::Dumper;
+
+# run with -d for debug
+my %opt;
+BEGIN { map { $opt{$_}=1 if s/^-// } @ARGV; }
+use constant DEBUG => (exists $opt{d} ? 1 : 0);
+
+use Test::More;
+use Test::Exception;
+use SQL::Translator;
+use SQL::Translator::Schema::Constants;
+
+# Usefull test subs for the schema objs
+#=============================================================================
+
+sub test_field {
+    my ($f1,$test) = @_;
+    unless ($f1) {
+        fail " Field '$test->{name}' doesn't exist!";
+        # TODO Do a skip on the following tests
+        return;
+    }
+
+       is( $f1->name, $test->{name}, "  Field name '$test->{name}'" );
+    
+       is( $f1->data_type, $test->{data_type}, "    Type is '$test->{data_type}'" )
+       if exists $test->{data_type};
+    
+       is( $f1->size, $test->{size}, "    Size is '$test->{size}'" )
+       if exists $test->{size};
+    
+       is( $f1->default_value, $test->{default_value},
+       "    Default value is ".(defined($test->{default_value}) ? "'$test->{default_value}'" : "UNDEF" ) )
+       if exists $test->{default_value};
+       
+       is( $f1->is_nullable, $test->{is_nullable}, 
+               "    ".($test->{is_nullable} ? 'can' : 'cannot').' be null' )
+       if exists $test->{is_nullable};
+    
+       is( $f1->is_unique, $test->{is_unique}, 
+               "    ".($test->{is_unique} ? 'can' : 'cannot').' be unique' )
+       if exists $test->{is_unique};
+    
+       is( $f1->is_primary_key, $test->{is_primary_key}, 
+               "    is ".($test->{is_primary_key} ? '' : 'not').' a primary_key' )
+       if exists $test->{is_primary_key};
+    
+       is( $f1->is_foreign_key, $test->{is_foreign_key}, 
+               "    is ".($test->{is_foreign_key} ? '' : 'not').' a foreign_key' )
+       if exists $test->{is_foreign_key};
+    
+       is( $f1->is_auto_increment, $test->{is_auto_increment}, 
+       "    is ".($test->{is_auto_increment} ?  '' : 'not').' an auto_increment' )
+       if exists $test->{is_auto_increment};
+}
+
+sub constraint_ok {
+    my ($con,$test) = @_;
+       #$test->{name} ||= "<anon>";
+
+       if ( exists $test->{name} ) {
+               is( $con->name, $test->{name}, "  Constraint '$test->{name}'" );
+       }
+       else {
+               ok( $con, "  Constraint" );
+       }
+       
+       is( $con->type, $test->{type}, "    type is '$test->{type}'" )
+       if exists $test->{type};
+       
+       is( $con->table->name, $test->{table}, "    table is '$test->{table}'" )
+       if exists $test->{table};
+       
+       is( join(",",$con->fields), $test->{fields},
+       "    fields is '$test->{fields}'" )
+       if exists $test->{fields};
+       
+       is( $con->reference_table, $test->{reference_table},
+       "    reference_table is '$test->{reference_table}'" )
+       if exists $test->{reference_table};
+       
+       is( join(",",$con->reference_fields), $test->{reference_fields},
+       "    reference_fields is '$test->{reference_fields}'" )
+       if exists $test->{reference_fields};
+       
+       is( $con->match_type, $test->{match_type},
+       "    match_type is '$test->{match_type}'" )
+       if exists $test->{match_type};
+       
+       is( $con->on_delete_do, $test->{on_delete_do},
+       "    on_delete_do is '$test->{on_delete_do}'" )
+       if exists $test->{on_delete_do};
+       
+       is( $con->on_update_do, $test->{on_update_do},
+       "    on_update_do is '$test->{on_update_do}'" )
+       if exists $test->{on_update_do};
+}
+
+sub test_table {
+    my $tbl = shift;
+    my %arg = @_;
+       $arg{constraints} ||= [];
+    my $name = $arg{name} || die "Need a table name to test.";
+    
+       my @fldnames = map { $_->{name} } @{$arg{fields}};
+       is_deeply( [ map {$_->name}   $tbl->get_fields ],
+               [ map {$_->{name}} @{$arg{fields}} ],
+               "Table $name\'s fields" );
+    foreach ( @{$arg{fields}} ) {
+        my $name = $_->{name} || die "Need a field name to test.";
+        test_field( $tbl->get_field($name), $_ );
+    }
+       
+       if ( my @tcons = @{$arg{constraints}} ) {
+               my @cons = $tbl->get_constraints;
+               is(scalar(@cons), scalar(@tcons),
+               "Table $name has ".scalar(@tcons)." Constraints");
+               foreach ( @cons ) {
+                       my $ans = { table => $tbl->name, %{shift @tcons}};
+                       constraint_ok( $_, $ans  );
+               }
+       }
+}
+
+# Testing 1,2,3,..
+#=============================================================================
+
+plan tests => 89;
+
+my $testschema = "$Bin/data/xmi/OrderDB.sqlfairy.poseidon2.xmi";
+die "Can't find test schema $testschema" unless -e $testschema;
+
+my $obj;
+$obj = SQL::Translator->new(
+    filename => $testschema,
+    from     => 'XML-XMI-SQLFairy',
+    to       => 'MySQL',
+    debug          => DEBUG,
+    show_warnings  => 1,
+);
+my $sql = $obj->translate;
+ok( $sql, "Got some SQL");
+print $sql if DEBUG;
+
+
+#
+# Test the schema
+#
+my $scma = $obj->schema;
+is( $scma->is_valid, 1, 'Schema is valid' );
+my @tblnames = map {$_->name} $scma->get_tables;
+is(scalar(@{$scma->get_tables}), scalar(@tblnames), "Right number of tables");
+is_deeply( \@tblnames, [qw/Order OrderLine Customer/]
+    ,"tables");
+
+test_table( $scma->get_table("Customer"),
+    name => "Customer",
+    fields => [
+    {
+        name => "customerID",
+        data_type => "INT",
+               size => 20,
+        default_value => undef,
+        is_nullable => 0,
+        is_primary_key => 1,
+    },
+    {
+        name => "name",
+        data_type => "VARCHAR",
+               size => 255,
+        default_value => undef,
+        is_nullable => 0,
+        is_primary_key => 0,
+    },
+    {
+        name => "email",
+        data_type => "VARCHAR",
+               size => 255,
+        default_value => undef,
+        is_nullable => 1,
+        is_primary_key => 0,
+    },
+    ],
+       constraints => [
+               {
+                       type => "PRIMARY KEY",
+                       fields => "customerID",
+               },
+        #{
+               #       name => "UniqueEmail",
+               #       type => "UNIQUE",
+               #       fields => "email",
+               #},
+       ],
+);
+
+test_table( $scma->get_table("Order"),
+    name => "Order",
+    fields => [
+    {
+        name => "orderDate",
+        data_type => "DATE",
+        default_value => undef,
+        is_nullable => 0,
+        is_primary_key => 0,
+    },
+    {
+        name => "orderID",
+        data_type => "INT",
+               size => 10,
+        default_value => undef,
+        is_nullable => 0,
+        is_primary_key => 1,
+    },
+    {
+        name => "customerID",
+        data_type => "INT",
+               size => 20,
+        default_value => undef,
+        is_nullable => 0,
+        is_primary_key => 0,
+        is_foreign_key => 1,
+    },
+    ],
+       constraints => [
+               {
+                       type => "PRIMARY KEY",
+                       fields => "orderID",
+               },
+               {
+                       type => "FOREIGN KEY",
+                       fields => "customerID",
+                       reference_table => "Customer",
+                       reference_fields => "customerID",
+               },
+       ],
+       # TODO
+       #indexes => [
+       #       {
+       #               name => "idxOrderDate",
+       #               type => "INDEX",
+       #               fields => "orderDate",
+       #       },
+       #],
+);
+
+
+test_table( $scma->get_table("OrderLine"),
+    name => "OrderLine",
+    fields => [
+    {
+        name => "lineNumber",
+        data_type => "INT",
+               size => 255,
+        default_value => 1,
+        is_nullable => 0,
+        is_primary_key => 1,
+    },
+    {
+        name => "quantity",
+        data_type => "INT",
+               size => 255,
+        default_value => 1,
+        is_nullable => 0,
+        is_primary_key => 0,
+    },
+    {
+        name => "orderID",
+        data_type => "INT",
+               size => 10,
+        default_value => undef,
+        is_nullable => 1,
+        is_primary_key => 0,
+        is_foreign_key => 1,
+    },
+    ],
+       constraints => [
+               {
+                       type => "PRIMARY KEY",
+                       fields => "lineNumber,orderID",
+               },
+               {
+                       type => "FOREIGN KEY",
+                       fields => "orderID",
+                       reference_table => "Order",
+                       reference_fields => "orderID",
+               },
+       ],
+);
diff --git a/t/data/xmi/OrderDB.sqlfairy.poseidon2.xmi b/t/data/xmi/OrderDB.sqlfairy.poseidon2.xmi
new file mode 100644 (file)
index 0000000..acf3007
--- /dev/null
@@ -0,0 +1,452 @@
+<?xml version = '1.0' encoding = 'UTF-8' ?>\r
+<XMI xmi.version = '1.2' xmlns:UML = 'org.omg.xmi.namespace.UML' timestamp = 'Mon Oct 06 18:34:04 BST 2003'>\r
+  <XMI.header>\r
+    <XMI.documentation>\r
+      <XMI.exporter>Netbeans XMI Writer</XMI.exporter>\r
+      <XMI.exporterVersion>1.0</XMI.exporterVersion>\r
+    </XMI.documentation>\r
+  </XMI.header>\r
+  <XMI.content>\r
+    <UML:Multiplicity xmi.id = '5539d8:f7b62bc3a2:-7ff9'>\r
+      <UML:Multiplicity.range>\r
+        <UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7ff8' lower = '1' upper = '1'/>\r
+      </UML:Multiplicity.range>\r
+    </UML:Multiplicity>\r
+    <UML:Multiplicity xmi.id = '5539d8:f7b62bc3a2:-7ff7'>\r
+      <UML:Multiplicity.range>\r
+        <UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7ff6' lower = '1' upper = '1'/>\r
+      </UML:Multiplicity.range>\r
+    </UML:Multiplicity>\r
+    <UML:Multiplicity xmi.id = '5539d8:f7b62bc3a2:-7fd6'>\r
+      <UML:Multiplicity.range>\r
+        <UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7fd5' lower = '1' upper = '1'/>\r
+      </UML:Multiplicity.range>\r
+    </UML:Multiplicity>\r
+    <UML:Multiplicity xmi.id = '5539d8:f7b62bc3a2:-7fec'>\r
+      <UML:Multiplicity.range>\r
+        <UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7feb' lower = '1' upper = '1'/>\r
+      </UML:Multiplicity.range>\r
+    </UML:Multiplicity>\r
+    <UML:Model xmi.id = '5539d8:f7b62bc3a2:-7ff5' name = 'OrderDB' isSpecification = 'false'\r
+      isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+      <UML:Namespace.ownedElement>\r
+        <UML:Class xmi.id = '5539d8:f7b62bc3a2:-7ff4' name = 'Order' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'\r
+          isActive = 'false'>\r
+          <UML:Classifier.feature>\r
+            <UML:Attribute xmi.id = '5539d8:f7b62bc3a2:-7ff1' name = 'orderDate' visibility = 'public'\r
+              isSpecification = 'false' ownerScope = 'instance'>\r
+              <UML:ModelElement.taggedValue>\r
+                <UML:TaggedValue xmi.id = '3a5a9c:f811ae8178:-7f6f' isSpecification = 'false'>\r
+                  <UML:TaggedValue.dataValue>0</UML:TaggedValue.dataValue>\r
+                  <UML:TaggedValue.type>\r
+                    <UML:TagDefinition xmi.idref = '3a5a9c:f811ae8178:-7f6e'/>\r
+                  </UML:TaggedValue.type>\r
+                </UML:TaggedValue>\r
+              </UML:ModelElement.taggedValue>\r
+              <UML:StructuralFeature.type>\r
+                <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7ffa'/>\r
+              </UML:StructuralFeature.type>\r
+            </UML:Attribute>\r
+            <UML:Attribute xmi.id = '5539d8:f7b62bc3a2:-7ff3' name = 'orderID' visibility = 'public'\r
+              isSpecification = 'false' ownerScope = 'instance'>\r
+              <UML:ModelElement.stereotype>\r
+                <UML:Stereotype xmi.idref = '24d0fa:f8019a3e88:-7fbf'/>\r
+              </UML:ModelElement.stereotype>\r
+              <UML:StructuralFeature.type>\r
+                <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7ffb'/>\r
+              </UML:StructuralFeature.type>\r
+            </UML:Attribute>\r
+          </UML:Classifier.feature>\r
+        </UML:Class>\r
+        <UML:Class xmi.id = '5539d8:f7b62bc3a2:-7fef' name = 'OrderLine' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'\r
+          isActive = 'false'>\r
+          <UML:Classifier.feature>\r
+            <UML:Attribute xmi.id = '5539d8:f7b62bc3a2:-7e8d' name = 'lineNumber' visibility = 'public'\r
+              isSpecification = 'false' ownerScope = 'instance'>\r
+              <UML:Attribute.initialValue>\r
+                <UML:Expression xmi.id = '5539d8:f7b62bc3a2:-7e8c' language = 'java' body = '1'/>\r
+              </UML:Attribute.initialValue>\r
+              <UML:ModelElement.taggedValue>\r
+                <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7f9d' isSpecification = 'false'>\r
+                  <UML:TaggedValue.dataValue>1</UML:TaggedValue.dataValue>\r
+                  <UML:TaggedValue.type>\r
+                    <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7faa'/>\r
+                  </UML:TaggedValue.type>\r
+                </UML:TaggedValue>\r
+              </UML:ModelElement.taggedValue>\r
+              <UML:StructuralFeature.type>\r
+                <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7ff9'/>\r
+              </UML:StructuralFeature.type>\r
+            </UML:Attribute>\r
+            <UML:Attribute xmi.id = '5539d8:f7b62bc3a2:-7f0f' name = 'quantity' visibility = 'public'\r
+              isSpecification = 'false' ownerScope = 'instance'>\r
+              <UML:Attribute.initialValue>\r
+                <UML:Expression xmi.id = '5539d8:f7b62bc3a2:-7f0e' language = 'java' body = '1'/>\r
+              </UML:Attribute.initialValue>\r
+              <UML:ModelElement.taggedValue>\r
+                <UML:TaggedValue xmi.id = '3a5a9c:f811ae8178:-7f6b' isSpecification = 'false'>\r
+                  <UML:TaggedValue.dataValue>0</UML:TaggedValue.dataValue>\r
+                  <UML:TaggedValue.type>\r
+                    <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fcb'/>\r
+                  </UML:TaggedValue.type>\r
+                </UML:TaggedValue>\r
+              </UML:ModelElement.taggedValue>\r
+              <UML:StructuralFeature.type>\r
+                <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7ff9'/>\r
+              </UML:StructuralFeature.type>\r
+            </UML:Attribute>\r
+          </UML:Classifier.feature>\r
+        </UML:Class>\r
+        <UML:Class xmi.id = '5539d8:f7b62bc3a2:-7fe7' name = 'Customer' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'\r
+          isActive = 'false'>\r
+          <UML:ModelElement.comment>\r
+            <UML:Comment xmi.idref = '24d0fa:f8019a3e88:-7fa7'/>\r
+          </UML:ModelElement.comment>\r
+          <UML:Classifier.feature>\r
+            <UML:Attribute xmi.id = '5539d8:f7b62bc3a2:-7fe6' name = 'customerID' visibility = 'public'\r
+              isSpecification = 'false' ownerScope = 'instance'>\r
+              <UML:ModelElement.taggedValue>\r
+                <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fa6' isSpecification = 'false'>\r
+                  <UML:TaggedValue.dataValue>20</UML:TaggedValue.dataValue>\r
+                  <UML:TaggedValue.type>\r
+                    <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fd3'/>\r
+                  </UML:TaggedValue.type>\r
+                </UML:TaggedValue>\r
+                <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7f98' isSpecification = 'false'>\r
+                  <UML:TaggedValue.dataValue>ZEROFILL</UML:TaggedValue.dataValue>\r
+                  <UML:TaggedValue.type>\r
+                    <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7f97'/>\r
+                  </UML:TaggedValue.type>\r
+                </UML:TaggedValue>\r
+              </UML:ModelElement.taggedValue>\r
+              <UML:StructuralFeature.type>\r
+                <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7ffb'/>\r
+              </UML:StructuralFeature.type>\r
+            </UML:Attribute>\r
+            <UML:Attribute xmi.id = '5539d8:f7b62bc3a2:-7fe5' name = 'name' visibility = 'public'\r
+              isSpecification = 'false' ownerScope = 'instance'>\r
+              <UML:StructuralFeature.type>\r
+                <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7ff8'/>\r
+              </UML:StructuralFeature.type>\r
+            </UML:Attribute>\r
+            <UML:Attribute xmi.id = '24d0fa:f8019a3e88:-7f94' name = 'email' visibility = 'public'\r
+              isSpecification = 'false' ownerScope = 'instance'>\r
+              <UML:StructuralFeature.type>\r
+                <UML:DataType xmi.idref = '24d0fa:f8019a3e88:-7f93'/>\r
+              </UML:StructuralFeature.type>\r
+            </UML:Attribute>\r
+          </UML:Classifier.feature>\r
+        </UML:Class>\r
+        <UML:Association xmi.id = '5539d8:f7b62bc3a2:-7fe3' isSpecification = 'false'\r
+          isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:Association.connection>\r
+            <UML:AssociationEnd xmi.id = '5539d8:f7b62bc3a2:-7fe2' name = '' visibility = 'public'\r
+              isSpecification = 'false' isNavigable = 'true' ordering = 'unordered' aggregation = 'none'\r
+              targetScope = 'instance' changeability = 'changeable'>\r
+              <UML:AssociationEnd.multiplicity>\r
+                <UML:Multiplicity xmi.id = '5539d8:f7b62bc3a2:-7fe1'>\r
+                  <UML:Multiplicity.range>\r
+                    <UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7fe0' lower = '1' upper = '1'/>\r
+                  </UML:Multiplicity.range>\r
+                </UML:Multiplicity>\r
+              </UML:AssociationEnd.multiplicity>\r
+              <UML:AssociationEnd.participant>\r
+                <UML:Class xmi.idref = '5539d8:f7b62bc3a2:-7fe7'/>\r
+              </UML:AssociationEnd.participant>\r
+            </UML:AssociationEnd>\r
+            <UML:AssociationEnd xmi.id = '5539d8:f7b62bc3a2:-7fdf' name = '' visibility = 'public'\r
+              isSpecification = 'false' isNavigable = 'true' ordering = 'unordered' aggregation = 'none'\r
+              targetScope = 'instance' changeability = 'changeable'>\r
+              <UML:AssociationEnd.multiplicity>\r
+                <UML:Multiplicity xmi.id = '5539d8:f7b62bc3a2:-7fde'>\r
+                  <UML:Multiplicity.range>\r
+                    <UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7fdd' lower = '0' upper = '-1'/>\r
+                  </UML:Multiplicity.range>\r
+                </UML:Multiplicity>\r
+              </UML:AssociationEnd.multiplicity>\r
+              <UML:AssociationEnd.participant>\r
+                <UML:Class xmi.idref = '5539d8:f7b62bc3a2:-7ff4'/>\r
+              </UML:AssociationEnd.participant>\r
+            </UML:AssociationEnd>\r
+          </UML:Association.connection>\r
+        </UML:Association>\r
+        <UML:Association xmi.id = '5539d8:f7b62bc3a2:-7fee' isSpecification = 'false'\r
+          isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:Association.connection>\r
+            <UML:AssociationEnd xmi.id = '5539d8:f7b62bc3a2:-7fed' name = '' visibility = 'public'\r
+              isSpecification = 'false' isNavigable = 'true' ordering = 'unordered' aggregation = 'composite'\r
+              targetScope = 'instance' changeability = 'changeable'>\r
+              <UML:AssociationEnd.multiplicity>\r
+                <UML:Multiplicity xmi.id = '3a5a9c:f811ae8178:-7f71'>\r
+                  <UML:Multiplicity.range>\r
+                    <UML:MultiplicityRange xmi.id = '3a5a9c:f811ae8178:-7f70' lower = '0' upper = '1'/>\r
+                  </UML:Multiplicity.range>\r
+                </UML:Multiplicity>\r
+              </UML:AssociationEnd.multiplicity>\r
+              <UML:AssociationEnd.participant>\r
+                <UML:Class xmi.idref = '5539d8:f7b62bc3a2:-7ff4'/>\r
+              </UML:AssociationEnd.participant>\r
+            </UML:AssociationEnd>\r
+            <UML:AssociationEnd xmi.id = '5539d8:f7b62bc3a2:-7fea' name = '' visibility = 'public'\r
+              isSpecification = 'false' isNavigable = 'true' ordering = 'unordered' aggregation = 'none'\r
+              targetScope = 'instance' changeability = 'changeable'>\r
+              <UML:AssociationEnd.multiplicity>\r
+                <UML:Multiplicity xmi.id = '5539d8:f7b62bc3a2:-7fe9'>\r
+                  <UML:Multiplicity.range>\r
+                    <UML:MultiplicityRange xmi.id = '5539d8:f7b62bc3a2:-7fe8' lower = '0' upper = '-1'/>\r
+                  </UML:Multiplicity.range>\r
+                </UML:Multiplicity>\r
+              </UML:AssociationEnd.multiplicity>\r
+              <UML:AssociationEnd.participant>\r
+                <UML:Class xmi.idref = '5539d8:f7b62bc3a2:-7fef'/>\r
+              </UML:AssociationEnd.participant>\r
+            </UML:AssociationEnd>\r
+          </UML:Association.connection>\r
+        </UML:Association>\r
+        <UML:DataType xmi.id = '24d0fa:f8019a3e88:-7ff8' name = 'name' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:ModelElement.taggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fc4' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>VARCHAR</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fc3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fc2' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>255</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fd3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fab' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>1</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7faa'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+          </UML:ModelElement.taggedValue>\r
+        </UML:DataType>\r
+        <UML:DataType xmi.id = '24d0fa:f8019a3e88:-7ffb' name = 'id' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:ModelElement.taggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fd0' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>INT</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fc3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fcf' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>10</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fd3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fce' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>1</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fcd'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fcc' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>0</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fcb'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+          </UML:ModelElement.taggedValue>\r
+        </UML:DataType>\r
+        <UML:DataType xmi.id = '24d0fa:f8019a3e88:-7ffa' name = 'date' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:ModelElement.taggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fd7' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>DATE</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fc3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+          </UML:ModelElement.taggedValue>\r
+        </UML:DataType>\r
+        <UML:DataType xmi.id = '24d0fa:f8019a3e88:-7ff9' name = 'int' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:ModelElement.taggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fc6' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>INT</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fc3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7fc5' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>255</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fd3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+          </UML:ModelElement.taggedValue>\r
+        </UML:DataType>\r
+        <UML:Stereotype xmi.id = '24d0fa:f8019a3e88:-7fbf' name = 'PK' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:Stereotype.baseClass>ModelElement</UML:Stereotype.baseClass>\r
+        </UML:Stereotype>\r
+        <UML:Comment xmi.id = '24d0fa:f8019a3e88:-7fa7' name = '' visibility = 'public'\r
+          isSpecification = 'false' body = 'sqlfSize override&#10;on customerID&#10;&#10;Implied pkey&#10;- uses 1st field'>\r
+          <UML:Comment.annotatedElement>\r
+            <UML:Class xmi.idref = '5539d8:f7b62bc3a2:-7fe7'/>\r
+          </UML:Comment.annotatedElement>\r
+        </UML:Comment>\r
+        <UML:Package xmi.id = '24d0fa:f8019a3e88:-7f92' name = 'java' isSpecification = 'false'\r
+          isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:Namespace.ownedElement>\r
+            <UML:Package xmi.id = '24d0fa:f8019a3e88:-7f91' name = 'lang' isSpecification = 'false'\r
+              isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+              <UML:Namespace.ownedElement>\r
+                <UML:DataType xmi.id = '24d0fa:f8019a3e88:-7f90' name = 'void' isSpecification = 'false'\r
+                  isRoot = 'false' isLeaf = 'false' isAbstract = 'false'/>\r
+              </UML:Namespace.ownedElement>\r
+            </UML:Package>\r
+          </UML:Namespace.ownedElement>\r
+        </UML:Package>\r
+        <UML:DataType xmi.id = '24d0fa:f8019a3e88:-7f93' name = 'string' visibility = 'public'\r
+          isSpecification = 'false' isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>\r
+          <UML:ModelElement.taggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7f8f' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>VARCHAR</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fc3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+            <UML:TaggedValue xmi.id = '24d0fa:f8019a3e88:-7f8e' isSpecification = 'false'>\r
+              <UML:TaggedValue.dataValue>255</UML:TaggedValue.dataValue>\r
+              <UML:TaggedValue.type>\r
+                <UML:TagDefinition xmi.idref = '24d0fa:f8019a3e88:-7fd3'/>\r
+              </UML:TaggedValue.type>\r
+            </UML:TaggedValue>\r
+          </UML:ModelElement.taggedValue>\r
+        </UML:DataType>\r
+      </UML:Namespace.ownedElement>\r
+    </UML:Model>\r
+    <UML:TagDefinition xmi.id = '1f5eb7f:f7bb15dc4a:-7ffa' name = 'size' isSpecification = 'false'\r
+      tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '1f5eb7f:f7bb15dc4a:-7ff8'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '1f5eb7f:f7bb15dc4a:-7ff7' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '1f5eb7f:f7bb15dc4a:-7ff4' name = 'dataType'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '1f5eb7f:f7bb15dc4a:-7ff1'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '1f5eb7f:f7bb15dc4a:-7ff0' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '1f5eb7f:f7bb15dc4a:-7ff2' name = 'nullable'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '1f5eb7f:f7bb15dc4a:-7fef'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '1f5eb7f:f7bb15dc4a:-7fee' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '24d0fa:f8019a3e88:-7fd6' name = 'sqlfDataType'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '24d0fa:f8019a3e88:-7fd5'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '24d0fa:f8019a3e88:-7fd4' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '24d0fa:f8019a3e88:-7fd3' name = 'sqlfSize'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '24d0fa:f8019a3e88:-7fd2'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '24d0fa:f8019a3e88:-7fd1' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '24d0fa:f8019a3e88:-7fcd' name = 'sqlfIsAutoIncrement'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '24d0fa:f8019a3e88:-7fca'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '24d0fa:f8019a3e88:-7fc9' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '24d0fa:f8019a3e88:-7fcb' name = 'sqlfIsNullable'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '24d0fa:f8019a3e88:-7fc8'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '24d0fa:f8019a3e88:-7fc7' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '24d0fa:f8019a3e88:-7fc3' name = 'sqlfDataType'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '24d0fa:f8019a3e88:-7fc1'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '24d0fa:f8019a3e88:-7fc0' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '24d0fa:f8019a3e88:-7faa' name = 'sqlfRequired'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '24d0fa:f8019a3e88:-7fa9'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '24d0fa:f8019a3e88:-7fa8' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '24d0fa:f8019a3e88:-7f97' name = 'sqlfqualifier'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '24d0fa:f8019a3e88:-7f96'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '24d0fa:f8019a3e88:-7f95' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:TagDefinition xmi.id = '3a5a9c:f811ae8178:-7f6e' name = 'sqlfIsNullable'\r
+      isSpecification = 'false' tagType = 'String'>\r
+      <UML:TagDefinition.multiplicity>\r
+        <UML:Multiplicity xmi.id = '3a5a9c:f811ae8178:-7f6d'>\r
+          <UML:Multiplicity.range>\r
+            <UML:MultiplicityRange xmi.id = '3a5a9c:f811ae8178:-7f6c' lower = '1' upper = '1'/>\r
+          </UML:Multiplicity.range>\r
+        </UML:Multiplicity>\r
+      </UML:TagDefinition.multiplicity>\r
+    </UML:TagDefinition>\r
+    <UML:Uml1SemanticModelBridge xmi.id = '5539d8:f7b62bc3a2:-7f10' presentation = ''>\r
+      <UML:Uml1SemanticModelBridge.element>\r
+        <UML:Model xmi.idref = '5539d8:f7b62bc3a2:-7ff5'/>\r
+      </UML:Uml1SemanticModelBridge.element>\r
+    </UML:Uml1SemanticModelBridge>\r
+    <UML:Uml1SemanticModelBridge xmi.id = '3a5a9c:f811ae8178:-7fc0' presentation = ''>\r
+      <UML:Uml1SemanticModelBridge.element>\r
+        <UML:Model xmi.idref = '5539d8:f7b62bc3a2:-7ff5'/>\r
+      </UML:Uml1SemanticModelBridge.element>\r
+    </UML:Uml1SemanticModelBridge>\r
+    \r
+  </XMI.content>\r
+</XMI>\r