Set operations within an IN mustnt be simplified and must be encased within a SELECT

pull/257/head
Christopher Jolly 1 year ago
parent b5d3422022
commit e570dfbf0f

@ -67,6 +67,16 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
//_jetSqlExpressionFactory = jetSqlExpressionFactory; //_jetSqlExpressionFactory = jetSqlExpressionFactory;
} }
protected override bool TryGenerateWithoutWrappingSelect(SelectExpression selectExpression)
{
parent.TryPeek(out var exp);
if (exp is InExpression)
{
return false;
}
return base.TryGenerateWithoutWrappingSelect(selectExpression);
}
protected override Expression VisitSelect(SelectExpression selectExpression) protected override Expression VisitSelect(SelectExpression selectExpression)
{ {
// Copy & pasted from `QuerySqlGenerator` to implement Jet's non-standard JOIN syntax and DUAL table // Copy & pasted from `QuerySqlGenerator` to implement Jet's non-standard JOIN syntax and DUAL table
@ -569,8 +579,9 @@ namespace EntityFrameworkCore.Jet.Query.Sql.Internal
} }
} }
}*/ }*/
parent.Push(inExpression);
base.GenerateIn(inExpression, negated); base.GenerateIn(inExpression, negated);
parent.Pop();
} }
protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression) protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression)

@ -9862,26 +9862,26 @@ SELECT `s`.`Name`, (
INNER JOIN `Squads` AS `s0` ON `g2`.`SquadId` = `s0`.`Id`) INNER JOIN `Squads` AS `s0` ON `g2`.`SquadId` = `s0`.`Id`)
INNER JOIN `Cities` AS `c` ON `g2`.`CityOfBirthName` = `c`.`Name` INNER JOIN `Cities` AS `c` ON `g2`.`CityOfBirthName` = `c`.`Name`
WHERE 'Marcus' IN ( WHERE 'Marcus' IN (
SELECT `t0`.`Nickname` SELECT `u0`.`Nickname`
FROM ( FROM (
SELECT `g3`.`Nickname`, `g3`.`SquadId`, `g3`.`AssignedCityName`, `g3`.`CityOfBirthName`, `g3`.`Discriminator`, `g3`.`FullName`, `g3`.`HasSoulPatch`, `g3`.`LeaderNickname`, `g3`.`LeaderSquadId`, `g3`.`Rank` SELECT `g3`.`Nickname`
FROM `Gears` AS `g3` FROM `Gears` AS `g3`
UNION ALL UNION ALL
SELECT `g4`.`Nickname`, `g4`.`SquadId`, `g4`.`AssignedCityName`, `g4`.`CityOfBirthName`, `g4`.`Discriminator`, `g4`.`FullName`, `g4`.`HasSoulPatch`, `g4`.`LeaderNickname`, `g4`.`LeaderSquadId`, `g4`.`Rank` SELECT `g4`.`Nickname`
FROM `Gears` AS `g4` FROM `Gears` AS `g4`
) AS `t0` ) AS `u0`
) AND (`s`.`Name` = `s0`.`Name` OR (`s`.`Name` IS NULL AND `s0`.`Name` IS NULL))) AS `SumOfLengths` ) AND (`s`.`Name` = `s0`.`Name` OR (`s`.`Name` IS NULL AND `s0`.`Name` IS NULL))) AS `SumOfLengths`
FROM `Gears` AS `g` FROM `Gears` AS `g`
INNER JOIN `Squads` AS `s` ON `g`.`SquadId` = `s`.`Id` INNER JOIN `Squads` AS `s` ON `g`.`SquadId` = `s`.`Id`
WHERE 'Marcus' IN ( WHERE 'Marcus' IN (
SELECT `t`.`Nickname` SELECT `u`.`Nickname`
FROM ( FROM (
SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`Discriminator`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank` SELECT `g0`.`Nickname`
FROM `Gears` AS `g0` FROM `Gears` AS `g0`
UNION ALL UNION ALL
SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`AssignedCityName`, `g1`.`CityOfBirthName`, `g1`.`Discriminator`, `g1`.`FullName`, `g1`.`HasSoulPatch`, `g1`.`LeaderNickname`, `g1`.`LeaderSquadId`, `g1`.`Rank` SELECT `g1`.`Nickname`
FROM `Gears` AS `g1` FROM `Gears` AS `g1`
) AS `t` ) AS `u`
) )
GROUP BY `s`.`Name` GROUP BY `s`.`Name`
"""); """);

@ -3500,26 +3500,26 @@ WHERE (`t`.`Note` <> 'K.I.A.' OR `t`.`Note` IS NULL) AND `u`.`HasSoulPatch` <> T
await base.Optional_navigation_type_compensation_works_with_contains(async); await base.Optional_navigation_type_compensation_works_with_contains(async);
AssertSql( AssertSql(
""" """
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note] SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`
FROM [Tags] AS [t] FROM `Tags` AS `t`
LEFT JOIN ( LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId] SELECT `g`.`Nickname`, `g`.`SquadId`
FROM [Gears] AS [g] FROM `Gears` AS `g`
UNION ALL UNION ALL
SELECT [o].[Nickname], [o].[SquadId] SELECT `o`.`Nickname`, `o`.`SquadId`
FROM [Officers] AS [o] FROM `Officers` AS `o`
) AS [t0] ON [t].[GearNickName] = [t0].[Nickname] AND [t].[GearSquadId] = [t0].[SquadId] ) AS `u` ON `t`.`GearNickName` = `u`.`Nickname` AND `t`.`GearSquadId` = `u`.`SquadId`
WHERE ([t].[Note] <> N'K.I.A.' OR ([t].[Note] IS NULL)) AND EXISTS ( WHERE (`t`.`Note` <> 'K.I.A.' OR `t`.`Note` IS NULL) AND `u`.`SquadId` IN (
SELECT 1 SELECT `u0`.`SquadId`
FROM ( FROM (
SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], N'Gear' AS [Discriminator] SELECT `g0`.`SquadId`
FROM [Gears] AS [g0] FROM `Gears` AS `g0`
UNION ALL UNION ALL
SELECT [o0].[Nickname], [o0].[SquadId], [o0].[AssignedCityName], [o0].[CityOfBirthName], [o0].[FullName], [o0].[HasSoulPatch], [o0].[LeaderNickname], [o0].[LeaderSquadId], [o0].[Rank], N'Officer' AS [Discriminator] SELECT `o0`.`SquadId`
FROM [Officers] AS [o0] FROM `Officers` AS `o0`
) AS [t1] ) AS `u0`
WHERE [t1].[SquadId] = [t0].[SquadId]) )
"""); """);
} }
@ -10527,25 +10527,25 @@ WHERE DATEPART(millisecond, [m].[Duration]) = 1
await base.Contains_on_collection_of_byte_subquery(async); await base.Contains_on_collection_of_byte_subquery(async);
AssertSql( AssertSql(
""" """
SELECT [t].[Name], [t].[LocustHordeId], [t].[ThreatLevel], [t].[ThreatLevelByte], [t].[ThreatLevelNullableByte], [t].[DefeatedByNickname], [t].[DefeatedBySquadId], [t].[HighCommandId], [t].[Discriminator] SELECT `u`.`Name`, `u`.`LocustHordeId`, `u`.`ThreatLevel`, `u`.`ThreatLevelByte`, `u`.`ThreatLevelNullableByte`, `u`.`DefeatedByNickname`, `u`.`DefeatedBySquadId`, `u`.`HighCommandId`, `u`.`Discriminator`
FROM ( FROM (
SELECT [l].[Name], [l].[LocustHordeId], [l].[ThreatLevel], [l].[ThreatLevelByte], [l].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator] SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, CVar(NULL) AS `DefeatedBySquadId`, CVar(NULL) AS `HighCommandId`, 'LocustLeader' AS `Discriminator`
FROM [LocustLeaders] AS [l] FROM `LocustLeaders` AS `l`
UNION ALL UNION ALL
SELECT [l0].[Name], [l0].[LocustHordeId], [l0].[ThreatLevel], [l0].[ThreatLevelByte], [l0].[ThreatLevelNullableByte], [l0].[DefeatedByNickname], [l0].[DefeatedBySquadId], [l0].[HighCommandId], N'LocustCommander' AS [Discriminator] SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator`
FROM [LocustCommanders] AS [l0] FROM `LocustCommanders` AS `l0`
) AS [t] ) AS `u`
WHERE EXISTS ( WHERE `u`.`ThreatLevelByte` IN (
SELECT 1 SELECT `u0`.`ThreatLevelByte`
FROM ( FROM (
SELECT [l1].[Name], [l1].[LocustHordeId], [l1].[ThreatLevel], [l1].[ThreatLevelByte], [l1].[ThreatLevelNullableByte], NULL AS [DefeatedByNickname], NULL AS [DefeatedBySquadId], NULL AS [HighCommandId], N'LocustLeader' AS [Discriminator] SELECT `l1`.`ThreatLevelByte`
FROM [LocustLeaders] AS [l1] FROM `LocustLeaders` AS `l1`
UNION ALL UNION ALL
SELECT [l2].[Name], [l2].[LocustHordeId], [l2].[ThreatLevel], [l2].[ThreatLevelByte], [l2].[ThreatLevelNullableByte], [l2].[DefeatedByNickname], [l2].[DefeatedBySquadId], [l2].[HighCommandId], N'LocustCommander' AS [Discriminator] SELECT `l2`.`ThreatLevelByte`
FROM [LocustCommanders] AS [l2] FROM `LocustCommanders` AS `l2`
) AS [t0] ) AS `u0`
WHERE [t0].[ThreatLevelByte] = [t].[ThreatLevelByte]) )
"""); """);
} }
@ -13393,29 +13393,35 @@ ORDER BY `u`.`Nickname`, `u`.`SquadId`, `s`.`Id`, `s1`.`SquadId`
SELECT `s`.`Name`, ( SELECT `s`.`Name`, (
SELECT IIF(SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`)))) IS NULL, 0, SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`))))) SELECT IIF(SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`)))) IS NULL, 0, SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`)))))
FROM (( FROM ((
SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` SELECT `g2`.`SquadId`, `g2`.`CityOfBirthName`
FROM `Gears` AS `g0` FROM `Gears` AS `g2`
UNION ALL UNION ALL
SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` SELECT `o2`.`SquadId`, `o2`.`CityOfBirthName`
FROM `Officers` AS `o0` FROM `Officers` AS `o2`
) AS `t3` ) AS `u3`
INNER JOIN `Squads` AS `s0` ON `t3`.`SquadId` = `s0`.`Id`) INNER JOIN `Squads` AS `s0` ON `u3`.`SquadId` = `s0`.`Id`)
INNER JOIN `Cities` AS `c` ON `t3`.`CityOfBirthName` = `c`.`Name` INNER JOIN `Cities` AS `c` ON `u3`.`CityOfBirthName` = `c`.`Name`
WHERE 'Marcus' IN ( WHERE 'Marcus' IN (
SELECT `t4`.`Nickname` SELECT `u4`.`Nickname`
FROM ( FROM (
SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`AssignedCityName`, `g1`.`CityOfBirthName`, `g1`.`FullName`, `g1`.`HasSoulPatch`, `g1`.`LeaderNickname`, `g1`.`LeaderSquadId`, `g1`.`Rank`, 'Gear' AS `Discriminator` SELECT `u5`.`Nickname`
FROM `Gears` AS `g1` FROM (
UNION ALL SELECT `g3`.`Nickname`
SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`AssignedCityName`, `o1`.`CityOfBirthName`, `o1`.`FullName`, `o1`.`HasSoulPatch`, `o1`.`LeaderNickname`, `o1`.`LeaderSquadId`, `o1`.`Rank`, 'Officer' AS `Discriminator` FROM `Gears` AS `g3`
FROM `Officers` AS `o1` UNION ALL
UNION ALL SELECT `o3`.`Nickname`
SELECT `g2`.`Nickname`, `g2`.`SquadId`, `g2`.`AssignedCityName`, `g2`.`CityOfBirthName`, `g2`.`FullName`, `g2`.`HasSoulPatch`, `g2`.`LeaderNickname`, `g2`.`LeaderSquadId`, `g2`.`Rank`, 'Gear' AS `Discriminator` FROM `Officers` AS `o3`
FROM `Gears` AS `g2` ) AS `u5`
UNION ALL UNION ALL
SELECT `o2`.`Nickname`, `o2`.`SquadId`, `o2`.`AssignedCityName`, `o2`.`CityOfBirthName`, `o2`.`FullName`, `o2`.`HasSoulPatch`, `o2`.`LeaderNickname`, `o2`.`LeaderSquadId`, `o2`.`Rank`, 'Officer' AS `Discriminator` SELECT `u6`.`Nickname`
FROM `Officers` AS `o2` FROM (
) AS `t4` SELECT `g4`.`Nickname`
FROM `Gears` AS `g4`
UNION ALL
SELECT `o4`.`Nickname`
FROM `Officers` AS `o4`
) AS `u6`
) AS `u4`
) AND (`s`.`Name` = `s0`.`Name` OR (`s`.`Name` IS NULL AND `s0`.`Name` IS NULL))) AS `SumOfLengths` ) AND (`s`.`Name` = `s0`.`Name` OR (`s`.`Name` IS NULL AND `s0`.`Name` IS NULL))) AS `SumOfLengths`
FROM ( FROM (
SELECT `g`.`SquadId` SELECT `g`.`SquadId`
@ -13423,23 +13429,29 @@ FROM (
UNION ALL UNION ALL
SELECT `o`.`SquadId` SELECT `o`.`SquadId`
FROM `Officers` AS `o` FROM `Officers` AS `o`
) AS `t` ) AS `u`
INNER JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` INNER JOIN `Squads` AS `s` ON `u`.`SquadId` = `s`.`Id`
WHERE 'Marcus' IN ( WHERE 'Marcus' IN (
SELECT `t0`.`Nickname` SELECT `u2`.`Nickname`
FROM ( FROM (
SELECT `g3`.`Nickname`, `g3`.`SquadId`, `g3`.`AssignedCityName`, `g3`.`CityOfBirthName`, `g3`.`FullName`, `g3`.`HasSoulPatch`, `g3`.`LeaderNickname`, `g3`.`LeaderSquadId`, `g3`.`Rank`, 'Gear' AS `Discriminator` SELECT `u0`.`Nickname`
FROM `Gears` AS `g3` FROM (
UNION ALL SELECT `g0`.`Nickname`
SELECT `o3`.`Nickname`, `o3`.`SquadId`, `o3`.`AssignedCityName`, `o3`.`CityOfBirthName`, `o3`.`FullName`, `o3`.`HasSoulPatch`, `o3`.`LeaderNickname`, `o3`.`LeaderSquadId`, `o3`.`Rank`, 'Officer' AS `Discriminator` FROM `Gears` AS `g0`
FROM `Officers` AS `o3` UNION ALL
UNION ALL SELECT `o0`.`Nickname`
SELECT `g4`.`Nickname`, `g4`.`SquadId`, `g4`.`AssignedCityName`, `g4`.`CityOfBirthName`, `g4`.`FullName`, `g4`.`HasSoulPatch`, `g4`.`LeaderNickname`, `g4`.`LeaderSquadId`, `g4`.`Rank`, 'Gear' AS `Discriminator` FROM `Officers` AS `o0`
FROM `Gears` AS `g4` ) AS `u0`
UNION ALL UNION ALL
SELECT `o4`.`Nickname`, `o4`.`SquadId`, `o4`.`AssignedCityName`, `o4`.`CityOfBirthName`, `o4`.`FullName`, `o4`.`HasSoulPatch`, `o4`.`LeaderNickname`, `o4`.`LeaderSquadId`, `o4`.`Rank`, 'Officer' AS `Discriminator` SELECT `u1`.`Nickname`
FROM `Officers` AS `o4` FROM (
) AS `t0` SELECT `g1`.`Nickname`
FROM `Gears` AS `g1`
UNION ALL
SELECT `o1`.`Nickname`
FROM `Officers` AS `o1`
) AS `u1`
) AS `u2`
) )
GROUP BY `s`.`Name` GROUP BY `s`.`Name`
"""); """);

@ -10832,38 +10832,33 @@ ORDER BY `g`.`Nickname`, `g`.`SquadId`, `s`.`Id`, `s1`.`SquadId`
await base.Set_operator_with_navigation_in_projection_groupby_aggregate(async); await base.Set_operator_with_navigation_in_projection_groupby_aggregate(async);
AssertSql( AssertSql(
""" """
SELECT `s`.`Name`, ( SELECT `s`.`Name`, (
SELECT IIF(SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`)))) IS NULL, 0, SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`))))) SELECT IIF(SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`)))) IS NULL, 0, SUM(IIF(LEN(`c`.`Location`) IS NULL, NULL, CLNG(LEN(`c`.`Location`)))))
FROM ((`Gears` AS `g2` FROM (`Gears` AS `g2`
LEFT JOIN `Officers` AS `o2` ON `g2`.`Nickname` = `o2`.`Nickname` AND `g2`.`SquadId` = `o2`.`SquadId`)
INNER JOIN `Squads` AS `s0` ON `g2`.`SquadId` = `s0`.`Id`) INNER JOIN `Squads` AS `s0` ON `g2`.`SquadId` = `s0`.`Id`)
INNER JOIN `Cities` AS `c` ON `g2`.`CityOfBirthName` = `c`.`Name` INNER JOIN `Cities` AS `c` ON `g2`.`CityOfBirthName` = `c`.`Name`
WHERE 'Marcus' IN ( WHERE 'Marcus' IN (
SELECT `t0`.`Nickname` SELECT `u0`.`Nickname`
FROM ( FROM (
SELECT `g3`.`Nickname`, `g3`.`SquadId`, `g3`.`AssignedCityName`, `g3`.`CityOfBirthName`, `g3`.`FullName`, `g3`.`HasSoulPatch`, `g3`.`LeaderNickname`, `g3`.`LeaderSquadId`, `g3`.`Rank`, IIF(`o3`.`Nickname` IS NOT NULL, 'Officer', NULL) AS `Discriminator` SELECT `g3`.`Nickname`
FROM `Gears` AS `g3` FROM `Gears` AS `g3`
LEFT JOIN `Officers` AS `o3` ON `g3`.`Nickname` = `o3`.`Nickname` AND `g3`.`SquadId` = `o3`.`SquadId`
UNION ALL UNION ALL
SELECT `g4`.`Nickname`, `g4`.`SquadId`, `g4`.`AssignedCityName`, `g4`.`CityOfBirthName`, `g4`.`FullName`, `g4`.`HasSoulPatch`, `g4`.`LeaderNickname`, `g4`.`LeaderSquadId`, `g4`.`Rank`, IIF(`o4`.`Nickname` IS NOT NULL, 'Officer', NULL) AS `Discriminator` SELECT `g4`.`Nickname`
FROM `Gears` AS `g4` FROM `Gears` AS `g4`
LEFT JOIN `Officers` AS `o4` ON `g4`.`Nickname` = `o4`.`Nickname` AND `g4`.`SquadId` = `o4`.`SquadId` ) AS `u0`
) AS `t0`
) AND (`s`.`Name` = `s0`.`Name` OR (`s`.`Name` IS NULL AND `s0`.`Name` IS NULL))) AS `SumOfLengths` ) AND (`s`.`Name` = `s0`.`Name` OR (`s`.`Name` IS NULL AND `s0`.`Name` IS NULL))) AS `SumOfLengths`
FROM `Gears` AS `g` FROM `Gears` AS `g`
INNER JOIN `Squads` AS `s` ON `g`.`SquadId` = `s`.`Id` INNER JOIN `Squads` AS `s` ON `g`.`SquadId` = `s`.`Id`
WHERE 'Marcus' IN ( WHERE 'Marcus' IN (
SELECT `t`.`Nickname` SELECT `u`.`Nickname`
FROM ( FROM (
SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, IIF(`o0`.`Nickname` IS NOT NULL, 'Officer', NULL) AS `Discriminator` SELECT `g0`.`Nickname`
FROM `Gears` AS `g0` FROM `Gears` AS `g0`
LEFT JOIN `Officers` AS `o0` ON `g0`.`Nickname` = `o0`.`Nickname` AND `g0`.`SquadId` = `o0`.`SquadId`
UNION ALL UNION ALL
SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`AssignedCityName`, `g1`.`CityOfBirthName`, `g1`.`FullName`, `g1`.`HasSoulPatch`, `g1`.`LeaderNickname`, `g1`.`LeaderSquadId`, `g1`.`Rank`, IIF(`o1`.`Nickname` IS NOT NULL, 'Officer', NULL) AS `Discriminator` SELECT `g1`.`Nickname`
FROM `Gears` AS `g1` FROM `Gears` AS `g1`
LEFT JOIN `Officers` AS `o1` ON `g1`.`Nickname` = `o1`.`Nickname` AND `g1`.`SquadId` = `o1`.`SquadId` ) AS `u`
) AS `t`
) )
GROUP BY `s`.`Name` GROUP BY `s`.`Name`
"""); """);

Loading…
Cancel
Save