in core/lib/sqlparse/create.py [0:0]
def partition_to_model(cls, presult: ParseResults) -> models.PartitionConfig:
# Convert ParseResults from parsing a partitions config into a
# model. This can throw a PartitionParseError
mytype = presult.get("part_type", None)
mysubtype = presult.get("p_subtype", None)
if (
(not mytype and not mysubtype)
or mytype not in models.PartitionConfig.KNOWN_PARTITION_TYPES
or (
mysubtype is not None
and mysubtype not in models.PartitionConfig.KNOWN_PARTITION_SUBTYPES
)
):
raise PartitionParseError(
"partition_to_model Cannot init mode.PartitionConfig: "
f"type {mytype} subtype {mysubtype}"
)
pc = models.PartitionConfig()
pc.part_type = mytype
pc.p_subtype = mysubtype
def _strip_ticks(fields: Union[str, List[str]]) -> Union[str, List[str]]:
if isinstance(fields, str):
return fields.replace("`", "")
return [_strip_ticks(f) for f in fields]
if presult.get("invalid_partition_prefix"):
raise PartitionParseError(
f"Partition type {pc.part_type} cannot "
"have invalid partition number prefix defined"
)
# set fields_or_expr, full_type
if (
pc.part_type == models.PartitionConfig.PTYPE_LIST
or pc.part_type == models.PartitionConfig.PTYPE_RANGE
):
pc.num_partitions = len(presult.get("part_defs", []))
if pc.num_partitions == 0:
raise PartitionParseError(
f"Partition type {pc.part_type} MUST have partitions defined"
)
pc.part_defs = _process_partition_definitions(presult.part_defs)
if not pc.p_subtype:
pc.full_type = pc.part_type
pc.via_nested_expr = (
"via_nested_expr" in presult and "via_list" not in presult
)
pc.fields_or_expr = presult.p_expr.asList()
if pc.via_nested_expr:
# strip backticks e.g. to_days(`date`) -> [to_days, [date]]
pc.fields_or_expr = _strip_ticks(pc.fields_or_expr)
else:
pc.full_type = f"{pc.part_type} {pc.p_subtype}"
pc.fields_or_expr = presult.field_list.asList()
elif pc.part_type == models.PartitionConfig.PTYPE_KEY:
pc.full_type = (
pc.part_type if not pc.p_subtype else f"{pc.p_subtype} {pc.part_type}"
)
pc.num_partitions = int(presult.get("num_partitions", 1))
fl = presult.get("field_list", None)
pc.fields_or_expr = fl.asList() if fl else []
# This is the only place p_algo is valid. algorithm_for_key
algo_result = presult.get("p_algo")
if algo_result and len(algo_result.asList()) > 0:
pc.algorithm_for_key = int(algo_result.asList()[0])
elif pc.part_type == models.PartitionConfig.PTYPE_HASH:
pc.full_type = (
pc.part_type if not pc.p_subtype else f"{pc.p_subtype} {pc.part_type}"
)
pc.num_partitions = int(presult.get("num_partitions", 1))
hexpr = presult.get("p_hash_expr", None)
if not hexpr:
raise PartitionParseError(
f"Partition type {pc.part_type} MUST have p_hash_expr defined"
)
pc.fields_or_expr = _strip_ticks(hexpr.asList())
else:
# unreachable since we checked for all part_types earlier.
raise PartitionParseError(f"Unknown partition type {pc.part_type}")
# We avoid escaping fields/expr in partitions with backticks since
# its tricky to distinguish between a list of columns and an expression
# e.g. unix_timestamp(ts) - ts could be escaped but unix_ts cannot.
# Our parser will strip out backticks wherever possible. For nestedExpr
# usecases, this is done via _strip_ticks instead.
def _has_backticks(fields: Union[str, List[str]]) -> bool:
if isinstance(fields, list):
return any(_has_backticks(f) for f in fields)
return "`" in fields if isinstance(fields, str) else False
if _has_backticks(pc.fields_or_expr):
raise PartitionParseError(
f"field_or_expr cannot have backticks {pc.fields_or_expr}"
)
if len(pc.part_defs) > 0 and any(
pd.pdef_name.upper() == "NULL" for pd in pc.part_defs
):
# We will disallow this even if raw sql passed in as e.g.
# PARTITION `null` VALUES IN ...
raise PartitionParseError("Partition names may not be literal `null`")
return pc