[jira] [Commented] (TORQUE-369) LoadExternalSchemaTransformer recursively includes when cross-referencing

"Max Philipp Wriedt (Jira)" <[email protected]> Sun, 19 Jul 2026 23:47:00 +0000 (UTC)
Newsgroups gmane.comp.jakarta.turbine.torque.devel
Message-ID <[email protected]>
    [ https://issues.apache.org/jira/browse/TORQUE-369?page=3Dcom.atlassian=
.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=3D1809=
7467#comment-18097467 ]=20

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

Attached two patches against trunk (r1936339): one with the fix in {{LoadEx=
ternalSchemaTransformer}} and {{IncludeSchemaTransformer}}, one with the te=
sts.

[~gk] thanks, your analysis pointed at the right spot. I didn't use the dat=
abase name as the identity though. The name attribute is optional (the firs=
t schema in my example above doesn't have one at all) and it doesn't have t=
o 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. Th=
at 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 {{Dat=
abase}}, only allTables/allViews get aggregated, and every schema is genera=
ted into its own output. So a back reference is a valid thing to do, and th=
e patch just skips a file it has already loaded.

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

{noformat}
Cyclic include-schema reference: a-schema.xml -> b-schema.xml -> a-schema.x=
ml.
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 o=
f files already seen.

While writing the tests I noticed that include-schema also duplicates conte=
nt 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 stat=
ements. The patch inlines it only once. Strictly speaking that isn't this i=
ssue though, should I split it out?

One thing to watch out for: the visited set is created per invocation and p=
assed 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 transforme=
rs). The interesting one is testCyclicExternalSchemaIsLoadedOnce: both ddl =
scripts are generated and the foreign keys across the cyclic reference stil=
l 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 relati=
ve paths from {{controllerState.getSourceFile()}}, which is the top level s=
ource file and not the one currently being processed. Nested references fro=
m a subdirectory resolve against the wrong directory because of that. It do=
esn'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 ano=
ther schema definition) and back referencing to its origin, we get an infin=
ite recursion.
> Affects: org.apache.torque.templates.transformer.LoadExternalSchemaTransf=
ormer.transform()
> Example:
> First Schema:
> {code:java}
> <?xml version=3D"1.0" encoding=3D"UTF-8" ?>
> <database>
>     <external-schema filename=3Dsecondary-schema.xml" />
>     <table name=3D"test" javaName=3D"Test">
>         <column name=3D"Id" javaName=3D"Id" required=3D"true" type=3D"INT=
EGER" primaryKey=3D"true"/>
>         <column name=3D"Name" javaName=3D"Name" required=3D"true" type=3D=
"VARCHAR" size=3D"5"/>
>         <column name=3D"foreign-key" javaName=3D"ForeignKey" required=3D"=
true" type=3D"INTEGER" size=3D"2"/>
>         <!-- define foreign key to secondary scheme!-->
>     </table>
> </database>{code}
> Second Schema:=C2=A0
> {code:java}
> <?xml version=3D"1.0" encoding=3D"UTF-8" ?>
> <database
>     xmlns=3D"http://db.apache.org/torque/5.0/templates/database"
>     xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance"
>     xsi:schemaLocation=3D"http://db.apache.org/torque/5.0/templates/datab=
ase
>     https://db.apache.org/torque/torque-5.0/documentation/orm-reference/d=
atabase-5-0-strict.xsd" name=3D"test" defaultIdMethod=3D"native" defaultJav=
aType=3D"object">
>     <external-schema filename=3Dfirst-schema.xml" />
>     <table name=3D"foreign-key" javaName=3D"Test">
>         <column name=3D"Id" javaName=3D"Id" required=3D"true" type=3D"INT=
EGER" primaryKey=3D"true"/>
>         <column name=3D"Name" javaName=3D"Name" required=3D"true" type=3D=
"VARCHAR" size=3D"5"/>
>     </table>
>     <table name=3D"test2" javaName=3D"Test2">
>         <column name=3D"Id" javaName=3D"Id" required=3D"true" type=3D"INT=
EGER" primaryKey=3D"true"/>
>         <column name=3D"Name" javaName=3D"Name" required=3D"true" type=3D=
"VARCHAR" size=3D"5"/>
>         <column name=3D"foreign-key" javaName=3D"ForeignKey" required=3D"=
true" type=3D"INTEGER" size=3D"2"/>
>         <!-- define foreign key to first scheme!-->
>     </table>
> </database>{code}
> =C2=A0



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