From 7afd56c3c6d8360a5bfdfb2de30038b239fd756b Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 26 Jan 2017 22:09:34 -0500
Subject: [PATCH] Use castNode() in a bunch of statement-list-related code.

When I wrote commit ab1f0c822, I really missed the castNode() macro that
Peter E. had proposed shortly before.  This back-fills the uses I would
have put it to.  It's probably not all that significant, but there are
more assertions here than there were before, and conceivably they will
help catch any bugs associated with those representation changes.

I left behind a number of usages like "(Query *) copyObject(query_var)".
Those could have been converted as well, but Peter has proposed another
notational improvement that would handle copyObject cases automatically,
so I let that be for now.
---
 src/backend/catalog/pg_proc.c       |  2 +-
 src/backend/commands/createas.c     |  2 +-
 src/backend/commands/explain.c      | 15 +++++--------
 src/backend/commands/extension.c    |  4 ++--
 src/backend/commands/foreigncmds.c  |  2 +-
 src/backend/commands/portalcmds.c   |  6 ++---
 src/backend/commands/prepare.c      |  6 ++---
 src/backend/commands/tablecmds.c    |  2 +-
 src/backend/executor/functions.c    |  4 ++--
 src/backend/executor/spi.c          | 18 +++++++--------
 src/backend/parser/gram.y           |  2 +-
 src/backend/parser/parse_expr.c     |  6 ++---
 src/backend/parser/parse_type.c     |  2 +-
 src/backend/rewrite/rewriteDefine.c | 10 ++++-----
 src/backend/tcop/postgres.c         | 12 +++++-----
 src/backend/tcop/pquery.c           |  6 ++---
 src/backend/tcop/utility.c          |  9 +++-----
 src/backend/utils/cache/plancache.c | 35 +++++++++++------------------
 src/backend/utils/mmgr/portalmem.c  |  4 +---
 src/pl/plpgsql/src/pl_exec.c        |  6 ++---
 20 files changed, 63 insertions(+), 90 deletions(-)

diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index bb83a9a7c6e..6ab849c6ef5 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -930,7 +930,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
 			querytree_list = NIL;
 			foreach(lc, raw_parsetree_list)
 			{
-				RawStmt    *parsetree = (RawStmt *) lfirst(lc);
+				RawStmt    *parsetree = castNode(RawStmt, lfirst(lc));
 				List	   *querytree_sublist;
 
 				querytree_sublist = pg_analyze_and_rewrite_params(parsetree,
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 02cfcd182d0..646a88409f2 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -322,7 +322,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
 			elog(ERROR, "unexpected rewrite result for %s",
 				 is_matview ? "CREATE MATERIALIZED VIEW" :
 				 "CREATE TABLE AS SELECT");
-		query = (Query *) linitial(rewritten);
+		query = castNode(Query, linitial(rewritten));
 		Assert(query->commandType == CMD_SELECT);
 
 		/* plan the query --- note we disallow parallelism */
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 5d61a0195ed..0a67be031be 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -224,8 +224,7 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
 	 * executed repeatedly.  (See also the same hack in DECLARE CURSOR and
 	 * PREPARE.)  XXX FIXME someday.
 	 */
-	Assert(IsA(stmt->query, Query));
-	rewritten = QueryRewrite((Query *) copyObject(stmt->query));
+	rewritten = QueryRewrite(castNode(Query, copyObject(stmt->query)));
 
 	/* emit opening boilerplate */
 	ExplainBeginOutput(es);
@@ -246,7 +245,7 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
 		/* Explain every plan */
 		foreach(l, rewritten)
 		{
-			ExplainOneQuery((Query *) lfirst(l),
+			ExplainOneQuery(castNode(Query, lfirst(l)),
 							CURSOR_OPT_PARALLEL_OK, NULL, es,
 							queryString, params);
 
@@ -395,10 +394,9 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
 		CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
 		List	   *rewritten;
 
-		Assert(IsA(ctas->query, Query));
-		rewritten = QueryRewrite((Query *) copyObject(ctas->query));
+		rewritten = QueryRewrite(castNode(Query, copyObject(ctas->query)));
 		Assert(list_length(rewritten) == 1);
-		ExplainOneQuery((Query *) linitial(rewritten),
+		ExplainOneQuery(castNode(Query, linitial(rewritten)),
 						0, ctas->into, es,
 						queryString, params);
 	}
@@ -415,10 +413,9 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
 		DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
 		List	   *rewritten;
 
-		Assert(IsA(dcs->query, Query));
-		rewritten = QueryRewrite((Query *) copyObject(dcs->query));
+		rewritten = QueryRewrite(castNode(Query, copyObject(dcs->query)));
 		Assert(list_length(rewritten) == 1);
-		ExplainOneQuery((Query *) linitial(rewritten),
+		ExplainOneQuery(castNode(Query, linitial(rewritten)),
 						dcs->options, NULL, es,
 						queryString, params);
 	}
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 554fdc46b41..9680d986a01 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -713,7 +713,7 @@ execute_sql_string(const char *sql, const char *filename)
 	 */
 	foreach(lc1, raw_parsetree_list)
 	{
-		RawStmt    *parsetree = (RawStmt *) lfirst(lc1);
+		RawStmt    *parsetree = castNode(RawStmt, lfirst(lc1));
 		List	   *stmt_list;
 		ListCell   *lc2;
 
@@ -725,7 +725,7 @@ execute_sql_string(const char *sql, const char *filename)
 
 		foreach(lc2, stmt_list)
 		{
-			PlannedStmt *stmt = (PlannedStmt *) lfirst(lc2);
+			PlannedStmt *stmt = castNode(PlannedStmt, lfirst(lc2));
 
 			CommandCounterIncrement();
 
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 476a023ec54..6ff8b6998be 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -1572,7 +1572,7 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt)
 		 */
 		foreach(lc2, raw_parsetree_list)
 		{
-			RawStmt    *rs = (RawStmt *) lfirst(lc2);
+			RawStmt    *rs = castNode(RawStmt, lfirst(lc2));
 			CreateForeignTableStmt *cstmt = (CreateForeignTableStmt *) rs->stmt;
 			PlannedStmt *pstmt;
 
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 1d3e39299b9..29d0430dd87 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -42,14 +42,12 @@ void
 PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params,
 				  const char *queryString, bool isTopLevel)
 {
-	Query	   *query = (Query *) cstmt->query;
+	Query	   *query = castNode(Query, cstmt->query);
 	List	   *rewritten;
 	PlannedStmt *plan;
 	Portal		portal;
 	MemoryContext oldContext;
 
-	Assert(IsA(query, Query));	/* else parse analysis wasn't done */
-
 	/*
 	 * Disallow empty-string cursor name (conflicts with protocol-level
 	 * unnamed portal).
@@ -85,7 +83,7 @@ PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params,
 	if (list_length(rewritten) != 1)
 		elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
 
-	query = (Query *) linitial(rewritten);
+	query = castNode(Query, linitial(rewritten));
 
 	if (query->commandType != CMD_SELECT)
 		elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 7d7e3daf1e7..7b61da3ef00 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -265,8 +265,7 @@ ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause,
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("prepared statement is not a SELECT")));
-		pstmt = (PlannedStmt *) linitial(plan_list);
-		Assert(IsA(pstmt, PlannedStmt));
+		pstmt = castNode(PlannedStmt, linitial(plan_list));
 		if (pstmt->commandType != CMD_SELECT)
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -670,9 +669,8 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
 	/* Explain each query */
 	foreach(p, plan_list)
 	{
-		PlannedStmt *pstmt = (PlannedStmt *) lfirst(p);
+		PlannedStmt *pstmt = castNode(PlannedStmt, lfirst(p));
 
-		Assert(IsA(pstmt, PlannedStmt));
 		if (pstmt->commandType != CMD_UTILITY)
 			ExplainOnePlan(pstmt, into, es, query_string, paramLI, NULL);
 		else
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 04b5d9a943c..90f2f7f00e2 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9281,7 +9281,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
 	querytree_list = NIL;
 	foreach(list_item, raw_parsetree_list)
 	{
-		RawStmt    *rs = (RawStmt *) lfirst(list_item);
+		RawStmt    *rs = castNode(RawStmt, lfirst(list_item));
 		Node	   *stmt = rs->stmt;
 
 		if (IsA(stmt, IndexStmt))
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 15c709139ad..2d49a656502 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -707,7 +707,7 @@ init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK)
 	flat_query_list = NIL;
 	foreach(lc, raw_parsetree_list)
 	{
-		RawStmt    *parsetree = (RawStmt *) lfirst(lc);
+		RawStmt    *parsetree = castNode(RawStmt, lfirst(lc));
 		List	   *queryTree_sublist;
 
 		queryTree_sublist = pg_analyze_and_rewrite_params(parsetree,
@@ -1551,7 +1551,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
 	parse = NULL;
 	foreach(lc, queryTreeList)
 	{
-		Query	   *q = (Query *) lfirst(lc);
+		Query	   *q = castNode(Query, lfirst(lc));
 
 		if (q->canSetTag)
 			parse = q;
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 7bd37283b7f..55f97b14e6e 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1232,9 +1232,9 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
 	if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
 	{
 		if (list_length(stmt_list) == 1 &&
-		 ((PlannedStmt *) linitial(stmt_list))->commandType != CMD_UTILITY &&
-			((PlannedStmt *) linitial(stmt_list))->rowMarks == NIL &&
-			ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree))
+			castNode(PlannedStmt, linitial(stmt_list))->commandType != CMD_UTILITY &&
+			castNode(PlannedStmt, linitial(stmt_list))->rowMarks == NIL &&
+			ExecSupportsBackwardScan(castNode(PlannedStmt, linitial(stmt_list))->planTree))
 			portal->cursorOptions |= CURSOR_OPT_SCROLL;
 		else
 			portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
@@ -1248,8 +1248,8 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
 	if (portal->cursorOptions & CURSOR_OPT_SCROLL)
 	{
 		if (list_length(stmt_list) == 1 &&
-		 ((PlannedStmt *) linitial(stmt_list))->commandType != CMD_UTILITY &&
-			((PlannedStmt *) linitial(stmt_list))->rowMarks != NIL)
+			castNode(PlannedStmt, linitial(stmt_list))->commandType != CMD_UTILITY &&
+			castNode(PlannedStmt, linitial(stmt_list))->rowMarks != NIL)
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"),
@@ -1270,7 +1270,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
 
 		foreach(lc, stmt_list)
 		{
-			PlannedStmt *pstmt = (PlannedStmt *) lfirst(lc);
+			PlannedStmt *pstmt = castNode(PlannedStmt, lfirst(lc));
 
 			if (!CommandIsReadOnly(pstmt))
 			{
@@ -1757,7 +1757,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
 
 	foreach(list_item, raw_parsetree_list)
 	{
-		RawStmt    *parsetree = (RawStmt *) lfirst(list_item);
+		RawStmt    *parsetree = castNode(RawStmt, lfirst(list_item));
 		List	   *stmt_list;
 		CachedPlanSource *plansource;
 
@@ -1859,7 +1859,7 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
 
 	foreach(list_item, raw_parsetree_list)
 	{
-		RawStmt    *parsetree = (RawStmt *) lfirst(list_item);
+		RawStmt    *parsetree = castNode(RawStmt, lfirst(list_item));
 		CachedPlanSource *plansource;
 
 		plansource = CreateOneShotCachedPlan(parsetree,
@@ -2018,7 +2018,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
 
 		foreach(lc2, stmt_list)
 		{
-			PlannedStmt *stmt = (PlannedStmt *) lfirst(lc2);
+			PlannedStmt *stmt = castNode(PlannedStmt, lfirst(lc2));
 			bool		canSetTag = stmt->canSetTag;
 			DestReceiver *dest;
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a8e35fecccd..a4edea08a3e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -788,7 +788,7 @@ stmtmulti:	stmtmulti ';' stmt
 					if ($1 != NIL)
 					{
 						/* update length of previous stmt */
-						updateRawStmtEnd((RawStmt *) llast($1), @2);
+						updateRawStmtEnd(castNode(RawStmt, llast($1)), @2);
 					}
 					if ($3 != NULL)
 						$$ = lappend($1, makeRawStmt($3, @2 + 1));
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index c43ef19df5c..4b732724177 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -1502,8 +1502,7 @@ transformMultiAssignRef(ParseState *pstate, MultiAssignRef *maref)
 			sublink = (SubLink *) transformExprRecurse(pstate,
 													   (Node *) sublink);
 
-			qtree = (Query *) sublink->subselect;
-			Assert(IsA(qtree, Query));
+			qtree = castNode(Query, sublink->subselect);
 
 			/* Check subquery returns required number of columns */
 			if (count_nonjunk_tlist_entries(qtree->targetList) != maref->ncolumns)
@@ -1578,8 +1577,7 @@ transformMultiAssignRef(ParseState *pstate, MultiAssignRef *maref)
 
 		sublink = (SubLink *) tle->expr;
 		Assert(sublink->subLinkType == MULTIEXPR_SUBLINK);
-		qtree = (Query *) sublink->subselect;
-		Assert(IsA(qtree, Query));
+		qtree = castNode(Query, sublink->subselect);
 
 		/* Build a Param representing the current subquery output column */
 		tle = (TargetEntry *) list_nth(qtree->targetList, maref->colno - 1);
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 6660929dec7..8feec0b72b2 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -720,7 +720,7 @@ typeStringToTypeName(const char *str)
 	 */
 	if (list_length(raw_parsetree_list) != 1)
 		goto fail;
-	stmt = (SelectStmt *) ((RawStmt *) linitial(raw_parsetree_list))->stmt;
+	stmt = (SelectStmt *) castNode(RawStmt, linitial(raw_parsetree_list))->stmt;
 	if (stmt == NULL ||
 		!IsA(stmt, SelectStmt) ||
 		stmt->distinctClause != NIL ||
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 864d45ff128..481868bf53d 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -173,7 +173,7 @@ InsertRule(char *rulname,
 	if (event_qual != NULL)
 	{
 		/* Find query containing OLD/NEW rtable entries */
-		Query	   *qry = (Query *) linitial(action);
+		Query	   *qry = castNode(Query, linitial(action));
 
 		qry = getInsertSelectQuery(qry, NULL);
 		recordDependencyOnExpr(&myself, event_qual, qry->rtable,
@@ -286,7 +286,7 @@ DefineQueryRewrite(char *rulename,
 	 */
 	foreach(l, action)
 	{
-		query = (Query *) lfirst(l);
+		query = castNode(Query, lfirst(l));
 		if (query->resultRelation == 0)
 			continue;
 		/* Don't be fooled by INSERT/SELECT */
@@ -328,7 +328,7 @@ DefineQueryRewrite(char *rulename,
 		/*
 		 * ... the one action must be a SELECT, ...
 		 */
-		query = (Query *) linitial(action);
+		query = castNode(Query, linitial(action));
 		if (!is_instead ||
 			query->commandType != CMD_SELECT)
 			ereport(ERROR,
@@ -482,7 +482,7 @@ DefineQueryRewrite(char *rulename,
 
 		foreach(l, action)
 		{
-			query = (Query *) lfirst(l);
+			query = castNode(Query, lfirst(l));
 
 			if (!query->returningList)
 				continue;
@@ -813,7 +813,7 @@ setRuleCheckAsUser_Query(Query *qry, Oid userid)
 	{
 		CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
 
-		setRuleCheckAsUser_Query((Query *) cte->ctequery, userid);
+		setRuleCheckAsUser_Query(castNode(Query, cte->ctequery), userid);
 	}
 
 	/* If there are sublinks, search for them and process their RTEs */
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 62d49c8625f..b07d6c6cb9b 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -962,7 +962,7 @@ exec_simple_query(const char *query_string)
 	 */
 	foreach(parsetree_item, parsetree_list)
 	{
-		RawStmt    *parsetree = (RawStmt *) lfirst(parsetree_item);
+		RawStmt    *parsetree = castNode(RawStmt, lfirst(parsetree_item));
 		bool		snapshot_set = false;
 		const char *commandTag;
 		char		completionTag[COMPLETION_TAG_BUFSIZE];
@@ -1286,7 +1286,7 @@ exec_parse_message(const char *query_string,	/* string to execute */
 		bool		snapshot_set = false;
 		int			i;
 
-		raw_parse_tree = (RawStmt *) linitial(parsetree_list);
+		raw_parse_tree = castNode(RawStmt, linitial(parsetree_list));
 
 		/*
 		 * Get the command name for possible use in status display.
@@ -2148,7 +2148,7 @@ errdetail_execute(List *raw_parsetree_list)
 
 	foreach(parsetree_item, raw_parsetree_list)
 	{
-		RawStmt    *parsetree = (RawStmt *) lfirst(parsetree_item);
+		RawStmt    *parsetree = castNode(RawStmt, lfirst(parsetree_item));
 
 		if (IsA(parsetree->stmt, ExecuteStmt))
 		{
@@ -2502,9 +2502,8 @@ IsTransactionExitStmtList(List *pstmts)
 {
 	if (list_length(pstmts) == 1)
 	{
-		PlannedStmt *pstmt = (PlannedStmt *) linitial(pstmts);
+		PlannedStmt *pstmt = castNode(PlannedStmt, linitial(pstmts));
 
-		Assert(IsA(pstmt, PlannedStmt));
 		if (pstmt->commandType == CMD_UTILITY &&
 			IsTransactionExitStmt(pstmt->utilityStmt))
 			return true;
@@ -2518,9 +2517,8 @@ IsTransactionStmtList(List *pstmts)
 {
 	if (list_length(pstmts) == 1)
 	{
-		PlannedStmt *pstmt = (PlannedStmt *) linitial(pstmts);
+		PlannedStmt *pstmt = castNode(PlannedStmt, linitial(pstmts));
 
-		Assert(IsA(pstmt, PlannedStmt));
 		if (pstmt->commandType == CMD_UTILITY &&
 			IsA(pstmt->utilityStmt, TransactionStmt))
 			return true;
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 704be399cf7..e64ea2ed767 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -487,7 +487,7 @@ PortalStart(Portal portal, ParamListInfo params,
 				 * Create QueryDesc in portal's context; for the moment, set
 				 * the destination to DestNone.
 				 */
-				queryDesc = CreateQueryDesc((PlannedStmt *) linitial(portal->stmts),
+				queryDesc = CreateQueryDesc(castNode(PlannedStmt, linitial(portal->stmts)),
 											portal->sourceText,
 											GetActiveSnapshot(),
 											InvalidSnapshot,
@@ -1020,7 +1020,7 @@ FillPortalStore(Portal portal, bool isTopLevel)
 			break;
 
 		case PORTAL_UTIL_SELECT:
-			PortalRunUtility(portal, (PlannedStmt *) linitial(portal->stmts),
+			PortalRunUtility(portal, castNode(PlannedStmt, linitial(portal->stmts)),
 							 isTopLevel, true, treceiver, completionTag);
 			break;
 
@@ -1215,7 +1215,7 @@ PortalRunMulti(Portal portal,
 	 */
 	foreach(stmtlist_item, portal->stmts)
 	{
-		PlannedStmt *pstmt = (PlannedStmt *) lfirst(stmtlist_item);
+		PlannedStmt *pstmt = castNode(PlannedStmt, lfirst(stmtlist_item));
 
 		/*
 		 * If we got a cancel signal in prior command, quit
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 03062471774..801a9634dc1 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1829,22 +1829,19 @@ UtilityContainsQuery(Node *parsetree)
 	switch (nodeTag(parsetree))
 	{
 		case T_DeclareCursorStmt:
-			qry = (Query *) ((DeclareCursorStmt *) parsetree)->query;
-			Assert(IsA(qry, Query));
+			qry = castNode(Query, ((DeclareCursorStmt *) parsetree)->query);
 			if (qry->commandType == CMD_UTILITY)
 				return UtilityContainsQuery(qry->utilityStmt);
 			return qry;
 
 		case T_ExplainStmt:
-			qry = (Query *) ((ExplainStmt *) parsetree)->query;
-			Assert(IsA(qry, Query));
+			qry = castNode(Query, ((ExplainStmt *) parsetree)->query);
 			if (qry->commandType == CMD_UTILITY)
 				return UtilityContainsQuery(qry->utilityStmt);
 			return qry;
 
 		case T_CreateTableAsStmt:
-			qry = (Query *) ((CreateTableAsStmt *) parsetree)->query;
-			Assert(IsA(qry, Query));
+			qry = castNode(Query, ((CreateTableAsStmt *) parsetree)->query);
 			if (qry->commandType == CMD_UTILITY)
 				return UtilityContainsQuery(qry->utilityStmt);
 			return qry;
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index c31c603fbf5..dffc92762bc 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -975,7 +975,7 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
 	is_transient = false;
 	foreach(lc, plist)
 	{
-		PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc);
+		PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc));
 
 		if (plannedstmt->commandType == CMD_UTILITY)
 			continue;			/* Ignore utility statements */
@@ -1070,7 +1070,7 @@ cached_plan_cost(CachedPlan *plan, bool include_planner)
 
 	foreach(lc, plan->stmt_list)
 	{
-		PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc);
+		PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc));
 
 		if (plannedstmt->commandType == CMD_UTILITY)
 			continue;			/* Ignore utility statements */
@@ -1457,9 +1457,7 @@ QueryListGetPrimaryStmt(List *stmts)
 
 	foreach(lc, stmts)
 	{
-		Query	   *stmt = (Query *) lfirst(lc);
-
-		Assert(IsA(stmt, Query));
+		Query	   *stmt = castNode(Query, lfirst(lc));
 
 		if (stmt->canSetTag)
 			return stmt;
@@ -1478,12 +1476,10 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
 
 	foreach(lc1, stmt_list)
 	{
-		PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc1);
+		PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc1));
 		int			rt_index;
 		ListCell   *lc2;
 
-		Assert(IsA(plannedstmt, PlannedStmt));
-
 		if (plannedstmt->commandType == CMD_UTILITY)
 		{
 			/*
@@ -1549,9 +1545,7 @@ AcquirePlannerLocks(List *stmt_list, bool acquire)
 
 	foreach(lc, stmt_list)
 	{
-		Query	   *query = (Query *) lfirst(lc);
-
-		Assert(IsA(query, Query));
+		Query	   *query = castNode(Query, lfirst(lc));
 
 		if (query->commandType == CMD_UTILITY)
 		{
@@ -1618,9 +1612,9 @@ ScanQueryForLocks(Query *parsetree, bool acquire)
 	/* Recurse into subquery-in-WITH */
 	foreach(lc, parsetree->cteList)
 	{
-		CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
+		CommonTableExpr *cte = castNode(CommonTableExpr, lfirst(lc));
 
-		ScanQueryForLocks((Query *) cte->ctequery, acquire);
+		ScanQueryForLocks(castNode(Query, cte->ctequery), acquire);
 	}
 
 	/*
@@ -1648,7 +1642,7 @@ ScanQueryWalker(Node *node, bool *acquire)
 		SubLink    *sub = (SubLink *) node;
 
 		/* Do what we came for */
-		ScanQueryForLocks((Query *) sub->subselect, *acquire);
+		ScanQueryForLocks(castNode(Query, sub->subselect), *acquire);
 		/* Fall through to process lefthand args of SubLink */
 	}
 
@@ -1676,8 +1670,7 @@ PlanCacheComputeResultDesc(List *stmt_list)
 	{
 		case PORTAL_ONE_SELECT:
 		case PORTAL_ONE_MOD_WITH:
-			query = (Query *) linitial(stmt_list);
-			Assert(IsA(query, Query));
+			query = castNode(Query, linitial(stmt_list));
 			return ExecCleanTypeFromTL(query->targetList, false);
 
 		case PORTAL_ONE_RETURNING:
@@ -1686,8 +1679,7 @@ PlanCacheComputeResultDesc(List *stmt_list)
 			return ExecCleanTypeFromTL(query->returningList, false);
 
 		case PORTAL_UTIL_SELECT:
-			query = (Query *) linitial(stmt_list);
-			Assert(IsA(query, Query));
+			query = castNode(Query, linitial(stmt_list));
 			Assert(query->utilityStmt);
 			return UtilityTupleDescriptor(query->utilityStmt);
 
@@ -1744,7 +1736,7 @@ PlanCacheRelCallback(Datum arg, Oid relid)
 
 			foreach(lc, plansource->gplan->stmt_list)
 			{
-				PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc);
+				PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc));
 
 				if (plannedstmt->commandType == CMD_UTILITY)
 					continue;	/* Ignore utility statements */
@@ -1817,7 +1809,7 @@ PlanCacheFuncCallback(Datum arg, int cacheid, uint32 hashvalue)
 		{
 			foreach(lc, plansource->gplan->stmt_list)
 			{
-				PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc);
+				PlannedStmt *plannedstmt = castNode(PlannedStmt, lfirst(lc));
 				ListCell   *lc3;
 
 				if (plannedstmt->commandType == CMD_UTILITY)
@@ -1890,9 +1882,8 @@ ResetPlanCache(void)
 		 */
 		foreach(lc, plansource->query_list)
 		{
-			Query	   *query = (Query *) lfirst(lc);
+			Query	   *query = castNode(Query, lfirst(lc));
 
-			Assert(IsA(query, Query));
 			if (query->commandType != CMD_UTILITY ||
 				UtilityContainsQuery(query->utilityStmt))
 			{
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index e8ebc4684ca..3a3259bae27 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -153,9 +153,7 @@ PortalGetPrimaryStmt(Portal portal)
 
 	foreach(lc, portal->stmts)
 	{
-		PlannedStmt *stmt = (PlannedStmt *) lfirst(lc);
-
-		Assert(IsA(stmt, PlannedStmt));
+		PlannedStmt *stmt = castNode(PlannedStmt, lfirst(lc));
 
 		if (stmt->canSetTag)
 			return stmt;
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index b48146a362b..6fc3db07fe6 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3634,9 +3634,8 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
 
 			foreach(l2, plansource->query_list)
 			{
-				Query	   *q = (Query *) lfirst(l2);
+				Query	   *q = castNode(Query, lfirst(l2));
 
-				Assert(IsA(q, Query));
 				if (q->canSetTag)
 				{
 					if (q->commandType == CMD_INSERT ||
@@ -6825,8 +6824,7 @@ exec_simple_recheck_plan(PLpgSQL_expr *expr, CachedPlan *cplan)
 	 */
 	if (list_length(cplan->stmt_list) != 1)
 		return;
-	stmt = (PlannedStmt *) linitial(cplan->stmt_list);
-	Assert(IsA(stmt, PlannedStmt));
+	stmt = castNode(PlannedStmt, linitial(cplan->stmt_list));
 
 	/*
 	 * 2. It must be a RESULT plan --> no scan's required
-- 
GitLab