441 lines
20 KiB
HTML
Executable file
441 lines
20 KiB
HTML
Executable file
<?xml version="1.0"?>
|
|
<xsl:stylesheet version="1.0"
|
|
xmlns="http://bowyer.journeyman.cc/adl/1.4/"
|
|
xmlns:adl="http://bowyer.journeyman.cc/adl/1.4/"
|
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
|
<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
|
|
<!-- -->
|
|
<!-- adl2psql.xsl -->
|
|
<!-- -->
|
|
<!-- Purpose: -->
|
|
<!-- XSL stylesheet to generate Postgresql [7|8] from ADL. -->
|
|
<!-- -->
|
|
<!-- Author: Simon Brooke <simon@weft.co.uk> -->
|
|
<!-- Created: 24th January 2006 -->
|
|
<!-- Copyright: (c) 2006 Simon Brooke. -->
|
|
<!-- -->
|
|
<!-- This file is presently not up to date with changes in ADL -->
|
|
<!-- -->
|
|
<!-- :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: -->
|
|
|
|
<!--
|
|
JACQUARD 2 APPLICATION DESCRIPTION LANGUAGE FRAMEWORK
|
|
|
|
$Revision: 1.3 $
|
|
|
|
NOTES:
|
|
|
|
Needless to say this is all hugely experimental.
|
|
|
|
Running the primary key field last is a hack which gets around the fact that
|
|
otherwise it's extremely complex to lose the comma after the last field.
|
|
Ideally where there is one 'distinct="system"' property of an entity that
|
|
should be the primary key and perhaps we'll achieve that in the long run...
|
|
|
|
Still to do:
|
|
|
|
References in convenience views for fields which have their reference value at
|
|
two removes (i.e. the 'distinguish' mechanism in ADL
|
|
-->
|
|
|
|
<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"/>
|
|
|
|
<!-- the convention to use for fieldnames in link tables:
|
|
Name - the name of the foreign key is the same as the name of the table linked to
|
|
NameId - the name of the foreign key is the same as the name of the table linked to, followed by 'Id'
|
|
Name_Id - the name of the foreign key is the same as the name of the table linked to, followed by '_Id'
|
|
Name_Link - the name of the foreign key is the same as the name of the table linked to, followed by '_Link'
|
|
-->
|
|
<xsl:param name="linktable-field-name-convention" select="Name"/>
|
|
|
|
<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 PostgreSQL [7|8] using adl2psql.xsl $Revision: 1.3 $
|
|
--
|
|
-- <xsl:value-of select="@revision"/>
|
|
--
|
|
-- Code generator (c) 2006 Simon Brooke [simon@weft.co.uk]
|
|
-- http://www.weft.co.uk/library/jacquard/
|
|
--
|
|
-------------------------------------------------------------------------------------------------
|
|
|
|
<xsl:if test="string-length( $database) > 0">
|
|
use "<xsl:value-of select="$database"/>";
|
|
</xsl:if>
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- authentication roles
|
|
-------------------------------------------------------------------------------------------------
|
|
<xsl:apply-templates select="adl:group"/>
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- tables, views and permissions
|
|
-------------------------------------------------------------------------------------------------
|
|
<xsl:apply-templates select="adl:entity"/>
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- referential integrity constraints
|
|
-------------------------------------------------------------------------------------------------
|
|
<xsl:for-each select="adl:entity">
|
|
<xsl:variable name="nearside" select="@name"/>
|
|
<xsl:for-each select="adl:property[@type='entity']">
|
|
<xsl:call-template name="referentialintegrity">
|
|
<xsl:with-param name="nearside" select="$nearside"/>
|
|
</xsl:call-template>
|
|
|
|
</xsl:for-each>
|
|
<xsl:for-each select="adl:property[@type='link']">
|
|
<xsl:call-template name="linkintegrity">
|
|
<xsl:with-param name="nearside" select="$nearside"/>
|
|
</xsl:call-template>
|
|
|
|
</xsl:for-each>
|
|
</xsl:for-each>
|
|
-------------------------------------------------------------------------------------------------
|
|
-- end of file
|
|
-------------------------------------------------------------------------------------------------
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:documentation">
|
|
/* <xsl:apply-templates/> */
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:group">
|
|
-------------------------------------------------------------------------------------------------
|
|
-- security group <xsl:value-of select="@name"/>
|
|
-------------------------------------------------------------------------------------------------
|
|
<xsl:apply-templates select="adl:documentation"/>
|
|
CREATE GROUP <xsl:value-of select="@name"/>;
|
|
</xsl:template>
|
|
|
|
|
|
<xsl:template name="referentialintegrity">
|
|
<xsl:param name="nearside"/>
|
|
<!-- set up referential integrity constraints for primary tables -->
|
|
ALTER TABLE <xsl:value-of select="$nearside"/> ADD CONSTRAINT ri_<xsl:value-of select="$nearside"/><xsl:value-of select="concat( '_', @name)"/>
|
|
FOREIGN KEY ( <xsl:value-of select="@name"/>) REFERENCES <xsl:value-of select="@entity"/> ON DELETE NO ACTION;
|
|
</xsl:template>
|
|
|
|
|
|
<xsl:template name="linkintegrity">
|
|
<xsl:param name="nearside"/>
|
|
<!-- set up referential integrity constraints for link tables -->
|
|
ALTER TABLE ln_<xsl:value-of select="$nearside"/>_<xsl:value-of select="@entity"/>
|
|
ADD CONSTRAINT ri_<xsl:value-of select="$nearside"/>_<xsl:value-of select="@entity"/>_<xsl:value-of select="$nearside"/>_id
|
|
FOREIGN KEY ( <xsl:value-of select="$nearside"/>_id) REFERENCES <xsl:value-of select="$nearside"/> ON DELETE CASCADE;
|
|
|
|
ALTER TABLE ln_<xsl:value-of select="$nearside"/>_<xsl:value-of select="@entity"/>
|
|
ADD CONSTRAINT ri_<xsl:value-of select="$nearside"/>_<xsl:value-of select="@entity"/>_<xsl:value-of select="@entity"/>_id
|
|
FOREIGN KEY ( <xsl:value-of select="@entity"/>_id) REFERENCES <xsl:value-of select="@entity"/> ON DELETE CASCADE;
|
|
|
|
</xsl:template>
|
|
|
|
|
|
<xsl:template match="adl:entity">
|
|
<xsl:variable name="table" select="@name"/>
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- primary table <xsl:value-of select="@name"/>
|
|
-------------------------------------------------------------------------------------------------
|
|
CREATE TABLE <xsl:value-of select="@name"/>
|
|
(
|
|
<xsl:for-each select="descendant::adl:property[@type!='link']">
|
|
<xsl:apply-templates select="."/><xsl:choose>
|
|
<xsl:when test="position() = last()"/>
|
|
<xsl:otherwise>,<xsl:text>
|
|
</xsl:text></xsl:otherwise>
|
|
</xsl:choose>
|
|
</xsl:for-each>
|
|
);
|
|
|
|
---- permissions ------------------------------------------------------------------------------
|
|
<xsl:for-each select="adl:permission">
|
|
<xsl:call-template name="permission">
|
|
<xsl:with-param name="table" select="$table"/>
|
|
</xsl:call-template>
|
|
</xsl:for-each>
|
|
-------------------------------------------------------------------------------------------------
|
|
-- convenience view lv<xsl:value-of select="concat( '_', @name)"/> for lists
|
|
-------------------------------------------------------------------------------------------------
|
|
CREATE VIEW lv<xsl:value-of select="concat( '_', @name)"/> AS
|
|
SELECT <xsl:for-each select="adl:property[@type!='link']">
|
|
<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="@name"/>
|
|
</xsl:call-template> AS <xsl:value-of select="@name"/>
|
|
</xsl:when>
|
|
<xsl:otherwise><xsl:value-of select="$table"/>.<xsl:value-of select="@name"/>
|
|
</xsl:otherwise>
|
|
</xsl:choose><xsl:choose>
|
|
<xsl:when test="position() = last()"></xsl:when>
|
|
<xsl:otherwise>,
|
|
</xsl:otherwise>
|
|
</xsl:choose>
|
|
</xsl:for-each>
|
|
FROM <xsl:value-of select="@name"/>
|
|
<xsl:for-each select="adl:property[@type='entity']">, <xsl:value-of select="@entity"/> AS <xsl:value-of select="@name"/></xsl:for-each>
|
|
<xsl:text>
|
|
</xsl:text>
|
|
<xsl:for-each select="adl:property[@type='entity']">
|
|
<xsl:choose>
|
|
<xsl:when test="position() = 1">WHERE </xsl:when>
|
|
<xsl:otherwise>AND </xsl:otherwise>
|
|
</xsl:choose><xsl:value-of select="$table"/>.<xsl:value-of
|
|
select="@name"/> = <xsl:value-of select="@name"/>.<xsl:value-of select="@entity"/>_id
|
|
</xsl:for-each>;
|
|
|
|
---- permissions ------------------------------------------------------------------------------
|
|
<xsl:for-each select="adl:permission">
|
|
<xsl:call-template name="viewpermission">
|
|
<xsl:with-param name="table" select="$table"/>
|
|
</xsl:call-template>
|
|
</xsl:for-each>
|
|
|
|
<!-- link tables -->
|
|
<xsl:for-each select="adl:property[@type='link']">
|
|
<xsl:call-template name="linktable">
|
|
<xsl:with-param name="nearside" select="$table"/>
|
|
</xsl:call-template>
|
|
---- permissions ------------------------------------------------------------------------------
|
|
<xsl:variable name="farside" select="@entity"/>
|
|
<xsl:for-each select="../permission">
|
|
<xsl:call-template name="permission">
|
|
<xsl:with-param name="table">ln_<xsl:value-of select="$table"/>_<xsl:value-of select="$farside"/></xsl:with-param>
|
|
</xsl:call-template>
|
|
</xsl:for-each>
|
|
</xsl:for-each>
|
|
|
|
</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>
|
|
|
|
<xsl:template name="permission">
|
|
<xsl:param name="table"/>
|
|
<!-- decode the permissions for a table -->
|
|
<xsl:choose>
|
|
<xsl:when test="@permission='read'">GRANT SELECT ON <xsl:value-of
|
|
select="$table"/> TO GROUP <xsl:value-of select="@group"/>;</xsl:when>
|
|
<xsl:when test="@permission='insert'">GRANT INSERT ON <xsl:value-of
|
|
select="$table"/> TO GROUP <xsl:value-of select="@group"/>;</xsl:when>
|
|
<xsl:when test="@permission='noedit'">GRANT SELECT, INSERT ON <xsl:value-of
|
|
select="$table"/> TO GROUP <xsl:value-of select="@group"/>;</xsl:when>
|
|
<xsl:when test="@permission='edit'">GRANT SELECT, INSERT, UPDATE ON <xsl:value-of
|
|
select="$table"/> TO GROUP <xsl:value-of select="@group"/>;</xsl:when>
|
|
<xsl:when test="@permission='all'">GRANT SELECT, INSERT, UPDATE, DELETE ON <xsl:value-of
|
|
select="$table"/> TO GROUP <xsl:value-of select="@group"/>;</xsl:when>
|
|
<xsl:otherwise>REVOKE ALL ON <xsl:value-of
|
|
select="$table"/> FROM GROUP <xsl:value-of select="@group"/>;</xsl:otherwise>
|
|
</xsl:choose>
|
|
<xsl:text>
|
|
|
|
</xsl:text>
|
|
</xsl:template>
|
|
|
|
<xsl:template name="viewpermission">
|
|
<xsl:param name="table"/>
|
|
<!-- decode the permissions for a convenience view -->
|
|
<xsl:choose>
|
|
<xsl:when test="@permission='none'">REVOKE ALL ON lv_<xsl:value-of
|
|
select="$table"/> FROM GROUP <xsl:value-of select="@group"/>;</xsl:when>
|
|
<xsl:when test="@permission='insert'">REVOKE ALL ON lv_<xsl:value-of
|
|
select="$table"/> FROM GROUP <xsl:value-of select="@group"/>;</xsl:when>
|
|
<xsl:otherwise>GRANT SELECT ON lv_<xsl:value-of
|
|
select="$table"/> TO GROUP <xsl:value-of select="@group"/>;</xsl:otherwise>
|
|
</xsl:choose>
|
|
<xsl:text>
|
|
|
|
</xsl:text>
|
|
</xsl:template>
|
|
|
|
|
|
<xsl:template name="linktable">
|
|
<xsl:param name="nearside"/>
|
|
<xsl:variable name="farside">
|
|
<xsl:choose>
|
|
<xsl:when test="@entity = $nearside"><xsl:value-of select="@entity"/>_1</xsl:when>
|
|
<xsl:otherwise>
|
|
<xsl:value-of select="@entity"/>
|
|
</xsl:otherwise>
|
|
</xsl:choose>
|
|
</xsl:variable>
|
|
<!-- create a linking table -->
|
|
|
|
-------------------------------------------------------------------------------------------------
|
|
-- link table joining <xsl:value-of select="$nearside"/> with <xsl:value-of select="@entity"/>
|
|
-------------------------------------------------------------------------------------------------
|
|
CREATE TABLE ln_<xsl:value-of select="$nearside"/>_<xsl:value-of select="@entity"/>
|
|
(
|
|
<xsl:value-of select="$nearside"/>_id INT NOT NULL,
|
|
<xsl:value-of select="$farside"/>_id INT NOT NULL,
|
|
);
|
|
<xsl:text>
|
|
|
|
</xsl:text>
|
|
<!-- TODO: permissions for link tables! -->
|
|
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:property[@type='entity']">
|
|
<xsl:value-of select="@name"/> INT<xsl:if
|
|
test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if
|
|
test="@required='true'"> NOT NULL</xsl:if>
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:property[@type='defined']">
|
|
<xsl:variable name="name"><xsl:value-of select="@definition"/></xsl:variable>
|
|
<xsl:variable name="definitiontype"><xsl:value-of select="/application/definition[@name=$name]/@type"/></xsl:variable>
|
|
<xsl:value-of select="@name"/><xsl:text> </xsl:text><xsl:choose>
|
|
<xsl:when test="$definitiontype='string'">VARCHAR( <xsl:value-of
|
|
select="/application/definition[@name=$name]/@size"/>)</xsl:when>
|
|
<xsl:when test="$definitiontype='integer'">INT</xsl:when>
|
|
<xsl:when test="$definitiontype='real'">DOUBLE PRECISION</xsl:when>
|
|
<xsl:otherwise><xsl:value-of select="$definitiontype"/></xsl:otherwise>
|
|
</xsl:choose><xsl:if
|
|
test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose>
|
|
<xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when>
|
|
<xsl:when test="@required='true'"> NOT NULL</xsl:when>
|
|
</xsl:choose>
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:property[@type='string']">
|
|
<xsl:value-of select="@name"/> VARCHAR( <xsl:value-of select="@size"/>)<xsl:if
|
|
test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose>
|
|
<xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when>
|
|
<xsl:when test="@required='true'"> NOT NULL</xsl:when>
|
|
</xsl:choose>
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:property[@type='integer']">
|
|
<xsl:value-of select="@name"/> INT<xsl:if
|
|
test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose>
|
|
<xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when>
|
|
<xsl:when test="@required='true'"> NOT NULL</xsl:when>
|
|
</xsl:choose>
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:property[@type='real']">
|
|
<xsl:value-of select="@name"/> DOUBLE PRECISION<xsl:if
|
|
test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:if
|
|
test="@required='true'"> NOT NULL</xsl:if>
|
|
</xsl:template>
|
|
|
|
<xsl:template match="adl:property">
|
|
<xsl:value-of select="@name"/> <xsl:text> </xsl:text><xsl:value-of select="@type"/><xsl:if
|
|
test="string(@default)"> DEFAULT <xsl:value-of select="@default"/></xsl:if><xsl:choose>
|
|
<xsl:when test="parent::adl:key"> NOT NULL PRIMARY KEY</xsl:when>
|
|
<xsl:when test="@required='true'"> NOT NULL</xsl:when>
|
|
</xsl:choose>
|
|
</xsl:template>
|
|
|
|
</xsl:stylesheet>
|