mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
feat(postgresql): dynamic schema (#23401)
This commit is contained in:
@@ -72,12 +72,30 @@ COLUMN_DOES_NOT_EXIST_REGEX = re.compile(
|
||||
SYNTAX_ERROR_REGEX = re.compile('syntax error at or near "(?P<syntax_error>.*?)"')
|
||||
|
||||
|
||||
def parse_options(connect_args: Dict[str, Any]) -> Dict[str, str]:
|
||||
"""
|
||||
Parse ``options`` from ``connect_args`` into a dictionary.
|
||||
"""
|
||||
if not isinstance(connect_args.get("options"), str):
|
||||
return {}
|
||||
|
||||
tokens = (
|
||||
tuple(token.strip() for token in option.strip().split("=", 1))
|
||||
for option in re.split(r"-c\s?", connect_args["options"])
|
||||
if "=" in option
|
||||
)
|
||||
|
||||
return {token[0]: token[1] for token in tokens}
|
||||
|
||||
|
||||
class PostgresBaseEngineSpec(BaseEngineSpec):
|
||||
"""Abstract class for Postgres 'like' databases"""
|
||||
|
||||
engine = ""
|
||||
engine_name = "PostgreSQL"
|
||||
|
||||
supports_dynamic_schema = True
|
||||
|
||||
_time_grain_expressions = {
|
||||
None: "{col}",
|
||||
"PT1S": "DATE_TRUNC('second', {col})",
|
||||
@@ -147,6 +165,25 @@ class PostgresBaseEngineSpec(BaseEngineSpec):
|
||||
),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def adjust_engine_params(
|
||||
cls,
|
||||
uri: URL,
|
||||
connect_args: Dict[str, Any],
|
||||
catalog: Optional[str] = None,
|
||||
schema: Optional[str] = None,
|
||||
) -> Tuple[URL, Dict[str, Any]]:
|
||||
if not schema:
|
||||
return uri, connect_args
|
||||
|
||||
options = parse_options(connect_args)
|
||||
options["search_path"] = schema
|
||||
connect_args["options"] = " ".join(
|
||||
f"-c{key}={value}" for key, value in options.items()
|
||||
)
|
||||
|
||||
return uri, connect_args
|
||||
|
||||
@classmethod
|
||||
def get_schema_from_engine_params(
|
||||
cls,
|
||||
@@ -166,19 +203,16 @@ class PostgresBaseEngineSpec(BaseEngineSpec):
|
||||
to determine the schema for a non-qualified table in a query. In cases like
|
||||
that we raise an exception.
|
||||
"""
|
||||
options = re.split(r"-c\s?", connect_args.get("options", ""))
|
||||
for option in options:
|
||||
if "=" not in option:
|
||||
continue
|
||||
key, value = option.strip().split("=", 1)
|
||||
if key.strip() == "search_path":
|
||||
if "," in value:
|
||||
raise Exception(
|
||||
"Multiple schemas are configured in the search path, which means "
|
||||
"Superset is unable to determine the schema of unqualified table "
|
||||
"names and enforce permissions."
|
||||
)
|
||||
return value.strip()
|
||||
options = parse_options(connect_args)
|
||||
if search_path := options.get("search_path"):
|
||||
schemas = search_path.split(",")
|
||||
if len(schemas) > 1:
|
||||
raise Exception(
|
||||
"Multiple schemas are configured in the search path, which means "
|
||||
"Superset is unable to determine the schema of unqualified table "
|
||||
"names and enforce permissions."
|
||||
)
|
||||
return schemas[0]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user