[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)