Skip to content

Commit 0bb3576

Browse files
authored
GH Issue 1718: Lookup to a query in a parent folder contaminates the request's query environment container (#8177)
1 parent 98c1c60 commit 0bb3576

3 files changed

Lines changed: 98 additions & 6 deletions

File tree

‎query/src/org/labkey/query/QueryTestCase.jsp‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,98 @@ d,seven,twelve,day,month,date,duration,guid
16251625
assertEquals(2, StringUtils.countMatches(debugSql, "CONTAINERFILTER"));
16261626
}
16271627
1628+
// GH Issue 1718: a lookup resolves its target query against the folder the field is defined in, so compiling a query
1629+
// in a folder other than the request's must not move the environment container there.
1630+
@Test
1631+
public void testCompileLeavesEnvironmentContainer() throws Exception
1632+
{
1633+
User user = TestContext.get().getUser();
1634+
Container c = JunitUtil.getTestContainer();
1635+
Container sub = getSubfolder();
1636+
1637+
Object savedContainer = QueryService.get().getEnvironment(QueryService.Environment.CONTAINER);
1638+
try
1639+
{
1640+
QueryDefinition q = QueryService.get().createQueryDef(user, c, SchemaKey.fromString("core"), "QEnvContainer");
1641+
q.setSql("SELECT Name, ID FROM core.Containers");
1642+
q.save(user, c);
1643+
1644+
QueryService.get().setEnvironment(QueryService.Environment.CONTAINER, sub);
1645+
1646+
// compile in c, the way a lookup resolves its target in the folder the field is defined in
1647+
UserSchema coreInC = QueryService.get().getUserSchema(user, c, "core");
1648+
assertNotNull(coreInC.getTable("QEnvContainer"));
1649+
1650+
assertEquals(sub, QueryService.get().getEnvironment(QueryService.Environment.CONTAINER));
1651+
}
1652+
finally
1653+
{
1654+
QueryService.get().setEnvironment(QueryService.Environment.CONTAINER, savedContainer);
1655+
deleteQueryDef(user, c, "QEnvContainer");
1656+
}
1657+
}
1658+
1659+
// GH Issue 1718: folderPath() reports the folder its own query is compiled in. It used to read the same environment
1660+
// container that cross-folder compilation moves, so a sub-query from another folder could answer for its parent.
1661+
@Test
1662+
public void testFolderPathAcrossContainers() throws Exception
1663+
{
1664+
User user = TestContext.get().getUser();
1665+
Container c = JunitUtil.getTestContainer();
1666+
Container sub = getSubfolder();
1667+
1668+
Object savedContainer = QueryService.get().getEnvironment(QueryService.Environment.CONTAINER);
1669+
try
1670+
{
1671+
saveQueryDef(user, c, "QFolderPathInherited", "SELECT folderPath() AS p FROM core.Containers", true);
1672+
saveQueryDef(user, sub, "QFolderPathInner", "SELECT Name, ID FROM core.Containers", false);
1673+
1674+
QueryService.get().setEnvironment(QueryService.Environment.CONTAINER, c);
1675+
1676+
// an inherited query answers for the folder it runs in, not the one it is defined in
1677+
assertEquals(c.getPath(), selectFolderPath(user, c, "SELECT p FROM QFolderPathInherited"));
1678+
assertEquals(sub.getPath(), selectFolderPath(user, sub, "SELECT p FROM QFolderPathInherited"));
1679+
1680+
// compiling a sub-query from another folder must not answer for that folder
1681+
assertEquals(c.getPath(), selectFolderPath(user, c,
1682+
"SELECT folderPath() AS p FROM Folder.qtest.core.QFolderPathInner"));
1683+
1684+
assertEquals(c, QueryService.get().getEnvironment(QueryService.Environment.CONTAINER));
1685+
}
1686+
finally
1687+
{
1688+
QueryService.get().setEnvironment(QueryService.Environment.CONTAINER, savedContainer);
1689+
deleteQueryDef(user, c, "QFolderPathInherited");
1690+
deleteQueryDef(user, sub, "QFolderPathInner");
1691+
}
1692+
}
1693+
1694+
private void saveQueryDef(User user, Container container, String name, String sql, boolean canInherit)
1695+
{
1696+
deleteQueryDef(user, container, name);
1697+
QueryDefinition q = QueryService.get().createQueryDef(user, container, SchemaKey.fromString("core"), name);
1698+
q.setSql(sql);
1699+
q.setCanInherit(canInherit);
1700+
q.save(user, container);
1701+
}
1702+
1703+
private void deleteQueryDef(User user, Container container, String name)
1704+
{
1705+
QueryDefinition q = QueryService.get().getQueryDef(user, container, "core", name);
1706+
if (null != q)
1707+
q.delete(user);
1708+
}
1709+
1710+
private String selectFolderPath(User user, Container container, String sql) throws Exception
1711+
{
1712+
QuerySchema schema = QueryService.get().getUserSchema(user, container, "core");
1713+
try (Results rs = QueryService.get().getSelectBuilder(schema, sql, true).select(true))
1714+
{
1715+
assertTrue(sql, rs.next());
1716+
return rs.getString("p");
1717+
}
1718+
}
1719+
16281720
@Test
16291721
public void testJSONDataLoader() throws Exception
16301722
{

‎query/src/org/labkey/query/sql/Method.java‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,17 +1604,19 @@ public static String toSimpleString(SQLFragment f)
16041604
}
16051605

16061606

1607+
// GH Issue 1718: the query's own schema, not the thread-local, is authoritative for which query is being compiled.
1608+
// A lookup to a query in another folder compiles against that folder's schema, and reading the environment first
1609+
// made folder() report whichever query the thread compiled last.
16071610
static Container getCompileTimeContainer(Query query)
16081611
{
1609-
Container cCompile = (Container) QueryServiceImpl.get().getEnvironment(QueryService.Environment.CONTAINER);
1610-
if (null == cCompile && null != query)
1612+
if (null != query)
16111613
{
16121614
// Issue 53355: A column may be erroneously constructed (e.g. invalid calculated column) which can result in the schema being null
16131615
QuerySchema querySchema = query.getSchema();
16141616
if (querySchema != null)
1615-
cCompile = querySchema.getContainer();
1617+
return querySchema.getContainer();
16161618
}
1617-
return cCompile;
1619+
return (Container) QueryServiceImpl.get().getEnvironment(QueryService.Environment.CONTAINER);
16181620
}
16191621

16201622

‎query/src/org/labkey/query/sql/Query.java‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,8 +608,6 @@ public TableInfo getTableInfo()
608608
if (!_parseErrors.isEmpty())
609609
return null;
610610

611-
QueryService.get().setEnvironment(QueryService.Environment.CONTAINER, getSchema().getContainer());
612-
613611
TableInfo tinfo = _queryRoot.getTableInfo();
614612

615613
if (!_parseErrors.isEmpty())

0 commit comments

Comments
 (0)