[ 
https://issues.apache.org/jira/browse/TORQUE-369?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18097467#comment-18097467
 ] 

Max Philipp Wriedt commented on TORQUE-369:
-------------------------------------------

Attached two patches against trunk (r1936339): one with the fix in 
{{LoadExternalSchemaTransformer}} and {{IncludeSchemaTransformer}}, one with 
the tests.

[~gk] thanks, your analysis pointed at the right spot. I didn't use the 
database name as the identity though. The name attribute is optional (the first 
schema in my example above doesn't have one at all) and it doesn't have to be 
unique across files, since it refers to the database handle and not to the 
file. So I went with the canonical path of the schema file instead. That also 
means the {{intermediaries}} list isn't needed and the {{Database}} model can 
stay as it is.

I ended up treating the two transformers differently, because a cycle doesn't 
mean the same thing for both.

{{external-schema}} is a reference. The external file becomes its own 
{{Database}}, only allTables/allViews get aggregated, and every schema is 
generated into its own output. So a back reference is a valid thing to do, and 
the patch just skips a file it has already loaded.

{{include-schema}} inlines instead. If two files include each other, the result 
depends on which file you start the generation from, so the patch treats that 
as an error:

{noformat}
Cyclic include-schema reference: a-schema.xml -> b-schema.xml -> a-schema.xml.
A schema file must not include itself, directly or indirectly.
{noformat}

To tell a cycle from a diamond I needed a recursion stack next to the set of 
files already seen.

While writing the tests I noticed that include-schema also duplicates content 
without any cycle being involved: if A includes B and C and both of them 
include D, then D is inlined twice and you get duplicate CREATE TABLE 
statements. The patch inlines it only once. Strictly speaking that isn't this 
issue though, should I split it out?

One thing to watch out for: the visited set is created per invocation and 
passed down the recursion instead of living in a field. The transformers are 
held in static fields by {{SQLTransformer}}, {{SQLModelTransformer}} and 
{{OMTransformer}}, so a field would leak between generation runs, similar to 
TORQUE-372.

The tests cover all four recursion sites (both overloads of both transformers). 
The interesting one is testCyclicExternalSchemaIsLoadedOnce: both ddl scripts 
are generated and the foreign keys across the cyclic reference still resolve, 
so the external schema is still loaded, just not endlessly. The existing suite 
is unchanged and green.

One thing I left alone: all four methods take the base directory for relative 
paths from {{controllerState.getSourceFile()}}, which is the top level source 
file and not the one currently being processed. Nested references from a 
subdirectory resolve against the wrong directory because of that. It doesn't 
show up today since all test schemata sit flat in one directory. If I am not 
wrong that deserves its own issue rather than being bundled in here.


> LoadExternalSchemaTransformer recursively includes when cross-referencing
> -------------------------------------------------------------------------
>
>                 Key: TORQUE-369
>                 URL: https://issues.apache.org/jira/browse/TORQUE-369
>             Project: Torque
>          Issue Type: Bug
>          Components: Templates
>    Affects Versions: 5.1, 6.0
>            Reporter: Max Philipp Wriedt
>            Assignee: Max Philipp Wriedt
>            Priority: Major
>
> When referencing an external schema (to use foreign key references in another 
> schema definition) and back referencing to its origin, we get an infinite 
> recursion.
> Affects: 
> org.apache.torque.templates.transformer.LoadExternalSchemaTransformer.transform()
> Example:
> First Schema:
> {code:java}
> <?xml version="1.0" encoding="UTF-8" ?>
> <database>
>     <external-schema filename=secondary-schema.xml" />
>     <table name="test" javaName="Test">
>         <column name="Id" javaName="Id" required="true" type="INTEGER" 
> primaryKey="true"/>
>         <column name="Name" javaName="Name" required="true" type="VARCHAR" 
> size="5"/>
>         <column name="foreign-key" javaName="ForeignKey" required="true" 
> type="INTEGER" size="2"/>
>         <!-- define foreign key to secondary scheme!-->
>     </table>
> </database>{code}
> Second Schema: 
> {code:java}
> <?xml version="1.0" encoding="UTF-8" ?>
> <database
>     xmlns="http://db.apache.org/torque/5.0/templates/database";
>     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>     xsi:schemaLocation="http://db.apache.org/torque/5.0/templates/database
>     
> https://db.apache.org/torque/torque-5.0/documentation/orm-reference/database-5-0-strict.xsd";
>  name="test" defaultIdMethod="native" defaultJavaType="object">
>     <external-schema filename=first-schema.xml" />
>     <table name="foreign-key" javaName="Test">
>         <column name="Id" javaName="Id" required="true" type="INTEGER" 
> primaryKey="true"/>
>         <column name="Name" javaName="Name" required="true" type="VARCHAR" 
> size="5"/>
>     </table>
>     <table name="test2" javaName="Test2">
>         <column name="Id" javaName="Id" required="true" type="INTEGER" 
> primaryKey="true"/>
>         <column name="Name" javaName="Name" required="true" type="VARCHAR" 
> size="5"/>
>         <column name="foreign-key" javaName="ForeignKey" required="true" 
> type="INTEGER" size="2"/>
>         <!-- define foreign key to first scheme!-->
>     </table>
> </database>{code}
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to