--- /dev/null
+.. change::
+ :tags: bug, sql
+ :tickets: 10535
+
+ Added compiler-level None/NULL handling for the "literal processors" of all
+ datatypes that include literal processing, that is, where a value is
+ rendered inline within a SQL statement rather than as a bound parameter,
+ for all those types that do not feature explicit "null value" handling.
+ Previously this behavior was undefined and inconsistent.
if self.native_uuid:
def process(value):
- if value is not None:
- value = f"""'{str(value).replace("''", "'")}'"""
- return value
+ return f"""'{str(value).replace("''", "'")}'"""
return process
else:
if self.as_uuid:
def process(value):
- if value is not None:
- value = f"""'{value.hex}'"""
- return value
+ return f"""'{value.hex}'"""
return process
else:
def process(value):
- if value is not None:
- value = f"""'{
+ return f"""'{
value.replace("-", "").replace("'", "''")
}'"""
- return value
return process
class _OracleDateLiteralRender:
def _literal_processor_datetime(self, dialect):
def process(value):
- if value is not None:
- if getattr(value, "microsecond", None):
- value = (
- f"""TO_TIMESTAMP"""
- f"""('{value.isoformat().replace("T", " ")}', """
- """'YYYY-MM-DD HH24:MI:SS.FF')"""
- )
- else:
- value = (
- f"""TO_DATE"""
- f"""('{value.isoformat().replace("T", " ")}', """
- """'YYYY-MM-DD HH24:MI:SS')"""
- )
+ if getattr(value, "microsecond", None):
+ value = (
+ f"""TO_TIMESTAMP"""
+ f"""('{value.isoformat().replace("T", " ")}', """
+ """'YYYY-MM-DD HH24:MI:SS.FF')"""
+ )
+ else:
+ value = (
+ f"""TO_DATE"""
+ f"""('{value.isoformat().replace("T", " ")}', """
+ """'YYYY-MM-DD HH24:MI:SS')"""
+ )
return value
return process
def _literal_processor_date(self, dialect):
def process(value):
- if value is not None:
- if getattr(value, "microsecond", None):
- value = (
- f"""TO_TIMESTAMP"""
- f"""('{value.isoformat().split("T")[0]}', """
- """'YYYY-MM-DD')"""
- )
- else:
- value = (
- f"""TO_DATE"""
- f"""('{value.isoformat().split("T")[0]}', """
- """'YYYY-MM-DD')"""
- )
+ if getattr(value, "microsecond", None):
+ value = (
+ f"""TO_TIMESTAMP"""
+ f"""('{value.isoformat().split("T")[0]}', """
+ """'YYYY-MM-DD')"""
+ )
+ else:
+ value = (
+ f"""TO_DATE"""
+ f"""('{value.isoformat().split("T")[0]}', """
+ """'YYYY-MM-DD')"""
+ )
return value
return process
"""
+ if value is None and not type_.should_evaluate_none:
+ # issue #10535 - handle NULL in the compiler without placing
+ # this onto each type, except for "evaluate None" types
+ # (e.g. JSON)
+ return self.process(elements.Null._instance())
+
processor = type_._cached_literal_processor(self.dialect)
if processor:
try:
if _portion is not None:
def process(value):
- if value is not None:
- value = f"""'{value.isoformat().split("T")[_portion]}'"""
- return value
+ return f"""'{value.isoformat().split("T")[_portion]}'"""
else:
def process(value):
- if value is not None:
- value = f"""'{value.isoformat().replace("T", " ")}'"""
- return value
+ return f"""'{value.isoformat().replace("T", " ")}'"""
return process
value = int_processor(value)
elif string_processor and isinstance(value, str):
value = string_processor(value)
+ else:
+ raise NotImplementedError()
+
return value
return process
if not self.as_uuid:
def process(value):
- if value is not None:
- value = (
- f"""'{value.replace("-", "").replace("'", "''")}'"""
- )
- return value
+ return f"""'{value.replace("-", "").replace("'", "''")}'"""
return process
else:
if character_based_uuid:
def process(value):
- if value is not None:
- value = f"""'{value.hex}'"""
- return value
+ return f"""'{value.hex}'"""
return process
else:
def process(value):
- if value is not None:
- value = f"""'{str(value).replace("'", "''")}'"""
- return value
+ return f"""'{str(value).replace("'", "''")}'"""
return process
)
connection.execute(ins)
+ ins = t.insert().values(
+ x=literal(None, type_, literal_execute=True)
+ )
+ connection.execute(ins)
+
if support_whereclause and self.supports_whereclause:
if compare:
stmt = t.select().where(
)
)
else:
- stmt = t.select()
+ stmt = t.select().where(t.c.x.is_not(None))
rows = connection.execute(stmt).all()
assert rows, "No rows returned"
value = filter_(value)
assert value in output
+ stmt = t.select().where(t.c.x.is_(None))
+ rows = connection.execute(stmt).all()
+ eq_(rows, [(None,)])
+
return run