Hello
During migration of an application from SQL Server to Postgresql I found some queries which cause LLBLGen to generate invalid code. All problems are related to mismatched types in CASE clause.
Example 1:
QueryableFactory f = new QueryableFactory();
var fetchDeleted = true;
f.Create<AccountEntity>(ReadOnlySession.GetLinqMetaData<LinqMetaData>())
.Where(p => p.AccountTypeId == 1 && fetchDeleted ? p.IsDeleted : !p.IsDeleted)
.Select(p => p.ExternalId)
Ends up as:
2014-01-08 17:26:58 CET LOG: statement: SELECT "LPLA_1"."external_id" AS "ExternalId" FROM "public"."account" "LPLA_1" WHERE ( ( ( ( (CASE WHEN CASE WHEN ( ( "LPLA_1"."account_type_id" = ((1)::int4)) AND ( 1=1)) THEN 1 ELSE 0 END=1 THEN "LPLA_1"."is_deleted" ELSE CASE WHEN NOT ( "LPLA_1"."is_deleted" = ((TRUE)::bool)) THEN 1 ELSE 0 END END)=1))))
2014-01-08 17:26:58 CET ERROR: CASE types integer and boolean cannot be matched at character 199
This example can be trivially fixed by using "fetchDeleted==p.isDeleted".
Another case:
f.Create<EndPointConfigurationEntity>(ReadOnlySession.GetLinqMetaData<LinqMetaData>()).Where(p => p.ApiTypeId == 1)
.Select(p => new {
isDefaultCatalog = p.Catalog == null ? (bool?) null : p.Catalog.AccountDefaultCatalogs.Any(adc => adc.AccountId == p.AccountId),
externalId = p.ExternalId
})
Generates:
SELECT CASE WHEN CASE WHEN ( ( "LPA_L1"."id" IS NULL)) THEN 1 ELSE 0 END=1 THEN ((NULL)::varchar) ELSE CASE WHEN EXISTS (SELECT "LPLA_3"."id" AS "Id" FROM "public"."account_default_catalog" "LPLA_3" WHERE ( "LPA_L1"."id" = "LPLA_3"."catalog_id" AND ( "LPLA_3"."account_id" = "LPA_L2"."account_id"))) THEN 1 ELSE 0 END END AS "isDefaultCatalog", "LPA_L2"."external_id" AS "externalId" FROM ( "public"."catalog" "LPA_L1" RIGHT JOIN "public"."end_point_configuration" "LPA_L2" ON "LPA_L1"."id"="LPA_L2"."catalog_id") WHERE ( ( ( ( "LPA_L2"."api_type_id" = ((1)::int4)))))
2014-01-08 17:26:58 CET ERROR: CASE types integer and character varying cannot be matched at character 83
In this case I cannot just drop "p.Catalog == null ? (bool?) null : " part (which fixes the problem), because I expect isDefaultCatalog to return null if endpoint is linked to no catalog or TRUE/FALSE if linked catalog is or not among account defaults.
The same problem can be demonstrated with simpler code:
f.Create<EndPointConfigurationEntity>(ReadOnlySession.GetLinqMetaData<LinqMetaData>())
.Where(p => p.ApiTypeId == 1)
.Select(p => p.Catalog == null ? (bool?) null : true)
Which gives:
2014-01-08 17:26:58 CET LOG: statement: SELECT CASE WHEN CASE WHEN ( ( "LPA_L1"."id" IS NULL)) THEN 1 ELSE 0 END=1 THEN ((NULL)::varchar) ELSE ((1)) END AS "LPFA_3" FROM ( "public"."catalog" "LPA_L1" RIGHT JOIN "public"."end_point_configuration" "LPA_L2" ON "LPA_L1"."id"="LPA_L2"."catalog_id") WHERE ( ( ( ( "LPA_L2"."api_type_id" = ((1)::int4)))))
2014-01-08 17:26:58 CET ERROR: CASE types integer and character varying cannot be matched at character 83
In general ternary operator seems quite buggy when used with Postgresql.
I tested this with .Net 4.0, LLBLGen Pro runtime v 3.5.12.1101 (that's what we use in production) and v 4.1.13.1213 (trial).
Postgresql version 9.3.