<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns="http://cygnets.co.uk/schemas/adl-1.2" xmlns:adl="http://cygnets.co.uk/schemas/adl-1.2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Application Description Language framework adl2mssql.xsl (c) 2007 Cygnet Solutions Ltd Convert ADL to MS-SQL $Author: sb $ $Revision: 1.2 $ --> <xsl:output indent="no" encoding="UTF-8" method="text"/> <xsl:include href="base-type-include.xslt"/> <!-- The convention to use for naming auto-generated abstract primary keys. Known values are Id - the autogenerated primary key, if any, is called just 'Id' Name - the autogenerated primary key has the same name as the entity NameId - the name of the auto generated primary key is the name of the entity followed by 'Id' Name_Id - the name of the auto generated primary key is the name of the entity followed by '_Id' --> <xsl:param name="abstract-key-name-convention" select="Id"/> <xsl:param name="database"/> <!-- the name and version of the product being built --> <xsl:param name="product-version" select="'Application Description Language Framework'"/> <!-- define upper and lower case letters to enable case conversion --> <xsl:variable name="ucase">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable> <xsl:variable name="lcase">abcdefghijklmnopqrstuvwxyz</xsl:variable> <!-- define SQL keywords to police these out of field names --> <xsl:variable name="sqlkeywords-multiline"> ADD EXCEPT PERCENT ALL EXEC PLAN ALTER EXECUTE PRECISION AND EXISTS PRIMARY ANY EXIT PRINT AS FETCH PROC ASC FILE PROCEDURE AUTHORIZATION FILLFACTOR PUBLIC BACKUP FOR RAISERROR BEGIN FOREIGN READ BETWEEN FREETEXT READTEXT BREAK FREETEXTTABLE RECONFIGURE BROWSE FROM REFERENCES BULK FULL REPLICATION BY FUNCTION RESTORE CASCADE GOTO RESTRICT CASE GRANT RETURN CHECK GROUP REVOKE CHECKPOINT HAVING RIGHT CLOSE HOLDLOCK ROLLBACK CLUSTERED IDENTITY ROWCOUNT COALESCE IDENTITY_INSERT ROWGUIDCOL COLLATE IDENTITYCOL RULE COLUMN IF SAVE COMMIT IN SCHEMA COMPUTE INDEX SELECT CONSTRAINT INNER SESSION_USER CONTAINS INSERT SET CONTAINSTABLE INTERSECT SETUSER CONTINUE INTO SHUTDOWN CONVERT IS SOME CREATE JOIN STATISTICS CROSS KEY SYSTEM_USER CURRENT KILL TABLE CURRENT_DATE LEFT TEXTSIZE CURRENT_TIME LIKE THEN CURRENT_TIMESTAMP LINENO TO CURRENT_USER LOAD TOP CURSOR NATIONAL TRAN DATABASE NOCHECK TRANSACTION DBCC NONCLUSTERED TRIGGER DEALLOCATE NOT TRUNCATE DECLARE NULL TSEQUAL DEFAULT NULLIF UNION DELETE OF UNIQUE DENY OFF UPDATE DESC OFFSETS UPDATETEXT DISK ON USE DISTINCT OPEN USER DISTRIBUTED OPENDATASOURCE VALUES DOUBLE OPENQUERY VARYING DROP OPENROWSET VIEW DUMMY OPENXML WAITFOR DUMP OPTION WHEN ELSE OR WHERE END ORDER WHILE ERRLVL OUTER WITH ESCAPE OVER WRITETEXT </xsl:variable> <xsl:variable name="sqlkeywords" select="concat(' ', normalize-space($sqlkeywords-multiline), ' ')"/> <xsl:template match="adl:application"> ------------------------------------------------------------------------------------------------- -- -- <xsl:value-of select="$product-version"/> -- -- Database for application <xsl:value-of select="@name"/> version <xsl:value-of select="@version"/> -- Generated for MS-SQL 2000+ using adl2mssql.xslt <xsl:value-of select="substring('$Revision: 1.2 $', 12)"/> -- -- Code generator (c) 2007 Cygnet Solutions Ltd -- ------------------------------------------------------------------------------------------------- <xsl:if test="string-length( $database) > 0"> use <xsl:value-of select="$database"/>; </xsl:if> ------------------------------------------------------------------------------------------------- -- authentication roles ------------------------------------------------------------------------------------------------- <xsl:apply-templates select="adl:group"/> ------------------------------------------------------------------------------------------------- -- primary tables, views and permissions ------------------------------------------------------------------------------------------------- <xsl:apply-templates select="adl:entity" mode="table"/> ------------------------------------------------------------------------------------------------- -- link tables ------------------------------------------------------------------------------------------------- <xsl:apply-templates select="adl:entity" mode="links"/> ------------------------------------------------------------------------------------------------- -- primary referential integrity constraints ------------------------------------------------------------------------------------------------- <xsl:apply-templates select="adl:entity" mode="refinteg"/> ------------------------------------------------------------------------------------------------- -- end of file ------------------------------------------------------------------------------------------------- </xsl:template> <xsl:template match="adl:group"> execute sp_addrole @rolename = '<xsl:value-of select="@name"/>' GO </xsl:template> <!-- return the table name for the entity with this entity name --> <xsl:template name="tablename"> <xsl:param name="entityname"/> <xsl:choose> <xsl:when test="//adl:entity[@name=$entityname]/@table"> <xsl:value-of select="//adl:entity[@name=$entityname]/@table"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$entityname"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- generate a foreign key referential integrity check --> <xsl:template name="foreignkey"> <xsl:param name="nearside"/> <xsl:param name="farside"/> <xsl:param name="keyfield"/> <xsl:param name="ondelete" select="'NO ACTION'"/> <xsl:variable name="neartable"> <xsl:call-template name="tablename"> <xsl:with-param name="entityname" select="$nearside"/> </xsl:call-template> </xsl:variable> <xsl:variable name="fartable"> <xsl:call-template name="tablename"> <xsl:with-param name="entityname" select="$farside"/> </xsl:call-template> </xsl:variable> <!-- set up referential integrity constraints for primary tables --> ALTER TABLE "<xsl:value-of select="$neartable"/>" ADD FOREIGN KEY ( "<xsl:value-of select="$keyfield"/>") REFERENCES "<xsl:value-of select="$fartable"/>" ON DELETE <xsl:value-of select="$ondelete"/> GO </xsl:template> <!-- generate referential integrity constraints --> <xsl:template match="adl:entity" mode="refinteg"> <xsl:variable name="nearside" select="@name"/> <xsl:for-each select="descendant::adl:property[@type='entity']"> <xsl:variable name="farside" select="@entity"/> <xsl:variable name="keyfield"> <xsl:call-template name="property-column-name"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="//adl:entity[@name=$farside]//adl:property[@farkey=$keyfield and @entity=$nearside]"> <!-- there's a 'list' property pointing the other way; let it do the heavy hauling --> </xsl:when> <xsl:otherwise> <xsl:call-template name="foreignkey"> <xsl:with-param name="nearside" select="$nearside"/> <xsl:with-param name="farside" select="$farside"/> <xsl:with-param name="keyfield" select="$keyfield"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:for-each> <xsl:for-each select="descendant::adl:property[@type='list']"> <xsl:variable name="farkey"> <xsl:choose> <xsl:when test="@farkey"> <xsl:value-of select="@farkey"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="../@name"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:call-template name="foreignkey"> <xsl:with-param name="nearside" select="@entity"/> <xsl:with-param name="farside" select="../@name"/> <xsl:with-param name="keyfield" select="$farkey"/> <xsl:with-param name="ondelete"> <xsl:choose> <xsl:when test="@cascade='all'">CASCADE</xsl:when> <xsl:when test="@cascade='all-delete-orphan'">CASCADE</xsl:when> <xsl:when test="@cascade='delete'">CASCADE</xsl:when> <xsl:otherwise>NO ACTION</xsl:otherwise> </xsl:choose> </xsl:with-param> </xsl:call-template> </xsl:for-each> </xsl:template> <!-- don't generate foreign tables - although we will generate ref integ constraints for them --> <xsl:template match="adl:entity[@foreign='true']" mode="table"/> <xsl:template match="adl:entity" mode="table"> <xsl:variable name="table"> <xsl:call-template name="tablename"> <xsl:with-param name="entityname" select="@name"/> </xsl:call-template> </xsl:variable> ------------------------------------------------------------------------------------------------- -- primary table <xsl:value-of select="$table"/> ------------------------------------------------------------------------------------------------- CREATE TABLE "<xsl:value-of select="$table"/>" ( <xsl:for-each select="descendant::adl:property[not( @type='link' or @type = 'list' or @concrete='false')]"> <xsl:apply-templates select="."/> <xsl:if test="position() != last()">,</xsl:if> </xsl:for-each> <xsl:apply-templates select="adl:key"/> ) GO ---- permissions ------------------------------------------------------------------------------ <xsl:for-each select="adl:permission"> <xsl:call-template name="permission"> <xsl:with-param name="entity" select="ancestor::adl:entity"/> </xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template match="adl:key"> <xsl:if test="adl:property[not( @concrete='false')]"> , PRIMARY KEY( <xsl:for-each select="adl:property[not( @concrete='false')]">"<xsl:call-template name="property-column-name"> <xsl:with-param name="property" select="."/> </xsl:call-template>"<xsl:if test="position() != last()">, </xsl:if></xsl:for-each>) </xsl:if> </xsl:template> <xsl:template name="distinctfield"> <xsl:param name="table"/> <xsl:param name="alias"/> <!-- print the names of the distinguishing fields in this table, concatenating into a single string. --> <xsl:for-each select="/application/entity[@name=$table]"> <xsl:for-each select="property[@distinct='user' or @distinct='all']"> <xsl:choose> <xsl:when test="@type='entity'"> <xsl:call-template name="distinctfield"> <xsl:with-param name="table" select="@entity"/> <xsl:with-param name="alias" select="concat( $alias, '_', @name)"></xsl:with-param> </xsl:call-template> </xsl:when> <xsl:otherwise> "<xsl:value-of select="$alias"/>"."<xsl:value-of select="@name"/>"<xsl:if test="position() != last()"> + ' ' + </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:for-each> </xsl:template> <!-- fix up linking tables. Donoe after all primary tables have been created, because otherwise some links may fail --> <xsl:template match="adl:entity" mode="links"> <xsl:variable name="entityname" select="@name"/> <xsl:for-each select="adl:property[@type='link']"> <xsl:call-template name="linktable"> <xsl:with-param name="nearside" select="$entityname"/> </xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template name="permission"> <xsl:param name="entity"/> <!-- decode the permissions for a table --> <xsl:variable name="table"> <xsl:call-template name="tablename"> <xsl:with-param name="entityname" select="$entity/@name"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="@permission='read'"> GRANT SELECT ON "<xsl:value-of select="$table"/>" TO <xsl:value-of select="@group"/> </xsl:when> <xsl:when test="@permission='insert'"> GRANT INSERT ON "<xsl:value-of select="$table"/>" TO <xsl:value-of select="@group"/> </xsl:when> <xsl:when test="@permission='noedit'"> GRANT SELECT, INSERT ON "<xsl:value-of select="$table"/>" TO <xsl:value-of select="@group"/> </xsl:when> <xsl:when test="@permission='edit'"> GRANT SELECT, INSERT, UPDATE ON "<xsl:value-of select="$table"/>" TO <xsl:value-of select="@group"/> </xsl:when> <xsl:when test="@permission='all'"> GRANT SELECT, INSERT, UPDATE, DELETE ON "<xsl:value-of select="$table"/>" TO <xsl:value-of select="@group"/> </xsl:when> <xsl:otherwise> REVOKE ALL ON "<xsl:value-of select="$table"/>" FROM <xsl:value-of select="@group"/> </xsl:otherwise> </xsl:choose> <xsl:text> GO </xsl:text> </xsl:template> <!-- expects to be called in the context of an entity; probably should make this explicit. TODO: this is a mess; refactor. --> <xsl:template name="linktable"> <xsl:param name="nearside"/> <!-- This is tricky. For any many-to-many relationship between two entities, we only want to create one link table, even if (as should be) a property of type 'link' has been declared at both ends --> <xsl:variable name="farside"> <xsl:choose> <xsl:when test="@entity = $nearside"> <xsl:value-of select="concat( @entity, '_1')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="@entity"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="comparison"> <xsl:call-template name="stringcompare"> <xsl:with-param name="node1" select="$nearside"/> <xsl:with-param name="node2" select="@entity"/> </xsl:call-template> </xsl:variable> <xsl:variable name="farentityname" select="@entity"/> <xsl:variable name="farentity" select="//adl:entity[@name=$farentityname]"/> <xsl:variable name="myresponsibility"> <xsl:choose> <!-- if we could use the compare( string, string) function this would be a lot simpler, but unfortunately that's in XSL 2.0, and neither NAnt nor Visual Studio can manage that --> <!-- if the link is back to me, then obviously I'm responsible --> <xsl:when test="$comparison = 0">true</xsl:when> <!-- generally, the entity whose name is later in the default collating sequence shall not be responsible. --> <xsl:when test="$comparison = -1">true</xsl:when> <!-- However if the one that is earlier doesn't have a 'link' property for this join, however, then later end will have to do it --> <xsl:when test="$comparison = 1"> <xsl:choose> <!-- the far side is doing it... --> <xsl:when test="$farentity/adl:property[@type='link' and @entity=$nearside]">false</xsl:when> <xsl:otherwise>true</xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise>false</xsl:otherwise> </xsl:choose> </xsl:variable> <!-- Problems with responsibility for generating link tables: --> -- Problems with responsibility for generating link tables: -- @entity = <xsl:value-of select="@entity"/> -- $nearside = <xsl:value-of select="$nearside"/> -- $farside = <xsl:value-of select="$farside"/> -- farlink = <xsl:value-of select="$farentity/adl:property[@type='link' and @entity=$nearside]/@name"/> -- comparison = '<xsl:value-of select="$comparison"/>' -- my responsibility = <xsl:value-of select="$myresponsibility"/> <xsl:variable name="linktablename"> <xsl:choose> <xsl:when test="$comparison =-1"> <xsl:value-of select="concat( 'LN_', $nearside, '_', @entity)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="concat( 'LN_', @entity, '_', $nearside)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="$myresponsibility='true'"> <!-- create a linking table --> ------------------------------------------------------------------------------------------------- -- link table joining <xsl:value-of select="$nearside"/> with <xsl:value-of select="@entity"/> ------------------------------------------------------------------------------------------------- CREATE TABLE "<xsl:value-of select="$linktablename"/>" ( "<xsl:value-of select="concat( $nearside, 'Link')"/>" <xsl:call-template name="sql-type"> <xsl:with-param name="property" select="//adl:entity[@name=$nearside]/adl:key/adl:property[position()=1]"/> </xsl:call-template> NOT NULL, "<xsl:value-of select="concat( $farside, 'Link')"/>" <xsl:call-template name="sql-type"> <xsl:with-param name="property" select="$farentity/adl:key/adl:property[position()=1]"/> </xsl:call-template> NOT NULL ) GO <xsl:text> </xsl:text> ---- permissions ------------------------------------------------------------------------------ <!-- only two levels of permission really matter for a link table. If you can read both of the parent tables, then you can read the link table. If you can edit either of the parent tables, then you need full CRUD permissions on the link table. --> <xsl:for-each select="//adl:group"> <xsl:variable name="groupname" select="@name"/> <xsl:choose> <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='all']"> GRANT SELECT,INSERT,UPDATE,DELETE ON <xsl:value-of select="$linktablename"/> TO <xsl:value-of select="$groupname"/> </xsl:when> <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='edit']"> GRANT SELECT,INSERT,UPDATE,DELETE ON <xsl:value-of select="$linktablename"/> TO <xsl:value-of select="$groupname"/> </xsl:when> <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='all']"> GRANT SELECT,INSERT,UPDATE,DELETE ON <xsl:value-of select="$linktablename"/> TO <xsl:value-of select="$groupname"/> </xsl:when> <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='edit']"> GRANT SELECT,INSERT,UPDATE,DELETE ON <xsl:value-of select="$linktablename"/> TO <xsl:value-of select="$groupname"/> </xsl:when> <xsl:when test="//adl:entity[@name=$nearside]/adl:permission[@group=$groupname and @permission='none']"> REVOKE ALL ON <xsl:value-of select="$linktablename"/> FROM <xsl:value-of select="$groupname"/> </xsl:when> <xsl:when test="//adl:entity[@name=$farside]/adl:permission[@group=$groupname and @permission='none']"> REVOKE ALL ON <xsl:value-of select="$linktablename"/> FROM <xsl:value-of select="$groupname"/> </xsl:when> <xsl:otherwise> GRANT SELECT ON <xsl:value-of select="$linktablename"/> TO <xsl:value-of select="$groupname"/> </xsl:otherwise> </xsl:choose> GO </xsl:for-each> ---- referential integrity -------------------------------------------------------------------- <xsl:variable name="neartable"> <xsl:call-template name="tablename"> <xsl:with-param name="entityname" select="$nearside"/> </xsl:call-template> </xsl:variable> <xsl:variable name="fartable"> <xsl:call-template name="tablename"> <xsl:with-param name="entityname" select="$farentityname"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$nearside=@entity"> <xsl:call-template name="foreignkey"> <xsl:with-param name="nearside" select="$linktablename"/> <xsl:with-param name="farside" select="$neartable"/> <xsl:with-param name="keyfield" select="concat( $nearside, 'Link')"/> <xsl:with-param name="ondelete" select="'NO ACTION'"/> </xsl:call-template> <xsl:call-template name="foreignkey"> <xsl:with-param name="nearside" select="$linktablename"/> <xsl:with-param name="farside" select="$fartable"/> <xsl:with-param name="keyfield" select="concat( $farside, 'Link')"/> <xsl:with-param name="ondelete" select="'CASCADE'"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="foreignkey"> <xsl:with-param name="nearside" select="$linktablename"/> <xsl:with-param name="farside" select="$neartable"/> <xsl:with-param name="keyfield" select="concat( $nearside, 'Id')"/> <xsl:with-param name="ondelete" select="'CASCADE'"/> </xsl:call-template> <xsl:call-template name="foreignkey"> <xsl:with-param name="nearside" select="$linktablename"/> <xsl:with-param name="farside" select="$fartable"/> <xsl:with-param name="keyfield" select="concat( @entity, 'Id')"/> <xsl:with-param name="ondelete" select="'CASCADE'"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> -- Suppressing generation of <xsl:value-of select="$linktablename"/>, as it is not my responsibility </xsl:otherwise> </xsl:choose> <xsl:if test="myresponsibility='true'"> </xsl:if> </xsl:template> <xsl:template match="adl:property[@type='list']"> -- Suppressing output of property <xsl:value-of select="@name"/>, -- as it is the 'one' end of a one-to-many relationship </xsl:template> <xsl:template match="adl:generator[@action='native']"> IDENTITY( 1, 1) </xsl:template> <xsl:template match="adl:generator"/> <!-- the grand unified property handler, using the sql-type template to generate the correct types for each field --> <xsl:template match="adl:property"> <xsl:variable name="column"> <xsl:call-template name="property-column-name"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:variable name="type"> <xsl:call-template name="sql-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:variable name="base-type"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:variable name="generator"> <xsl:apply-templates select="adl:generator"/> </xsl:variable> "<xsl:value-of select="$column"/>" <xsl:value-of select="concat( normalize-space( $type), ' ', normalize-space( $generator))"/><xsl:if test="@required='true'"> NOT NULL</xsl:if><xsl:if test="string(@default)"> DEFAULT <xsl:choose> <xsl:when test="$base-type = 'integer' or $base-type = 'real' or $base-type = 'money'"> <xsl:value-of select="@default"/> </xsl:when> <xsl:otherwise>'<xsl:value-of select="@default"/>'</xsl:otherwise> </xsl:choose> </xsl:if> </xsl:template> <!-- properties of type 'entity' are supposed to be being handled by the grand unified property handler. Unfortunately it gets them wrong and I'm not sure why. So temporarily this special case template fixes the problem. TODO: work out what's wrong with the grand unified version --> <xsl:template match="adl:property[@type='entity']"> <xsl:variable name="column"> <xsl:call-template name="property-column-name"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:variable name="type"> <xsl:call-template name="sql-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> "<xsl:value-of select="$column"/>" <xsl:value-of select="$type"/><xsl:if test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if test="@required='true'"> NOT NULL</xsl:if> </xsl:template> <!-- consistent, repeatable way of getting the column name for a given property --> <xsl:template name="property-column-name"> <!-- a property element --> <xsl:param name="property"/> <xsl:variable name="unescaped"> <xsl:choose> <xsl:when test="$property/@column"> <xsl:value-of select="$property/@column"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$property/@name"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="contains( $sqlkeywords, concat(' ', translate( $unescaped, $lcase, $ucase),' '))"> <xsl:value-of select="concat( '[', $unescaped, ']')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$unescaped"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="primary-key-name"> <xsl:param name="entityname"/> <xsl:choose> <xsl:when test="//adl:entity[@name=$entityname]/@natural-key"> <xsl:value-of select="//adl:entity[@name=$entityname]/@natural-key"/> </xsl:when> <xsl:when test="//adl:entity[@name=$entityname]/key"> <xsl:choose> <xsl:when test="count(//adl:entity[@name=$entityname]/adl:key/adl:property) > 1"> <xsl:message terminate="no"> ADL: WARNING: entity '<xsl:value-of select="$entityname"/>' has a compound primary key; adl2mssql is not yet clever enough to generate appropriate code </xsl:message> </xsl:when> <xsl:otherwise> <xsl:value-of select="//adl:entity[@name=$entityname]/adl:key/adl:property[position()=1]"/> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <xsl:choose> <xsl:when test="$abstract-key-name-convention='Name'"> <xsl:value-of select="@name"/> </xsl:when> <xsl:when test="$abstract-key-name-convention = 'NameId'"> <xsl:value-of select="concat( $entityname, 'Id')"/> </xsl:when> <xsl:when test="$abstract-key-name-convention = 'Name_Id'"> <xsl:value-of select="concat( $entityname, '_Id')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="'Id'"/> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- return the SQL type of the property which is passed as a parameter --> <xsl:template name="sql-type"> <xsl:param name="property"/> <xsl:variable name="base-type"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> <xsl:variable name="base-size"> <xsl:call-template name="base-size"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$base-type = 'entity'"> <xsl:variable name="entity" select="$property/@entity"/> <xsl:choose> <xsl:when test="//adl:entity[@name=$entity]"> <xsl:choose> <xsl:when test="//adl:entity[@name=$entity]/adl:key/adl:property"> <xsl:call-template name="sql-type"> <xsl:with-param name="property" select="//adl:entity[@name=$entity]/adl:key/adl:property[position()=1]"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes"> ADL: ERROR: property '<xsl:value-of select="$property/@name"/>' refers to entity '<xsl:value-of select="$property/@entity"/>', but this entity has no key. </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes"> ADL: ERROR: property '<xsl:value-of select="$property/@name"/>' refers to entity '<xsl:value-of select="$property/@entity"/>', but no such entity exists. </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:when test="$base-type = 'date'">DATETIME</xsl:when> <xsl:when test="$base-type = 'time'">DATETIME</xsl:when> <!-- TODO: if the type was 'defined' then the size should probably come from the typedef --> <xsl:when test="$base-type = 'string'">VARCHAR( <xsl:value-of select="$base-size"/>)</xsl:when> <xsl:when test="$base-type = 'text'">TEXT</xsl:when> <xsl:when test="$base-type = 'boolean'">BIT</xsl:when> <xsl:when test="$base-type = 'timestamp'">TIMESTAMP</xsl:when> <xsl:when test="$base-type = 'integer'">INT</xsl:when> <xsl:when test="$base-type = 'real'">DOUBLE PRECISION</xsl:when> <xsl:when test="$base-type = 'money'">DECIMAL</xsl:when> <xsl:otherwise>[sql:unknown? [<xsl:value-of select="$base-type"/>]]</xsl:otherwise> </xsl:choose> </xsl:template> <!-- horrible, horrible hackery. Compare two strings and return * 0 if they are identical, * -1 if the first is earlier in the default collating sequence, * 1 if the first is later. In XSL 2.0 this could be done using the compare(string, string) function. --> <xsl:template name="stringcompare"> <xsl:param name="node1"/> <xsl:param name="node2"/> <xsl:choose> <xsl:when test="string($node1)=string($node2)"> <xsl:text>0</xsl:text> </xsl:when> <xsl:otherwise> <xsl:for-each select="$node1 | $node2"> <xsl:sort select="."/> <xsl:if test="position()=1"> <xsl:choose> <xsl:when test="string(.) = string($node1)"> <xsl:text>-1</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>1</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:for-each> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>