On Wed, 20 Jul 2022 at 14:21, tanghy.f...@fujitsu.com <tanghy.f...@fujitsu.com> 
wrote:
> On Wednesday, July 20, 2022 12:52 PM, Michael Paquier <mich...@paquier.xyz> 
> wrote:
>> What about the argument of upthread where we could use a goto in
>> functions where there are multiple pattern validation checks?  Per se
>> v4 attached.
>
> Thanks for your kindly remind and modification.
> I checked v4 patch, it looks good but I think there can be some minor 
> improvement.
> So I deleted some redundant braces around "goto error_return; ".
> Also added an error handle section in validateSQLNamePattern.
>
> Kindly to have a check at the attached v5 patch.
>
> Regards,
> Tang

Thanks for updating the patch.  It looks good.  However, it cannot be
applied on 14 stable.  The attached patches are for 10-14.

-- 
Regrads,
Japin Li.
ChengDu WenWu Information Technology Co.,Ltd.

>From 1dd828a40d5a45c0ee021f42f8eee354082a72cf Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Wed, 20 Jul 2022 12:47:52 +0900
Subject: [PATCH v5] fix the memory leak in psql describe


diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 88d92a08ae..77b0f87e39 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -112,7 +112,10 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "p.proname", NULL,
 								"pg_catalog.pg_function_is_visible(p.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
 
@@ -182,7 +185,10 @@ describeAccessMethods(const char *pattern, bool verbose)
 								NULL, "amname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -244,7 +250,10 @@ describeTablespaces(const char *pattern, bool verbose)
 								NULL, "spcname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -534,7 +543,7 @@ describeFunctions(const char *functypes, const char *func_pattern,
 								"n.nspname", "p.proname", NULL,
 								"pg_catalog.pg_function_is_visible(p.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	for (int i = 0; i < num_arg_patterns; i++)
 	{
@@ -561,7 +570,7 @@ describeFunctions(const char *functypes, const char *func_pattern,
 										true, false,
 										nspname, typname, ft, tiv,
 										NULL, 3))
-				return false;
+				goto error_return;
 		}
 		else
 		{
@@ -599,6 +608,10 @@ describeFunctions(const char *functypes, const char *func_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -682,7 +695,10 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
 								"pg_catalog.format_type(t.oid, NULL)",
 								"pg_catalog.pg_type_is_visible(t.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -836,7 +852,7 @@ describeOperators(const char *oper_pattern,
 								"n.nspname", "o.oprname", NULL,
 								"pg_catalog.pg_operator_is_visible(o.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	if (num_arg_patterns == 1)
 		appendPQExpBufferStr(&buf, "  AND o.oprleft = 0\n");
@@ -866,7 +882,7 @@ describeOperators(const char *oper_pattern,
 										true, false,
 										nspname, typname, ft, tiv,
 										NULL, 3))
-				return false;
+				goto error_return;
 		}
 		else
 		{
@@ -890,6 +906,10 @@ describeOperators(const char *oper_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -953,7 +973,10 @@ listAllDbs(const char *pattern, bool verbose)
 		if (!validateSQLNamePattern(&buf, pattern, false, false,
 									NULL, "d.datname", NULL, NULL,
 									NULL, 1))
+		{
+			termPQExpBuffer(&buf);
 			return false;
+		}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 	res = PSQLexec(buf.data);
@@ -1106,7 +1129,10 @@ permissionsList(const char *pattern)
 								"n.nspname", "c.relname", NULL,
 								"n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -1177,16 +1203,13 @@ listDefaultACLs(const char *pattern)
 								"pg_catalog.pg_get_userbyid(d.defaclrole)",
 								NULL,
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
 
 	res = PSQLexec(buf.data);
 	if (!res)
-	{
-		termPQExpBuffer(&buf);
-		return false;
-	}
+		goto error_return;
 
 	myopt.nullPrint = NULL;
 	printfPQExpBuffer(&buf, _("Default access privileges"));
@@ -1200,6 +1223,10 @@ listDefaultACLs(const char *pattern)
 	termPQExpBuffer(&buf);
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -1253,7 +1280,7 @@ objectDescription(const char *pattern, bool showSystem)
 								false, "n.nspname", "pgc.conname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	/* Domain constraint descriptions */
 	appendPQExpBuffer(&buf,
@@ -1277,7 +1304,7 @@ objectDescription(const char *pattern, bool showSystem)
 								false, "n.nspname", "pgc.conname", NULL,
 								"pg_catalog.pg_type_is_visible(t.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	/* Operator class descriptions */
 	appendPQExpBuffer(&buf,
@@ -1301,7 +1328,7 @@ objectDescription(const char *pattern, bool showSystem)
 								"n.nspname", "o.opcname", NULL,
 								"pg_catalog.pg_opclass_is_visible(o.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	/* Operator family descriptions */
 	appendPQExpBuffer(&buf,
@@ -1325,7 +1352,7 @@ objectDescription(const char *pattern, bool showSystem)
 								"n.nspname", "opf.opfname", NULL,
 								"pg_catalog.pg_opfamily_is_visible(opf.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	/* Rule descriptions (ignore rules for views) */
 	appendPQExpBuffer(&buf,
@@ -1348,7 +1375,7 @@ objectDescription(const char *pattern, bool showSystem)
 								"n.nspname", "r.rulename", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	/* Trigger descriptions */
 	appendPQExpBuffer(&buf,
@@ -1370,7 +1397,7 @@ objectDescription(const char *pattern, bool showSystem)
 								"n.nspname", "t.tgname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	appendPQExpBufferStr(&buf,
 						 ") AS tt\n"
@@ -1393,6 +1420,10 @@ objectDescription(const char *pattern, bool showSystem)
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -1428,7 +1459,10 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
 
@@ -3614,7 +3648,10 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "r.rolname", NULL, NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -3739,11 +3776,11 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
 					  gettext_noop("Settings"));
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "r.rolname", NULL, NULL, &havewhere, 1))
-		return false;
+		goto error_return;
 	if (!validateSQLNamePattern(&buf, pattern2, havewhere, false,
 								NULL, "d.datname", NULL, NULL,
 								NULL, 1))
-		return false;
+		goto error_return;
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
 	res = PSQLexec(buf.data);
@@ -3779,6 +3816,10 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -3940,7 +3981,10 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
 
@@ -4157,7 +4201,10 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose)
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBuffer(&buf, "ORDER BY \"Schema\", %s%s\"Name\";",
 					  mixed_output ? "\"Type\" DESC, " : "",
@@ -4233,7 +4280,10 @@ listLanguages(const char *pattern, bool verbose, bool showSystem)
 		if (!validateSQLNamePattern(&buf, pattern, false, false,
 									NULL, "l.lanname", NULL, NULL,
 									NULL, 2))
+		{
+			termPQExpBuffer(&buf);
 			return false;
+		}
 
 	if (!showSystem && !pattern)
 		appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
@@ -4319,7 +4369,10 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "t.typname", NULL,
 								"pg_catalog.pg_type_is_visible(t.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -4395,7 +4448,10 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "c.conname", NULL,
 								"pg_catalog.pg_conversion_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -4542,7 +4598,10 @@ listEventTriggers(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "evtname", NULL, NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1");
 
@@ -4638,7 +4697,10 @@ listExtendedStats(const char *pattern)
 								"es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname",
 								NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -4742,7 +4804,7 @@ listCasts(const char *pattern, bool verbose)
 								"pg_catalog.format_type(ts.oid, NULL)",
 								"pg_catalog.pg_type_is_visible(ts.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	appendPQExpBufferStr(&buf, ") OR (true");
 
@@ -4751,7 +4813,7 @@ listCasts(const char *pattern, bool verbose)
 								"pg_catalog.format_type(tt.oid, NULL)",
 								"pg_catalog.pg_type_is_visible(tt.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
 
@@ -4770,6 +4832,10 @@ listCasts(const char *pattern, bool verbose)
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -4851,7 +4917,10 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "c.collname", NULL,
 								"pg_catalog.pg_collation_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -4914,7 +4983,10 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
 								NULL, "n.nspname", NULL,
 								NULL,
 								NULL, 2))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -5029,7 +5101,10 @@ listTSParsers(const char *pattern, bool verbose)
 								"n.nspname", "p.prsname", NULL,
 								"pg_catalog.pg_ts_parser_is_visible(p.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5072,7 +5147,10 @@ listTSParsersVerbose(const char *pattern)
 								"n.nspname", "p.prsname", NULL,
 								"pg_catalog.pg_ts_parser_is_visible(p.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5215,7 +5293,10 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 	res = PSQLexec(buf.data);
 	termPQExpBuffer(&buf);
 	if (!res)
+	{
+		termPQExpBuffer(&title);
 		return false;
+	}
 
 	myopt.nullPrint = NULL;
 	if (nspname)
@@ -5281,7 +5362,10 @@ listTSDictionaries(const char *pattern, bool verbose)
 								"n.nspname", "d.dictname", NULL,
 								"pg_catalog.pg_ts_dict_is_visible(d.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5344,7 +5428,10 @@ listTSTemplates(const char *pattern, bool verbose)
 								"n.nspname", "t.tmplname", NULL,
 								"pg_catalog.pg_ts_template_is_visible(t.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5396,7 +5483,10 @@ listTSConfigs(const char *pattern, bool verbose)
 								"n.nspname", "c.cfgname", NULL,
 								"pg_catalog.pg_ts_config_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5440,7 +5530,10 @@ listTSConfigsVerbose(const char *pattern)
 								"n.nspname", "c.cfgname", NULL,
 								"pg_catalog.pg_ts_config_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
 
@@ -5613,7 +5706,10 @@ listForeignDataWrappers(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "fdwname", NULL, NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -5687,7 +5783,10 @@ listForeignServers(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "s.srvname", NULL, NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -5740,7 +5839,10 @@ listUserMappings(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "um.srvname", "um.usename", NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5810,7 +5912,10 @@ listForeignTables(const char *pattern, bool verbose)
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5859,7 +5964,10 @@ listExtensions(const char *pattern)
 								NULL, "e.extname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -5900,7 +6008,10 @@ listExtensionContents(const char *pattern)
 								NULL, "e.extname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -6014,8 +6125,7 @@ validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where,
 	{
 		pg_log_error("improper qualified name (too many dotted names): %s",
 					 pattern);
-		termPQExpBuffer(&dbbuf);
-		return false;
+		goto error_return;
 	}
 
 	if (maxparts > 1 && dotcnt == maxparts - 1)
@@ -6023,16 +6133,21 @@ validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where,
 		if (PQdb(pset.db) == NULL)
 		{
 			pg_log_error("You are currently not connected to a database.");
-			return false;
+			goto error_return;
 		}
 		if (strcmp(PQdb(pset.db), dbbuf.data) != 0)
 		{
 			pg_log_error("cross-database references are not implemented: %s",
 						 pattern);
-			return false;
+			goto error_return;
 		}
 	}
+	termPQExpBuffer(&dbbuf);
 	return true;
+
+error_return:
+	termPQExpBuffer(&dbbuf);
+	return false;
 }
 
 /*
@@ -6090,7 +6205,10 @@ listPublications(const char *pattern)
 								NULL, "pubname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -6205,7 +6323,10 @@ describePublications(const char *pattern)
 								NULL, "pubname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 2;");
 
@@ -6417,7 +6538,10 @@ describeSubscriptions(const char *pattern, bool verbose)
 								NULL, "subname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -6521,7 +6645,7 @@ listOperatorClasses(const char *access_method_pattern,
 		if (!validateSQLNamePattern(&buf, access_method_pattern,
 									false, false, NULL, "am.amname", NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 	if (type_pattern)
 	{
 		/* Match type name pattern against either internal or external name */
@@ -6530,7 +6654,7 @@ listOperatorClasses(const char *access_method_pattern,
 									"pg_catalog.format_type(t.oid, NULL)",
 									"pg_catalog.pg_type_is_visible(t.oid)",
 									NULL, 3))
-			return false;
+			goto error_return;
 	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
@@ -6549,6 +6673,10 @@ listOperatorClasses(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -6597,7 +6725,7 @@ listOperatorFamilies(const char *access_method_pattern,
 		if (!validateSQLNamePattern(&buf, access_method_pattern,
 									false, false, NULL, "am.amname", NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 	if (type_pattern)
 	{
 		appendPQExpBuffer(&buf,
@@ -6614,7 +6742,7 @@ listOperatorFamilies(const char *access_method_pattern,
 									"pg_catalog.format_type(t.oid, NULL)",
 									"pg_catalog.pg_type_is_visible(t.oid)",
 									NULL, 3))
-			return false;
+			goto error_return;
 		appendPQExpBufferStr(&buf, "  )\n");
 	}
 
@@ -6634,6 +6762,10 @@ listOperatorFamilies(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -6696,13 +6828,13 @@ listOpFamilyOperators(const char *access_method_pattern,
 									false, false, NULL, "am.amname",
 									NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 
 	if (family_pattern)
 		if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
 									"nsf.nspname", "of.opfname", NULL, NULL,
 									NULL, 3))
-			return false;
+			goto error_return;
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
 						 "  o.amoplefttype = o.amoprighttype DESC,\n"
@@ -6725,6 +6857,10 @@ listOpFamilyOperators(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -6784,12 +6920,12 @@ listOpFamilyFunctions(const char *access_method_pattern,
 									false, false, NULL, "am.amname",
 									NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 	if (family_pattern)
 		if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
 									"ns.nspname", "of.opfname", NULL, NULL,
 									NULL, 3))
-			return false;
+			goto error_return;
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
 						 "  ap.amproclefttype = ap.amprocrighttype DESC,\n"
@@ -6810,6 +6946,10 @@ listOpFamilyFunctions(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
-- 
2.33.0.windows.2

>From fee69e1f3b56d4639aed789ee38850d68fb052a6 Mon Sep 17 00:00:00 2001
From: Japin Li <japi...@hotmail.com>
Date: Wed, 20 Jul 2022 15:52:45 +0800
Subject: [PATCH v5 1/1] fix the memory leak in psql describe

---
 src/bin/psql/describe.c | 201 ++++++++++++++++++++++++++++++++++------
 1 file changed, 172 insertions(+), 29 deletions(-)

diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 8fe39475fa..c6ff5a9d14 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -131,7 +131,10 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem)
 							  "n.nspname", "p.proname", NULL,
 							  "pg_catalog.pg_function_is_visible(p.oid)",
 							  NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
 
@@ -201,7 +204,10 @@ describeAccessMethods(const char *pattern, bool verbose)
 								NULL, "amname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -290,7 +296,10 @@ describeTablespaces(const char *pattern, bool verbose)
 								NULL, "spcname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -656,7 +665,7 @@ describeFunctions(const char *functypes, const char *func_pattern,
 								"n.nspname", "p.proname", NULL,
 								"pg_catalog.pg_function_is_visible(p.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	for (int i = 0; i < num_arg_patterns; i++)
 	{
@@ -683,7 +692,7 @@ describeFunctions(const char *functypes, const char *func_pattern,
 										true, false,
 										nspname, typname, ft, tiv,
 										NULL, 3))
-				return false;
+				goto error_return;
 		}
 		else
 		{
@@ -721,6 +730,10 @@ describeFunctions(const char *functypes, const char *func_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -827,7 +840,10 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
 								"pg_catalog.format_type(t.oid, NULL)",
 								"pg_catalog.pg_type_is_visible(t.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -982,7 +998,7 @@ describeOperators(const char *oper_pattern,
 								"n.nspname", "o.oprname", NULL,
 								"pg_catalog.pg_operator_is_visible(o.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	if (num_arg_patterns == 1)
 		appendPQExpBufferStr(&buf, "  AND o.oprleft = 0\n");
@@ -1012,7 +1028,7 @@ describeOperators(const char *oper_pattern,
 										true, false,
 										nspname, typname, ft, tiv,
 										NULL, 3))
-				return false;
+				goto error_return;
 		}
 		else
 		{
@@ -1036,6 +1052,10 @@ describeOperators(const char *oper_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -1093,7 +1113,10 @@ listAllDbs(const char *pattern, bool verbose)
 		if (!validateSQLNamePattern(&buf, pattern, false, false,
 									NULL, "d.datname", NULL, NULL,
 									NULL, 1))
+		{
+			termPQExpBuffer(&buf);
 			return false;
+		}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 	res = PSQLexec(buf.data);
@@ -1247,7 +1270,10 @@ permissionsList(const char *pattern)
 								"n.nspname", "c.relname", NULL,
 								"n.nspname !~ '^pg_' AND pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -1328,7 +1354,10 @@ listDefaultACLs(const char *pattern)
 								"pg_catalog.pg_get_userbyid(d.defaclrole)",
 								NULL,
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3;");
 
@@ -1404,7 +1433,7 @@ objectDescription(const char *pattern, bool showSystem)
 								false, "n.nspname", "pgc.conname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	/* Domain constraint descriptions */
 	appendPQExpBuffer(&buf,
@@ -1428,7 +1457,7 @@ objectDescription(const char *pattern, bool showSystem)
 								false, "n.nspname", "pgc.conname", NULL,
 								"pg_catalog.pg_type_is_visible(t.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 
 	/*
@@ -1458,7 +1487,7 @@ objectDescription(const char *pattern, bool showSystem)
 									"n.nspname", "o.opcname", NULL,
 									"pg_catalog.pg_opclass_is_visible(o.oid)",
 									NULL, 3))
-			return false;
+			goto error_return;
 	}
 
 	/*
@@ -1489,7 +1518,7 @@ objectDescription(const char *pattern, bool showSystem)
 									"n.nspname", "opf.opfname", NULL,
 									"pg_catalog.pg_opfamily_is_visible(opf.oid)",
 									NULL, 3))
-			return false;
+			goto error_return;
 	}
 
 	/* Rule descriptions (ignore rules for views) */
@@ -1513,7 +1542,7 @@ objectDescription(const char *pattern, bool showSystem)
 								"n.nspname", "r.rulename", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	/* Trigger descriptions */
 	appendPQExpBuffer(&buf,
@@ -1535,7 +1564,7 @@ objectDescription(const char *pattern, bool showSystem)
 								"n.nspname", "t.tgname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	appendPQExpBufferStr(&buf,
 						 ") AS tt\n"
@@ -1558,6 +1587,10 @@ objectDescription(const char *pattern, bool showSystem)
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -1593,7 +1626,10 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
 
@@ -3852,7 +3888,7 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
 		if (!validateSQLNamePattern(&buf, pattern, false, false,
 									NULL, "r.rolname", NULL, NULL,
 									NULL, 1))
-			return false;
+			goto error_return;
 	}
 	else
 	{
@@ -3869,14 +3905,14 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
 		if (!validateSQLNamePattern(&buf, pattern, false, false,
 									NULL, "u.usename", NULL, NULL,
 									NULL, 1))
-			return false;
+			goto error_return;
 	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
 	res = PSQLexec(buf.data);
 	if (!res)
-		return false;
+		goto error_return;
 
 	nrows = PQntuples(res);
 	attr = pg_malloc0((nrows + 1) * sizeof(*attr));
@@ -3962,6 +3998,10 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 static void
@@ -4006,11 +4046,11 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
 					  gettext_noop("Settings"));
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "r.rolname", NULL, NULL, &havewhere, 1))
-		return false;
+		goto error_return;
 	if (!validateSQLNamePattern(&buf, pattern2, havewhere, false,
 								NULL, "d.datname", NULL, NULL,
 								NULL, 1))
-		return false;
+		goto error_return;
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
 	res = PSQLexec(buf.data);
@@ -4046,6 +4086,10 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 
@@ -4229,7 +4273,10 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
 
@@ -4446,7 +4493,10 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose)
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBuffer(&buf, "ORDER BY \"Schema\", %s%s\"Name\";",
 					  mixed_output ? "\"Type\" DESC, " : "",
@@ -4527,7 +4577,10 @@ listLanguages(const char *pattern, bool verbose, bool showSystem)
 		if (!validateSQLNamePattern(&buf, pattern, false, false,
 									NULL, "l.lanname", NULL, NULL,
 									NULL, 2))
+		{
+			termPQExpBuffer(&buf);
 			return false;
+		}
 
 	if (!showSystem && !pattern)
 		appendPQExpBufferStr(&buf, "WHERE l.lanplcallfoid != 0\n");
@@ -4620,7 +4673,10 @@ listDomains(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "t.typname", NULL,
 								"pg_catalog.pg_type_is_visible(t.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -4696,7 +4752,10 @@ listConversions(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "c.conname", NULL,
 								"pg_catalog.pg_conversion_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -4764,7 +4823,10 @@ listEventTriggers(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "evtname", NULL, NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1");
 
@@ -4860,7 +4922,10 @@ listExtendedStats(const char *pattern)
 								"es.stxnamespace::pg_catalog.regnamespace::pg_catalog.text", "es.stxname",
 								NULL, "pg_catalog.pg_statistics_obj_is_visible(es.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -4971,7 +5036,7 @@ listCasts(const char *pattern, bool verbose)
 								"pg_catalog.format_type(ts.oid, NULL)",
 								"pg_catalog.pg_type_is_visible(ts.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	appendPQExpBufferStr(&buf, ") OR (true");
 
@@ -4980,7 +5045,7 @@ listCasts(const char *pattern, bool verbose)
 								"pg_catalog.format_type(tt.oid, NULL)",
 								"pg_catalog.pg_type_is_visible(tt.oid)",
 								NULL, 3))
-		return false;
+		goto error_return;
 
 	appendPQExpBufferStr(&buf, ") )\nORDER BY 1, 2;");
 
@@ -4999,6 +5064,10 @@ listCasts(const char *pattern, bool verbose)
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -5081,7 +5150,10 @@ listCollations(const char *pattern, bool verbose, bool showSystem)
 								"n.nspname", "c.collname", NULL,
 								"pg_catalog.pg_collation_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5142,7 +5214,10 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
 								NULL, "n.nspname", NULL,
 								NULL,
 								NULL, 2))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -5204,7 +5279,10 @@ listTSParsers(const char *pattern, bool verbose)
 								"n.nspname", "p.prsname", NULL,
 								"pg_catalog.pg_ts_parser_is_visible(p.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5247,7 +5325,10 @@ listTSParsersVerbose(const char *pattern)
 								"n.nspname", "p.prsname", NULL,
 								"pg_catalog.pg_ts_parser_is_visible(p.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5390,7 +5471,10 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 	res = PSQLexec(buf.data);
 	termPQExpBuffer(&buf);
 	if (!res)
+	{
+		termPQExpBuffer(&title);
 		return false;
+	}
 
 	myopt.nullPrint = NULL;
 	if (nspname)
@@ -5466,7 +5550,10 @@ listTSDictionaries(const char *pattern, bool verbose)
 								"n.nspname", "d.dictname", NULL,
 								"pg_catalog.pg_ts_dict_is_visible(d.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5539,7 +5626,10 @@ listTSTemplates(const char *pattern, bool verbose)
 								"n.nspname", "t.tmplname", NULL,
 								"pg_catalog.pg_ts_template_is_visible(t.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5601,7 +5691,10 @@ listTSConfigs(const char *pattern, bool verbose)
 								"n.nspname", "c.cfgname", NULL,
 								"pg_catalog.pg_ts_config_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -5645,7 +5738,10 @@ listTSConfigsVerbose(const char *pattern)
 								"n.nspname", "c.cfgname", NULL,
 								"pg_catalog.pg_ts_config_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 3, 2;");
 
@@ -5834,7 +5930,10 @@ listForeignDataWrappers(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "fdwname", NULL, NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -5918,7 +6017,10 @@ listForeignServers(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "s.srvname", NULL, NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -5981,7 +6083,10 @@ listUserMappings(const char *pattern, bool verbose)
 	if (!validateSQLNamePattern(&buf, pattern, false, false,
 								NULL, "um.srvname", "um.usename", NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -6061,7 +6166,10 @@ listForeignTables(const char *pattern, bool verbose)
 								"n.nspname", "c.relname", NULL,
 								"pg_catalog.pg_table_is_visible(c.oid)",
 								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
 
@@ -6120,7 +6228,10 @@ listExtensions(const char *pattern)
 								NULL, "e.extname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -6171,7 +6282,10 @@ listExtensionContents(const char *pattern)
 								NULL, "e.extname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -6285,8 +6399,7 @@ validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where,
 	{
 		pg_log_error("improper qualified name (too many dotted names): %s",
 					 pattern);
-		termPQExpBuffer(&dbbuf);
-		return false;
+		goto error_return;
 	}
 
 	if (maxparts > 1 && dotcnt == maxparts-1)
@@ -6294,16 +6407,21 @@ validateSQLNamePattern(PQExpBuffer buf, const char *pattern, bool have_where,
 		if (PQdb(pset.db) == NULL)
 		{
 			pg_log_error("You are currently not connected to a database.");
-			return false;
+			goto error_return;
 		}
 		if (strcmp(PQdb(pset.db), dbbuf.data) != 0)
 		{
 			pg_log_error("cross-database references are not implemented: %s",
 						 pattern);
-			return false;
+			goto error_return;
 		}
 	}
+	termPQExpBuffer(&dbbuf);
 	return true;
+
+error_return:
+	termPQExpBuffer(&dbbuf);
+	return false;
 }
 
 /*
@@ -6361,7 +6479,10 @@ listPublications(const char *pattern)
 								NULL, "pubname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -6430,7 +6551,10 @@ describePublications(const char *pattern)
 								NULL, "pubname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 2;");
 
@@ -6616,7 +6740,10 @@ describeSubscriptions(const char *pattern, bool verbose)
 								NULL, "subname", NULL,
 								NULL,
 								NULL, 1))
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1;");
 
@@ -6725,7 +6852,7 @@ listOperatorClasses(const char *access_method_pattern,
 		if (!validateSQLNamePattern(&buf, access_method_pattern,
 									false, false, NULL, "am.amname", NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 	if (type_pattern)
 	{
 		/* Match type name pattern against either internal or external name */
@@ -6734,7 +6861,7 @@ listOperatorClasses(const char *access_method_pattern,
 									"pg_catalog.format_type(t.oid, NULL)",
 									"pg_catalog.pg_type_is_visible(t.oid)",
 									NULL, 3))
-			return false;
+			goto error_return;
 	}
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;");
@@ -6753,6 +6880,10 @@ listOperatorClasses(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+ error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -6801,7 +6932,7 @@ listOperatorFamilies(const char *access_method_pattern,
 		if (!validateSQLNamePattern(&buf, access_method_pattern,
 									false, false, NULL, "am.amname", NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 	if (type_pattern)
 	{
 		appendPQExpBuffer(&buf,
@@ -6818,7 +6949,7 @@ listOperatorFamilies(const char *access_method_pattern,
 									"pg_catalog.format_type(t.oid, NULL)",
 									"pg_catalog.pg_type_is_visible(t.oid)",
 									NULL, 3))
-			return false;
+			goto error_return;
 		appendPQExpBufferStr(&buf, "  )\n");
 	}
 
@@ -6838,6 +6969,10 @@ listOperatorFamilies(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -6900,13 +7035,13 @@ listOpFamilyOperators(const char *access_method_pattern,
 									false, false, NULL, "am.amname",
 									NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 
 	if (family_pattern)
 		if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
 									"nsf.nspname", "of.opfname", NULL, NULL,
 									NULL, 3))
-			return false;
+			goto error_return;
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
 						 "  o.amoplefttype = o.amoprighttype DESC,\n"
@@ -6929,6 +7064,10 @@ listOpFamilyOperators(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
 
 /*
@@ -6988,12 +7127,12 @@ listOpFamilyFunctions(const char *access_method_pattern,
 									false, false, NULL, "am.amname",
 									NULL, NULL,
 									&have_where, 1))
-			return false;
+			goto error_return;
 	if (family_pattern)
 		if (!validateSQLNamePattern(&buf, family_pattern, have_where, false,
 									"ns.nspname", "of.opfname", NULL, NULL,
 									NULL, 3))
-			return false;
+			goto error_return;
 
 	appendPQExpBufferStr(&buf, "ORDER BY 1, 2,\n"
 						 "  ap.amproclefttype = ap.amprocrighttype DESC,\n"
@@ -7014,4 +7153,8 @@ listOpFamilyFunctions(const char *access_method_pattern,
 
 	PQclear(res);
 	return true;
+
+error_return:
+	termPQExpBuffer(&buf);
+	return false;
 }
-- 
2.17.1

>From 11b11f08f56ba77707e2a160cc36648b6f14effb Mon Sep 17 00:00:00 2001
From: Japin Li <japi...@hotmail.com>
Date: Wed, 20 Jul 2022 14:12:53 +0800
Subject: [PATCH v5 1/1] fix the memory leak in psql describe

---
 src/bin/psql/describe.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index c7ff55fbd7..32a18becba 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3441,7 +3441,10 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
 
 	res = PSQLexec(buf.data);
 	if (!res)
+	{
+		termPQExpBuffer(&buf);
 		return false;
+	}
 
 	nrows = PQntuples(res);
 	attr = pg_malloc0((nrows + 1) * sizeof(*attr));
@@ -4800,7 +4803,10 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
 	res = PSQLexec(buf.data);
 	termPQExpBuffer(&buf);
 	if (!res)
+	{
+		termPQExpBuffer(&title);
 		return false;
+	}
 
 	myopt.nullPrint = NULL;
 	if (nspname)
-- 
2.17.1

Reply via email to