diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/pom.xml
index e080820e339..d2c5c0b016a 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/pom.xml
@@ -175,6 +175,18 @@
legend-engine-xt-relationalStore-pure
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-mapping-pure
+
+
+ org.finos.legend.engine
+ legend-engine-pure-platform-dsl-store-java
+
+
+ org.finos.legend.engine
+ legend-engine-pure-platform-store-relational-java
+
org.eclipse.collections
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/src/main/resources/core_relational_duckdb/relational/sqlQueryToString/duckdbExtension.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/src/main/resources/core_relational_duckdb/relational/sqlQueryToString/duckdbExtension.pure
index 4d82ff9f2c0..dd1ba2cf377 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/src/main/resources/core_relational_duckdb/relational/sqlQueryToString/duckdbExtension.pure
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/src/main/resources/core_relational_duckdb/relational/sqlQueryToString/duckdbExtension.pure
@@ -29,6 +29,7 @@ function <> meta::relational::functions::sqlQueryToString::duckD
joinStringsProcessor = processJoinStringsOperationWithConcatCall_JoinStrings_1__SqlGenerationContext_1__String_1_,
literalProcessor = $literalProcessor,
selectSQLQueryProcessor = processSelectSQLQueryForDuckDB_SelectSQLQuery_1__SqlGenerationContext_1__Boolean_1__String_1_,
+ selectSQLQueryWithCTEsProcessor = processSelectSQLQueryWithCTEsDefault_SelectSQLQueryWithCommonTableExpressions_1__SqlGenerationContext_1__Boolean_1__String_1_,
columnNameToIdentifier = columnNameToIdentifierForDuckDB_String_1__DbConfig_1__String_1_,
identifierProcessor = processIdentifierWithDoubleQuotes_String_1__DbConfig_1__String_1_,
dynaFuncDispatch = $dynaFuncDispatch,
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/src/main/resources/core_relational_duckdb/relational/sqlQueryToString/tests/testDuckDBSQLGeneration.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/src/main/resources/core_relational_duckdb/relational/sqlQueryToString/tests/testDuckDBSQLGeneration.pure
new file mode 100644
index 00000000000..12df861e484
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-duckdb/legend-engine-xt-relationalStore-duckdb-pure/src/main/resources/core_relational_duckdb/relational/sqlQueryToString/tests/testDuckDBSQLGeneration.pure
@@ -0,0 +1,37 @@
+// Copyright 2024 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+###Pure
+import meta::core::runtime::*;
+import meta::external::store::relational::runtime::*;
+import meta::relational::extension::*;
+import meta::relational::functions::sqlQueryToString::*;
+import meta::relational::functions::sqlstring::*;
+import meta::relational::metamodel::relation::*;
+import meta::relational::runtime::*;
+import meta::relational::tests::*;
+import meta::relational::tests::model::simple::*;
+import meta::relational::tests::postProcessor::cteExtraction::*;
+
+function <> meta::relational::tests::sqlQueryToString::duckDB::testCTESQLGeneration(): Boolean[1]
+{
+ let func = {|Trade.all()->project([x|$x.id, x|$x.quantity], ['TradeID', 'Quantity'])->limit(10)->filter(x | $x.getInteger('TradeID') == 100)};
+ let pp = testRuntimeWithCTEPP().connectionStores->at(0).connection->cast(@DatabaseConnection).sqlQueryPostProcessors;
+ let result = toSQLString($func, simpleRelationalMapping, DatabaseType.DuckDB, []->cast(@String), $pp, ^Format(newLine='', indent=''), relationalExtensions(), noDebug());
+ assertEquals(
+ 'WITH subquery_cte_1_1 AS (select "root".ID as "TradeID", "root".quantity as "Quantity" from tradeTable as "root" limit 10) \n' +
+ 'select "TradeID" as "TradeID", "Quantity" as "Quantity" from subquery_cte_1_1 as "subselect" where "TradeID" = 100',
+ $result
+ );
+}
\ No newline at end of file
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/postprocessor/cteExtractionPostProcessor.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/postprocessor/cteExtractionPostProcessor.pure
index 88c47e5c323..4d3d68a75fc 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/postprocessor/cteExtractionPostProcessor.pure
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/postprocessor/cteExtractionPostProcessor.pure
@@ -138,7 +138,7 @@ function <> meta::relational::tests::postProcessor::cteExtra
meta::relational::tests::createTablesAndFillDb();
}
-function <> meta::relational::tests::postProcessor::cteExtraction::testRuntimeWithCTEPP(): Runtime[1]
+function meta::relational::tests::postProcessor::cteExtraction::testRuntimeWithCTEPP(): Runtime[1]
{
^Runtime
(
@@ -244,3 +244,18 @@ function <> meta::relational::tests::postProcessor::cteExtraction::te
let resultWithoutCTEPP = execute($func, simpleRelationalMapping, testRuntime(), relationalExtensions());
assertEquals($resultWithoutCTEPP.values->toCSV(), $result.values->toCSV());
}
+
+function <> meta::relational::tests::postProcessor::cteExtraction::testCorrelatedSubQueryIsolationStrategy(): Boolean[1]
+{
+ let func = {|
+ Person.all()->project([x|$x.firm.legalName, x|$x.firm.employeeByLastName('Smith').firstName], ['Legal Name','Employee Name'])
+ };
+ let result = execute($func, simpleRelationalMapping, testRuntimeWithCTEPP(), relationalExtensions());
+ assertSameSQL(
+ 'WITH subquery_cte_1_1 AS (select "persontable_2".FIRMID as FIRMID, "persontable_2".FIRSTNAME as FIRSTNAME from personTable as "persontable_2" where "persontable_2".LASTNAME = \'Smith\') ' +
+ 'select "firmtable_0".LEGALNAME as "Legal Name", "persontable_1".FIRSTNAME as "Employee Name" from personTable as "root" left outer join firmTable as "firmtable_0" on ("firmtable_0".ID = "root".FIRMID) left outer join subquery_cte_1_1 as "persontable_1" on ("firmtable_0".ID = "persontable_1".FIRMID)',
+ $result
+ );
+ let resultWithoutCTEPP = execute($func, simpleRelationalMapping, testRuntime(), relationalExtensions());
+ assertEquals($resultWithoutCTEPP.values->toCSV(), $result.values->toCSV());
+}
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/sqlQueryToString/extensionDefaults.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/sqlQueryToString/extensionDefaults.pure
index b5f6b15e3ec..a814e663ff2 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/sqlQueryToString/extensionDefaults.pure
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/sqlQueryToString/extensionDefaults.pure
@@ -309,7 +309,7 @@ function <> meta::relational::functions::sqlQueryToString::defau
): String[1]
{
$ctes->map(cte |
- $cte.name + ' AS (' + $sgc.dbConfig.selectSQLQueryProcessor($cte->cast(@SelectCommonTableExpression).selectSQLQuery->cast(@SelectSQLQuery), $sgc, $isSubSelect) + ')'
+ $cte.name + ' AS (' + $sgc.dbConfig.selectSQLQueryProcessor($cte->cast(@SelectCommonTableExpression).selectSQLQuery->cast(@SelectSQLQuery), ^$sgc(format = $sgc.format->indent()), $isSubSelect) + ')'
)->joinStrings(', \n') + ' \n';
}