Repository: TobikoData/sqlmesh
Pull request #2339 (2024-03-25 16:06:58)

Fix: fix testing webhook parameters


Patch:
diff --git a/.circleci/continue_config.yml b/.circleci/continue_config.yml
index db301980..cd17db69 100644
--- a/.circleci/continue_config.yml
+++ b/.circleci/continue_config.yml
@@ -225,10 +225,10 @@ jobs:
                   "parameters":{
                     "run_main_pr":false, 
                     "run_sqlmesh_commit":true, 
-                    "sqlmesh_branch":"'"$CIRCLE_BRANCH"'",
-                    "sqlmesh_commit_author":"'"$CIRCLE_USERNAME"'",
-                    "sqlmesh_commit_hash":"'"$CIRCLE_SHA1"'",
-                    "sqlmesh_commit_pr":"'"$CIRCLE_PULL_REQUEST"'"
+                    "sqlmesh_branch":"'$CIRCLE_BRANCH'",
+                    "sqlmesh_commit_author":"'$CIRCLE_USERNAME'",
+                    "sqlmesh_commit_hash":"'$CIRCLE_SHA1'",
+                    "sqlmesh_commit_pr":"'$CIRCLE_PULL_REQUEST'"
                     }
                 }'
 
diff --git a/sqlmesh/core/engine_adapter/base_postgres.py b/sqlmesh/core/engine_adapter/base_postgres.py
index 63ef895a..049f84ee 100644
--- a/sqlmesh/core/engine_adapter/base_postgres.py
+++ b/sqlmesh/core/engine_adapter/base_postgres.py
@@ -35,10 +35,11 @@ class BasePostgresEngineAdapter(EngineAdapter):
         sql = (
             exp.select("column_name", "data_type")
             .from_(self.COLUMNS_TABLE)
-            .where(
-                f"table_name = '{table.alias_or_name}' AND table_schema = '{table.args['db'].name}'"
-            )
+            .where(f"table_name = '{table.alias_or_name}'")
         )
+        if table.args.get("db"):
+            sql = sql.where(f"table_schema = '{table.args['db'].name}'")
+
         self.execute(sql)
         resp = self.cursor.fetchall()
         if not resp:
diff --git a/sqlmesh/core/engine_adapter/redshift.py b/sqlmesh/core/engine_adapter/redshift.py
index 9ddaf8a6..639d08d9 100644
--- a/sqlmesh/core/engine_adapter/redshift.py
+++ b/sqlmesh/core/engine_adapter/redshift.py
@@ -4,7 +4,6 @@ import typing as t
 
 import pandas as pd
 from sqlglot import exp
-from sqlglot.errors import ErrorLevel
 
 from sqlmesh.core.dialect import to_schema
 from sqlmesh.core.engine_adapter.base_postgres import BasePostgresEngineAdapter
@@ -20,7 +19,7 @@ from sqlmesh.core.engine_adapter.shared import (
     SourceQuery,
     set_catalog,
 )
-from sqlmesh.utils.errors import SQLMeshError
+from sqlmesh.utils import random_id
 
 if t.TYPE_CHECKING:
     from sqlmesh.core._typing import SchemaName, TableName
@@ -121,68 +120,36 @@ class RedshiftEngineAdapter(
             and statement.expression.args.get("limit") is not None
             and statement.expression.args["limit"].expression.this == "0"
         ):
+            assert not isinstance(table_name_or_schema, exp.Schema)
             # redshift has a bug where CTAS statements have non determistic types. if a limit
             # is applied to a ctas statement, VARCHAR types default to 1 in some instances.
             # this checks the explain plain from redshift and tries to detect when these optimizer
             # bugs occur and force a cast
-            explain_statement = statement.copy()
-            for select in explain_statement.find_all(exp.Select):
-                if select.args.get("from"):
-                    select.set("limit", None)
-                    select.set("where", None)
+            select_statement = statement.expression.copy()
+            for select_or_union in select_statement.find_all(exp.Select, exp.Union):
+                select_or_union.set("limit", None)
+                select_or_union.set("where", None)
+
+            temp_view_name = exp.table_(f"#sqlmesh__{random_id()}")
+            self.create_view(
+                temp_view_name, select_statement, replace=False, no_schema_binding=False
+            )
+            columns_to_types_from_view = self.columns(temp_view_name)
 
-            explain_statement_sql = explain_statement.sql(
-                dialect=self.dialect, identify=True, unsupported_level=ErrorLevel.IGNORE, copy=False
+            schema = self._build_schema_exp(
+                exp.to_table(table_name_or_schema),
+                columns_to_types_from_view,
             )
-            plan = parse_plan(
-                "\n".join(r[0] for r in self.fetchall(f"EXPLAIN VERBOSE {explain_statement_sql}"))
+            statement = super()._build_create_table_exp(
+                schema,
+                None,
+                exists=exists,
+                replace=replace,
+                columns_to_types=columns_to_types_from_view,
+                table_description=table_description,
+                **kwargs,
             )
 
-            if plan:
-                select = exp.Select().from_(statement.expression.subquery("_subquery"))
-                statement.expression.replace(select)
-
-                for target in plan["targetlist"]:  # type: ignore
-                    if target["name"] == "TARGETENTRY":
-                        resdom = target["resdom"]
-                        resname = resdom["resname"]
-                        if resname == "<>":
-                            # A synthetic column added by Redshift to compute a window function.
-                            continue
-                        if resname == "? column ?":
-                            table_name_str = (
-                                table_name_or_schema
-                                if isinstance(table_name_or_schema, str)
-                                else table_name_or_schema.sql(dialect=self.dialect)
-                            )
-                            raise SQLMeshError(f"Missing column name for table '{table_name_str}'")
-                        # https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
-                        restype = resdom["restype"]
-                        data_type: t.Optional[str] = None
-                        if restype == "1043":
-                            size = (
-                                int(resdom["restypmod"]) - 4
-                                if resdom["restypmod"] != "- 1"
-                                else "MAX"
-                            )
-                            # Cast NULL instead of the original projection to trick the planner into assigning a
-                            # correct type to the column.
-                            data_type = f"VARCHAR({size})"
-                        else:
-                            data_type = REDSHIFT_PLAN_TYPE_MAPPINGS.get(restype)
-
-                        if data_type:
-                            select.select(
-                                exp.cast(
-                                    exp.null(),
-                                    data_type,
-                                    dialect=self.dialect,
-                                ).as_(resname),
-                                copy=False,
-                            )
-                        else:
-                            select.select(resname, copy=False)
-
         return statement
 
     def create_view(
@@ -209,7 +176,7 @@ class RedshiftEngineAdapter(
             materialized,
             table_description=table_description,
             column_descriptions=column_descriptions,
-            no_schema_binding=True,
+            no_schema_binding=create_kwargs.pop("no_schema_binding", True),
             **create_kwargs,
         )
 
@@ -309,90 +276,3 @@ class RedshiftEngineAdapter(
             )
             for row in df.itertuples()
         ]
-
-
-def parse_plan(plan: str) -> t.Optional[t.Dict]:
-    """Parse the output of a redshift explain verbose query plan into a Python dict."""
-    from sqlglot import Tokenizer, TokenType
-    from sqlglot.tokens import Token
-
-    tokens = Tokenizer().tokenize(plan)
-    i = 0
-    terminal_tokens = {TokenType.L_PAREN, TokenType.R_PAREN, TokenType.R_BRACE, TokenType.COLON}
-
-    def curr() -> t.Optional[TokenType]:
-        return tokens[i].token_type if i < len(tokens) else None
-
-    def advance() -> Token:
-        nonlocal i
-        i += 1
-        return tokens[i - 1]
-
-    def match(token_type: TokenType, raise_unmatched: bool = False) -> t.Optional[Token]:
-        if curr() == token_type:
-            return advance()
-        if raise_unmatched:
-            raise Exception(f"Expected {token_type}")
-        return None
-
-    def parse_value() -> t.Any:
-        if match(TokenType.L_PAREN):
-            values = []
-            while not match(TokenType.R_PAREN):
-                values.append(parse_value())
-            return values
-
-        nested = parse_nested()
-
-        if nested:
-            return nested
-
-        value = []
-
-        while not curr() in terminal_tokens:
-            value.append(advance().text)
-
-        return " ".join(value)
-
-    def parse_nested() -> t.Optional[t.Dict]:
-        if not match(TokenType.L_BRACE):
-            return None
-        query_plan = {}
-        query_plan["name"] = advance().text
-
-        while match(TokenType.COLON):
-            key = advance().text
-
-            while match(TokenType.DOT):
-                key += f".{advance().text}"
-
-            query_plan[key] = parse_value()
-
-        match(TokenType.R_BRACE, True)
-        return query_plan
-
-    while curr():
-        nested = parse_nested()
-
-        if nested and nested.get("name") in ("RESULT", "SEQSCAN"):
-            return nested
-        advance()
-    return None
-
-
-# https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
-REDSHIFT_PLAN_TYPE_MAPPINGS = {
-    "16": "BOOL",
-    "18": "CHAR",
-    "21": "SMALLINT",
-    "23": "INT",
-    "20": "BIGINT",
-    "1700": "NUMERIC",
-    "700": "FLOAT",
-    "701": "DOUBLE",
-    "1114": "TIMESTAMP",
-    "1184": "TIMESTAMPTZ",
-    "1083": "TIME",
-    "1266": "TIMETZ",
-    "1082": "DATE",
-}
diff --git a/sqlmesh/core/snapshot/evaluator.py b/sqlmesh/core/snapshot/evaluator.py
index dc185a3b..98e47840 100644
--- a/sqlmesh/core/snapshot/evaluator.py
+++ b/sqlmesh/core/snapshot/evaluator.py
@@ -1094,10 +1094,12 @@ class MaterializableStrategy(PromotableStrategy):
                 column_descriptions=model.column_descriptions if is_table_deployable else None,
             )
 
-            # only sql models have queries that can be tested
-            # additionally, we always create temp tables and sometimes
-            # we additionally created prod tables, so we only need to test one.
-            if model.is_sql and not is_table_deployable:
+            # Only sql models have queries that can be tested.
+            # Additionally, we always create temp tables and sometimes we additionally created prod tables,
+            # we need to make sure that we only dry run once.
+            # We also need to make sure that we don't dry run on Redshift because its planner / optimizer sometimes
+            # breaks on our CTAS queries due to us relying on the WHERE FALSE LIMIT 0 combo.
+            if model.is_sql and not is_table_deployable and self.adapter.dialect != "redshift":
                 logger.info("Dry running model '%s'", model.name)
                 self.adapter.fetchall(ctas_query)
         else:


Test patch:
diff --git a/tests/core/engine_adapter/test_redshift.py b/tests/core/engine_adapter/test_redshift.py
index 91044531..df13be88 100644
--- a/tests/core/engine_adapter/test_redshift.py
+++ b/tests/core/engine_adapter/test_redshift.py
@@ -8,7 +8,6 @@ from sqlglot import expressions as exp
 from sqlglot import parse_one
 
 from sqlmesh.core.engine_adapter import RedshiftEngineAdapter
-from sqlmesh.core.engine_adapter.redshift import parse_plan
 from tests.core.engine_adapter import to_sql_calls
 
 pytestmark = [pytest.mark.engine, pytest.mark.redshift]
@@ -33,82 +32,42 @@ def test_columns(adapter: t.Callable):
 def test_create_table_from_query_exists_no_if_not_exists(
     adapter: t.Callable, mocker: MockerFixture
 ):
+    mocker.patch(
+        "sqlmesh.core.engine_adapter.redshift.random_id",
+        return_value="test_random_id",
+    )
+
     mocker.patch(
         "sqlmesh.core.engine_adapter.redshift.RedshiftEngineAdapter.table_exists",
         return_value=True,
     )
 
-    mocker.patch(
-        "sqlmesh.core.engine_adapter.redshift.parse_plan",
+    columns_mock = mocker.patch(
+        "sqlmesh.core.engine_adapter.redshift.RedshiftEngineAdapter.columns",
         return_value={
-            "targetlist": [
-                {
-                    "name": "TARGETENTRY",
-                    "resdom": {
-                        "resname": "a",
-                        "restype": "1043",
-                        "restypmod": "- 1",
-                    },
-                },
-                {
-                    "name": "TARGETENTRY",
-                    "resdom": {
-                        "resname": "b",
-                        "restype": "1043",
-                        "restypmod": "64",
-                    },
-                },
-                {
-                    "name": "TARGETENTRY",
-                    "resdom": {
-                        "resname": "c",
-                        "restype": "1043",
-                        "restypmod": "- 1",
-                    },
-                },
-                {
-                    "name": "TARGETENTRY",
-                    "resdom": {
-                        "resname": "d",
-                        "restype": "1043",
-                        "restypmod": "- 1",
-                    },
-                },
-                {
-                    "name": "TARGETENTRY",
-                    "resdom": {
-                        "resname": "e",
-                        "restype": "1114",
-                        "restypmod": "- 1",
-                    },
-                },
-                {
-                    "name": "TARGETENTRY",
-                    "resdom": {
-                        "resname": "f",
-                        "restype": "0000",  # Unknown type
-                        "restypmod": "- 1",
-                    },
-                },
-            ]
+            "a": exp.DataType.build("VARCHAR(MAX)", dialect="redshift"),
+            "b": exp.DataType.build("VARCHAR(60)", dialect="redshift"),
+            "c": exp.DataType.build("VARCHAR(MAX)", dialect="redshift"),
+            "d": exp.DataType.build("VARCHAR(MAX)", dialect="redshift"),
+            "e": exp.DataType.build("TIMESTAMP", dialect="redshift"),
         },
     )
 
     adapter.ctas(
-        table_name="test_table",
+        table_name="test_schema.test_table",
         query_or_df=parse_one(
-            "SELECT a, b, x + 1 AS c, d AS d, e, f FROM (SELECT * FROM table WHERE FALSE LIMIT 0) WHERE d > 0 AND FALSE LIMIT 0"
+            "SELECT a, b, x + 1 AS c, d AS d, e FROM (SELECT * FROM table WHERE FALSE LIMIT 0) WHERE d > 0 AND FALSE LIMIT 0"
         ),
         exists=False,
     )
 
     assert to_sql_calls(adapter) == [
-        'EXPLAIN VERBOSE CREATE TABLE "test_table" AS SELECT "a", "b", "x" + 1 AS "c", "d" AS "d", "e", "f" FROM (SELECT * FROM "table")',
-        'CREATE TABLE "test_table" AS SELECT CAST(NULL AS VARCHAR(MAX)) AS "a", CAST(NULL AS VARCHAR(60)) AS "b", CAST(NULL '
-        'AS VARCHAR(MAX)) AS "c", CAST(NULL AS VARCHAR(MAX)) AS "d", CAST(NULL AS TIMESTAMP) AS "e", "f" FROM (SELECT "a", "b", "x" + 1 '
-        'AS "c", "d" AS "d", "e", "f" FROM (SELECT * FROM "table" WHERE FALSE LIMIT 0) WHERE "d" > 0 AND FALSE LIMIT 0) AS "_subquery"',
+        'CREATE VIEW "#sqlmesh__test_random_id" AS SELECT "a", "b", "x" + 1 AS "c", "d" AS "d", "e" FROM (SELECT * FROM "table")',
+        'CREATE TABLE "test_schema"."test_table" ("a" VARCHAR(MAX), "b" VARCHAR(60), "c" VARCHAR(MAX), "d" VARCHAR(MAX), "e" TIMESTAMP)',
     ]
 
+    columns_mock.assert_called_once_with(exp.table_("#sqlmesh__test_random_id"))
+
 
 def test_create_table_from_query_exists_and_if_not_exists(
     adapter: t.Callable, mocker: MockerFixture
@@ -293,675 +252,3 @@ def test_create_view(adapter: t.Callable):
         'DROP VIEW IF EXISTS "test_view" CASCADE',
         'CREATE VIEW "test_view" ("a", "b") AS SELECT "cola" FROM "table" WITH NO SCHEMA BINDING',
     ]
-
-
-def test_parse_plan():
-    plan = parse_plan(
-        """
-{ RESULT
-  :startup_cost 0.00
-  :total_cost 0.07
-  :plan_rows 2
-  :node_id 1
-  :parent_id 0
-  :plan_width 32
-  :best_pathkeys <>
-  :dist_info.dist_strategy DS_DIST_NONE
-  :dist_info.dist_keys <>
-  :dist_info.seqscan_is_distributed false
-  :dist_info.topology 1966505242
-  :phys_properties <>
-  :reqd_phys_properties <>
-  :targetlist (
-    { TARGETENTRY
-    :resdom
-      { RESDOM
-      :resno 1
-      :restype 25
-      :restypmod 36
-      :resname cola
-      :ressortgroupref 0
-      :resorigtbl 0
-      :resorigcol 0
-      :resjunk false
-      }
-    :expr
-      { FUNCEXPR
-      :funcid 2311
-      :funcresulttype 25
-      :funcretset false
-      :funcformat 0
-      :args (
-        { RELABELTYPE
-        :arg
-          { VAR
-          :varno 65001
-          :varattno 1
-          :vartype 1043
-          :vartypmod -1
-          :varlevelsup 0
-          :varnoold 2
-          :varoattno 1
-          }
-        :resulttype 25
-        :resulttypmod -1
-        :relabelformat 0
-        }
-      )
-      }
-    }
-  )
-  :non_null_target (b)
-  :qual <>
-  :lefttree
-    { SUBQUERYSCAN
-    :startup_cost 0.00
-    :total_cost 0.06
-    :plan_rows 2
-    :node_id 2
-    :parent_id 1
-    :plan_width 32
-    :best_pathkeys <>
-    :dist_info.dist_strategy DS_DIST_ERR
-    :dist_info.dist_keys <>
-    :dist_info.seqscan_is_distributed false
-    :dist_info.topology 1966505242
-    :phys_properties <>
-    :reqd_phys_properties <>
-    :targetlist (
-      { TARGETENTRY
-      :resdom
-        { RESDOM
-        :resno 1
-        :restype 1043
-        :restypmod -1
-        :resname <>
-        :ressortgroupref 0
-        :resorigtbl 0
-        :resorigcol 0
-        :resjunk false
-        }
-      :expr
-        { VAR
-        :varno 2
-        :varattno 1
-        :vartype 1043
-        :vartypmod -1
-        :varlevelsup 0
-        :varnoold 2
-        :varoattno 1
-        }
-      }
-    )
-    :non_null_target (b)
-    :qual <>
-    :lefttree <>
-    :righttree <>
-    :initPlan <>
-    :extParam (b)
-    :allParam (b)
-    :nParamExec 0
-    :scanrelid 2
-    :tuples 0
-    :subplan
-      { APPEND
-      :startup_cost 0.00
-      :total_cost 0.04
-      :plan_rows 2
-      :node_id 3
-      :parent_id 2
-      :plan_width 0
-      :best_pathkeys <>
-      :dist_info.dist_strategy DS_DIST_ERR
-      :dist_info.dist_keys <>
-      :dist_info.seqscan_is_distributed false
-      :dist_info.topology 1966505242
-      :phys_properties <>
-      :reqd_phys_properties <>
-      :targetlist (
-        { TARGETENTRY
-        :resdom
-          { RESDOM
-          :resno 1
-          :restype 1043
-          :restypmod 5
-          :resname cola
-          :ressortgroupref 0
-          :resorigtbl 0
-          :resorigcol 0
-          :resjunk false
-          }
-        :expr
-          { VAR
-          :varno 0
-          :varattno 1
-          :vartype 1043
-          :vartypmod 5
-          :varlevelsup 0
-          :varnoold 0
-          :varoattno 1
-          }
-        }
-      )
-      :non_null_target (b)
-      :qual <>
-      :lefttree <>
-      :righttree <>
-      :initPlan <>
-      :extParam (b)
-      :allParam (b)
-      :nParamExec 0
-      :appendplans (
-        { NETWORK
-        :startup_cost 0.00
-        :total_cost 0.02
-        :plan_rows 1
-        :node_id 4
-        :parent_id 3
-        :plan_width 0
-        :best_pathkeys <>
-        :dist_info.dist_strategy DS_DIST_ERR
-        :dist_info.dist_keys <>
-        :dist_info.seqscan_is_distributed false
-        :dist_info.topology 1966505242
-        :phys_properties <>
-        :reqd_phys_properties <>
-        :targetlist (
-          { TARGETENTRY
-          :resdom
-            { RESDOM
-            :resno 1
-            :restype 1043
-            :restypmod 5
-            :resname cola
-            :ressortgroupref 0
-            :resorigtbl 0
-            :resorigcol 0
-            :resjunk false
-            }
-          :expr
-            { CONST
-            :consttype 1043
-            :constlen -1
-            :constbyval false
-            :constisnull false
-            :constvalue 5 [ 5 0 0 0 49 ]
-            }
-          }
-        )
-        :non_null_target (b)
-        :qual <>
-        :lefttree
-          { SUBQUERYSCAN
-          :startup_cost 0.00
-          :total_cost 0.02
-          :plan_rows 1
-          :node_id 5
-          :parent_id 4
-          :plan_width 0
-          :best_pathkeys <>
-          :dist_info.dist_strategy DS_DIST_ERR
-          :dist_info.dist_keys <>
-          :dist_info.seqscan_is_distributed false
-          :dist_info.topology 1966505242
-          :phys_properties <>
-          :reqd_phys_properties <>
-          :targetlist (
-            { TARGETENTRY
-            :resdom
-              { RESDOM
-              :resno 1
-              :restype 1043
-              :restypmod 5
-              :resname cola
-              :ressortgroupref 0
-              :resorigtbl 0
-              :resorigcol 0
-              :resjunk false
-              }
-            :expr
-              { FUNCEXPR
-              :funcid 669
-              :funcresulttype 1043
-              :funcretset false
-              :funcformat 2
-              :args (
-                { CONST
-                :consttype 1043
-                :constlen -1
-                :constbyval false
-                :constisnull false
-                :constvalue 5 [ 5 0 0 0 49 ]
-                }
-                { CONST
-                :consttype 23
-                :constlen 4
-                :constbyval true
-                :constisnull false
-                :constvalue 4 [ 5 0 0 0 0 0 0 0 ]
-                }
-                { CONST
-                :consttype 16
-                :constlen 1
-                :constbyval true
-                :constisnull false
-                :constvalue 1 [ 0 0 0 0 0 0 0 0 ]
-                }
-              )
-              }
-            }
-          )
-          :non_null_target (b)
-          :qual <>
-          :lefttree <>
-          :righttree <>
-          :initPlan <>
-          :extParam (b)
-          :allParam (b)
-          :nParamExec 0
-          :scanrelid 1
-          :tuples 0
-          :subplan
-            { RESULT
-            :startup_cost 0.00
-            :total_cost 0.01
-            :plan_rows 1
-            :node_id 6
-            :parent_id 5
-            :plan_width 0
-            :best_pathkeys <>
-            :dist_info.dist_strategy DS_DIST_NONE
-            :dist_info.dist_keys <>
-            :dist_info.seqscan_is_distributed false
-            :dist_info.topology 1966505242
-            :phys_properties <>
-            :reqd_phys_properties <>
-            :targetlist (
-              { TARGETENTRY
-              :resdom
-                { RESDOM
-                :resno 1
-                :restype 1043
-                :restypmod 204
-                :resname cola
-                :ressortgroupref 0
-                :resorigtbl 0
-                :resorigcol 0
-                :resjunk false
-                }
-              :expr
-                { CONST
-                :consttype 1043
-                :constlen -1
-                :constbyval false
-                :constisnull false
-                :constvalue 5 [ 5 0 0 0 49 ]
-                }
-              }
-            )
-            :non_null_target (b)
-            :qual <>
-            :lefttree <>
-            :righttree <>
-            :initPlan <>
-            :extParam (b)
-            :allParam (b)
-            :nParamExec 0
-            :resconstantqual <>
-            :scanrelid 0
-            :values_lists <>
-            }
-          }
-        :righttree <>
-        :initPlan <>
-        :extParam (b)
-        :allParam (b)
-        :nParamExec 0
-        :dataMovement Distribute
-        }
-        { NETWORK
-        :startup_cost 0.00
-        :total_cost 0.02
-        :plan_rows 1
-        :node_id 7
-        :parent_id 3
-        :plan_width 0
-        :best_pathkeys <>
-        :dist_info.dist_strategy DS_DIST_ERR
-        :dist_info.dist_keys <>
-        :dist_info.seqscan_is_distributed false
-        :dist_info.topology 1966505242
-        :phys_properties <>
-        :reqd_phys_properties <>
-        :targetlist (
-          { TARGETENTRY
-          :resdom
-            { RESDOM
-            :resno 1
-            :restype 1043
-            :restypmod 5
-            :resname cola
-            :ressortgroupref 0
-            :resorigtbl 0
-            :resorigcol 0
-            :resjunk false
-            }
-          :expr
-            { CONST
-            :consttype 1043
-            :constlen -1
-            :constbyval false
-            :constisnull false
-            :constvalue 5 [ 5 0 0 0 51 ]
-            }
-          }
-        )
-        :non_null_target (b)
-        :qual <>
-        :lefttree
-          { SUBQUERYSCAN
-          :startup_cost 0.00
-          :total_cost 0.02
-          :plan_rows 1
-          :node_id 8
-          :parent_id 7
-          :plan_width 0
-          :best_pathkeys <>
-          :dist_info.dist_strategy DS_DIST_ERR
-          :dist_info.dist_keys <>
-          :dist_info.seqscan_is_distributed false
-          :dist_info.topology 1966505242
-          :phys_properties <>
-          :reqd_phys_properties <>
-          :targetlist (
-            { TARGETENTRY
-            :resdom
-              { RESDOM
-              :resno 1
-              :restype 1043
-              :restypmod 5
-              :resname cola
-              :ressortgroupref 0
-              :resorigtbl 0
-              :resorigcol 0
-              :resjunk false
-              }
-            :expr
-              { FUNCEXPR
-              :funcid 669
-              :funcresulttype 1043
-              :funcretset false
-              :funcformat 2
-              :args (
-                { CONST
-                :consttype 1043
-                :constlen -1
-                :constbyval false
-                :constisnull false
-                :constvalue 5 [ 5 0 0 0 51 ]
-                }
-                { CONST
-                :consttype 23
-                :constlen 4
-                :constbyval true
-                :constisnull false
-                :constvalue 4 [ 5 0 0 0 0 0 0 0 ]
-                }
-                { CONST
-                :consttype 16
-                :constlen 1
-                :constbyval true
-                :constisnull false
-                :constvalue 1 [ 0 0 0 0 0 0 0 0 ]
-                }
-              )
-              }
-            }
-          )
-          :non_null_target (b)
-          :qual <>
-          :lefttree <>
-          :righttree <>
-          :initPlan <>
-          :extParam (b)
-          :allParam (b)
-          :nParamExec 0
-          :scanrelid 2
-          :tuples 0
-          :subplan
-            { RESULT
-            :startup_cost 0.00
-            :total_cost 0.01
-            :plan_rows 1
-            :node_id 9
-            :parent_id 8
-            :plan_width 0
-            :best_pathkeys <>
-            :dist_info.dist_strategy DS_DIST_NONE
-            :dist_info.dist_keys <>
-            :dist_info.seqscan_is_distributed false
-            :dist_info.topology 1966505242
-            :phys_properties <>
-            :reqd_phys_properties <>
-            :targetlist (
-              { TARGETENTRY
-              :resdom
-                { RESDOM
-                :resno 1
-                :restype 1043
-                :restypmod 204
-                :resname varchar
-                :ressortgroupref 0
-                :resorigtbl 0
-                :resorigcol 0
-                :resjunk false
-                }
-              :expr
-                { CONST
-                :consttype 1043
-                :constlen -1
-                :constbyval false
-                :constisnull false
-                :constvalue 5 [ 5 0 0 0 51 ]
-                }
-              }
-            )
-            :non_null_target (b)
-            :qual <>
-            :lefttree <>
-            :righttree <>
-            :initPlan <>
-            :extParam (b)
-            :allParam (b)
-            :nParamExec 0
-            :resconstantqual <>
-            :scanrelid 0
-            :values_lists <>
-            }
-          }
-        :righttree <>
-        :initPlan <>
-        :extParam (b)
-        :allParam (b)
-        :nParamExec 0
-        :dataMovement Distribute
-        }
-      )
-      :isTarget false
-      :streamable false
-      }
-    }
-  :righttree <>
-  :initPlan <>
-  :extParam (b)
-  :allParam (b)
-  :nParamExec 0
-  :resconstantqual (
-    { CONST
-    :consttype 16
-    :constlen 1
-    :constbyval true
-    :constisnull false
-    :constvalue 1 [ 0 0 0 0 0 0 0 0 ]
-    }
-    { CONST
-    :consttype 16
-    :constlen 1
-    :constbyval true
-    :constisnull false
-    :constvalue 1 [ 0 0 0 0 0 0 0 0 ]
-    }
-  )
-  :scanrelid 0
-  :values_lists <>
-  }
-    """
-    )
-    assert plan["targetlist"] == [
-        {
-            "expr": {
-                "args": [
-                    {
-                        "arg": {
-                            "name": "VAR",
-                            "varattno": "1",
-                            "varlevelsup": "0",
-                            "varno": "65001",
-                            "varnoold": "2",
-                            "varoattno": "1",
-                            "vartype": "1043",
-                            "vartypmod": "- 1",
-                        },
-                        "name": "RELABELTYPE",
-                        "relabelformat": "0",
-                        "resulttype": "25",
-                        "resulttypmod": "- 1",
-                    }
-                ],
-                "funcformat": "0",
-                "funcid": "2311",
-                "funcresulttype": "25",
-                "funcretset": "false",
-                "name": "FUNCEXPR",
-            },
-            "name": "TARGETENTRY",
-            "resdom": {
-                "name": "RESDOM",
-                "resjunk": "false",
-                "resname": "cola",
-                "resno": "1",
-                "resorigcol": "0",
-                "resorigtbl": "0",
-                "ressortgroupref": "0",
-                "restype": "25",
-                "restypmod": "36",
-            },
-        },
-    ]
-
-
-def test_parse_plan_limit():
-    plan = parse_plan(
-        """
-{ LIMIT
-  :startup_cost 0.00
-  :total_cost 0.00
-  :plan_rows 1
-  :node_id 1
-  :parent_id 0
-  :plan_width 0
-  :best_pathkeys <>
-  :phys_properties <>
-  :reqd_phys_properties <>
-  :targetlist (
-    { TARGETENTRY
-    :resdom
-      { RESDOM
-      :resno 1
-      :restype 20
-      :restypmod -1
-      :resname ?column?
-      :ressortgroupref 0
-      :resorigtbl 0
-      :resorigcol 0
-      :resjunk false
-      }
-    :expr
-      { CONST
-      :consttype 20
-      :constlen 8
-      :constbyval true
-      :constisnull true
-      :constvalue <>
-      }
-    }
-  )
-  }
-
-XN Limit  (cost=0.00..0.00 rows=1 width=0)
-  ->  XN Result  (cost=0.00..0.01 rows=1 width=0)
-        One-Time Filter: false
-
-  { RESULT
-  :targetlist (
-    { TARGETENTRY
-    :resdom
-      { RESDOM
-      :resno 1
-      :restype 1043
-      :restypmod 36
-      :resname surrogate_key
-      :ressortgroupref 0
-      :resorigtbl 0
-      :resorigcol 0
-      :resjunk false
-      }
-    :expr
-      { VAR
-      :varno 65001
-      :varattno 1
-      :vartype 1043
-      :vartypmod 36
-      :varlevelsup 0
-      :varnoold 1
-      :varoattno 1
-      }
-    }
-  )
-  :scanrelid 0
-  :values_lists <>
-  }
-        """
-    )
-
-    assert plan == {
-        "name": "RESULT",
-        "scanrelid": "0",
-        "targetlist": [
-            {
-                "expr": {
-                    "name": "VAR",
-                    "varattno": "1",
-                    "varlevelsup": "0",
-                    "varno": "65001",
-                    "varnoold": "1",
-                    "varoattno": "1",
-                    "vartype": "1043",
-                    "vartypmod": "36",
-                },
-                "name": "TARGETENTRY",
-                "resdom": {
-                    "name": "RESDOM",
-                    "resjunk": "false",
-                    "resname": "surrogate_key",
-                    "resno": "1",
-                    "resorigcol": "0",
-                    "resorigtbl": "0",
-                    "ressortgroupref": "0",
-                    "restype": "1043",
-                    "restypmod": "36",
-                },
-            }
-        ],
-        "values_lists": "<>",
-    }