Commits

Kirill Simonov committed 9780aba

Use a scalar unit to encode a tuple to boolean cast.

Comments (0)

Files changed (2)

src/htsql/tr/encode.py

 from ..adapter import Adapter, adapts
 from ..domain import Domain, UntypedDomain, TupleDomain, BooleanDomain
 from .error import EncodeError
+from .coerce import coerce
 from .binding import (Binding, RootBinding, QueryBinding, SegmentBinding,
                       TableBinding, FreeTableBinding, AttachedTableBinding,
                       ColumnBinding, LiteralBinding, SieveBinding,
                    QueryExpression, SegmentExpression, LiteralCode,
                    EqualityCode, TotalEqualityCode,
                    ConjunctionCode, DisjunctionCode, NegationCode,
-                   CastCode, ColumnUnit)
+                   CastCode, ColumnUnit, ScalarUnit)
 
 
 class EncodingState(object):
         # represents some space.  In this case, Boolean cast produces
         # an expression which is `FALSE` when the space is empty and
         # `TRUE` otherwise.  The actual expression is:
-        #   `!(column==null())`,
-        # where `column` is some non-nullable column of the prominent
-        # table of the space.
+        #   `!(unit==null())`,
+        # where `unit` is some non-nullable function on the space.
 
         # Translate the operand to a space node.
         space = self.state.relate(self.base)
-        # Now the space may lack the prominent table; however this case
-        # is hardly useful and difficult to handle, so we generate an
-        # error here.
-        if space.table is None:
-            raise EncodeError("expected a space with a prominent table",
-                              self.binding.mark)
-        # Find a non-nullable column; if all columns are nullable,
-        # our only option is to raise an error.
-        for column in space.table.columns:
-            if not column.is_nullable:
-                break
-        else:
-            raise EncodeError("expected a table with at least one"
-                              " non-nullable column", self.binding.mark)
-        # Generate and return the expression: `!(column==null())`.
-        unit = ColumnUnit(column, space, self.binding)
-        literal = LiteralCode(None, column.domain, self.binding)
-        return NegationCode(TotalEqualityCode(unit, literal, self.binding),
+        # `TRUE` and `NULL` literals.
+        true_literal = LiteralCode(True, coerce(BooleanDomain()), self.binding)
+        null_literal = LiteralCode(None, coerce(BooleanDomain()), self.binding)
+        # A `TRUE` constant as a function on the space.
+        unit = ScalarUnit(true_literal, space, self.binding)
+        # Return `!(unit==null())`.
+        return NegationCode(TotalEqualityCode(unit, null_literal, self.binding),
                             self.binding)
 
 

test/output/pgsql.yaml

 
          ----
          /{count(school),count(department),count(course)}
-         SELECT COALESCE("school"."!", 0), COALESCE("department"."!", 0), COALESCE("course"."!", 0) FROM (SELECT 1) AS "!" LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT ("school"."code" IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."school" AS "school") AS "school" ON (TRUE) LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT ("department"."code" IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department") AS "department" ON (TRUE) LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT ("course"."department" IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."course" AS "course") AS "course" ON (TRUE)
+         SELECT COALESCE("school"."!", 0), COALESCE("department"."!", 0), COALESCE("course"."!", 0) FROM (SELECT 1) AS "!" LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT (TRUE IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."school" AS "school") AS "school" ON (TRUE) LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT (TRUE IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department") AS "department" ON (TRUE) LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT (TRUE IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."course" AS "course") AS "course" ON (TRUE)
     - uri: /{count(department),count(department?exists(course))}
       status: 200 OK
       headers:
 
          ----
          /{count(department),count(department?exists(course))}
-         SELECT COALESCE("department_1"."!", 0), COALESCE("department_2"."!", 0) FROM (SELECT 1) AS "!" LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT ("department"."code" IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department") AS "department_1" ON (TRUE) LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT ("department"."code" IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department" WHERE EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT ("course"."department" IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department"))))) AS "department_2" ON (TRUE)
+         SELECT COALESCE("department_1"."!", 0), COALESCE("department_2"."!", 0) FROM (SELECT 1) AS "!" LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT (TRUE IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department") AS "department_1" ON (TRUE) LEFT OUTER JOIN (SELECT COUNT(NULLIF((NOT (TRUE IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department" WHERE EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT (TRUE IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department"))))) AS "department_2" ON (TRUE)
     - uri: /department{code,count(course{credits=3})}
       status: 200 OK
       headers:
 
          ----
          /department?exists(course)
-         SELECT "department"."code", "department"."name", "department"."school" FROM "ad"."department" AS "department" WHERE EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT ("course"."department" IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department")))) ORDER BY 1 ASC
+         SELECT "department"."code", "department"."name", "department"."school" FROM "ad"."department" AS "department" WHERE EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT (TRUE IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department")))) ORDER BY 1 ASC
     - uri: /school?!exists(department)
       status: 200 OK
       headers:
 
          ----
          /school?!exists(department)
-         SELECT "school"."code", "school"."name" FROM "ad"."school" AS "school" WHERE (NOT EXISTS((SELECT TRUE FROM "ad"."department" AS "department" WHERE ((NOT ("department"."code" IS NOT DISTINCT FROM NULL)) AND ("school"."code" = "department"."school"))))) ORDER BY 1 ASC
+         SELECT "school"."code", "school"."name" FROM "ad"."school" AS "school" WHERE (NOT EXISTS((SELECT TRUE FROM "ad"."department" AS "department" WHERE ((NOT (TRUE IS NOT DISTINCT FROM NULL)) AND ("school"."code" = "department"."school"))))) ORDER BY 1 ASC
     - uri: /school{*,count(department)}
       status: 200 OK
       headers:
 
          ----
          /school{*,count(department)}
-         SELECT "school"."code", "school"."name", COALESCE("department"."!", 0) FROM "ad"."school" AS "school" LEFT OUTER JOIN (SELECT "department"."school", COUNT(NULLIF((NOT ("department"."code" IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department" GROUP BY 1) AS "department" ON (("school"."code" = "department"."school")) ORDER BY 1 ASC
+         SELECT "school"."code", "school"."name", COALESCE("department"."!", 0) FROM "ad"."school" AS "school" LEFT OUTER JOIN (SELECT "department"."school", COUNT(NULLIF((NOT (TRUE IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department" GROUP BY 1) AS "department" ON (("school"."code" = "department"."school")) ORDER BY 1 ASC
     - uri: /school{*,count(department?exists(course))}
       status: 200 OK
       headers:
 
          ----
          /school{*,count(department?exists(course))}
-         SELECT "school"."code", "school"."name", COALESCE("department"."!", 0) FROM "ad"."school" AS "school" LEFT OUTER JOIN (SELECT "department"."school", COUNT(NULLIF((NOT ("department"."code" IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department" WHERE EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT ("course"."department" IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department")))) GROUP BY 1) AS "department" ON (("school"."code" = "department"."school")) ORDER BY 1 ASC
+         SELECT "school"."code", "school"."name", COALESCE("department"."!", 0) FROM "ad"."school" AS "school" LEFT OUTER JOIN (SELECT "department"."school", COUNT(NULLIF((NOT (TRUE IS NOT DISTINCT FROM NULL)), FALSE)) AS "!" FROM "ad"."department" AS "department" WHERE EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT (TRUE IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department")))) GROUP BY 1) AS "department" ON (("school"."code" = "department"."school")) ORDER BY 1 ASC
     - uri: /school{*,count(department.exists(course))}
       status: 200 OK
       headers:
 
          ----
          /school{*,count(department.exists(course))}
-         SELECT "school"."code", "school"."name", COALESCE("department"."!", 0) FROM "ad"."school" AS "school" LEFT OUTER JOIN (SELECT "department"."school", COUNT(NULLIF(EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT ("course"."department" IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department")))), FALSE)) AS "!" FROM "ad"."department" AS "department" GROUP BY 1) AS "department" ON (("school"."code" = "department"."school")) ORDER BY 1 ASC
+         SELECT "school"."code", "school"."name", COALESCE("department"."!", 0) FROM "ad"."school" AS "school" LEFT OUTER JOIN (SELECT "department"."school", COUNT(NULLIF(EXISTS((SELECT TRUE FROM "ad"."course" AS "course" WHERE ((NOT (TRUE IS NOT DISTINCT FROM NULL)) AND ("department"."code" = "course"."department")))), FALSE)) AS "!" FROM "ad"."department" AS "department" GROUP BY 1) AS "department" ON (("school"."code" = "department"."school")) ORDER BY 1 ASC
   - id: formatters
     tests:
     - uri: /school