*** a/doc/src/sgml/ref/deallocate.sgml --- b/doc/src/sgml/ref/deallocate.sgml *************** *** 26,32 **** PostgreSQL documentation ! DEALLOCATE [ PREPARE ] { name | ALL } --- 26,33 ---- ! DEALLOCATE [ PREPARE ] [ IF EXISTS ] name ! DEALLOCATE [ PREPARE ] ALL *************** *** 59,64 **** DEALLOCATE [ PREPARE ] { name | ALL --- 60,75 ---- + IF EXISTS + + + Do not throw an error if the prepared statement does not exist. + A notice is issued in this case. + + + + + name *** a/src/backend/commands/prepare.c --- b/src/backend/commands/prepare.c *************** *** 556,562 **** void DeallocateQuery(DeallocateStmt *stmt) { if (stmt->name) ! DropPreparedStatement(stmt->name, true); else DropAllPreparedStatements(); } --- 556,562 ---- DeallocateQuery(DeallocateStmt *stmt) { if (stmt->name) ! DropPreparedStatement(stmt->name, !stmt->missing_ok); else DropAllPreparedStatements(); } *************** *** 582,587 **** DropPreparedStatement(const char *stmt_name, bool showError) --- 582,591 ---- /* Now we can remove the hash table entry */ hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL); } + else + ereport(NOTICE, + (errmsg("prepared statement \"%s\" does not exist, skipping", + stmt_name))); } /* *** a/src/backend/nodes/copyfuncs.c --- b/src/backend/nodes/copyfuncs.c *************** *** 3675,3680 **** _copyDeallocateStmt(const DeallocateStmt *from) --- 3675,3681 ---- DeallocateStmt *newnode = makeNode(DeallocateStmt); COPY_STRING_FIELD(name); + COPY_SCALAR_FIELD(missing_ok); return newnode; } *** a/src/backend/nodes/equalfuncs.c --- b/src/backend/nodes/equalfuncs.c *************** *** 1961,1966 **** static bool --- 1961,1967 ---- _equalDeallocateStmt(const DeallocateStmt *a, const DeallocateStmt *b) { COMPARE_STRING_FIELD(name); + COMPARE_SCALAR_FIELD(missing_ok); return true; } *** a/src/backend/parser/gram.y --- b/src/backend/parser/gram.y *************** *** 8571,8582 **** DeallocateStmt: DEALLOCATE name --- 8571,8598 ---- { DeallocateStmt *n = makeNode(DeallocateStmt); n->name = $2; + n->missing_ok = FALSE; $$ = (Node *) n; } | DEALLOCATE PREPARE name { DeallocateStmt *n = makeNode(DeallocateStmt); n->name = $3; + n->missing_ok = FALSE; + $$ = (Node *) n; + } + | DEALLOCATE IF_P EXISTS name + { + DeallocateStmt *n = makeNode(DeallocateStmt); + n->name = $4; + n->missing_ok = TRUE; + $$ = (Node *) n; + } + | DEALLOCATE PREPARE IF_P EXISTS name + { + DeallocateStmt *n = makeNode(DeallocateStmt); + n->name = $5; + n->missing_ok = TRUE; $$ = (Node *) n; } | DEALLOCATE ALL *** a/src/include/nodes/parsenodes.h --- b/src/include/nodes/parsenodes.h *************** *** 2575,2580 **** typedef struct DeallocateStmt --- 2575,2581 ---- NodeTag type; char *name; /* The name of the plan to remove */ /* NULL means DEALLOCATE ALL */ + bool missing_ok; /* skip error if table missing */ } DeallocateStmt; /* *** a/src/test/regress/expected/prepare.out --- b/src/test/regress/expected/prepare.out *************** *** 178,180 **** SELECT name, statement, parameter_types FROM pg_prepared_statements --- 178,183 ---- ------+-----------+----------------- (0 rows) + -- test DEALLOCATE IF EXISTS; + DEALLOCATE IF EXISTS unprepared_statement; + NOTICE: prepared statement "unprepared_statement" does not exist, skipping *** a/src/test/regress/sql/prepare.sql --- b/src/test/regress/sql/prepare.sql *************** *** 75,77 **** SELECT name, statement, parameter_types FROM pg_prepared_statements --- 75,80 ---- DEALLOCATE ALL; SELECT name, statement, parameter_types FROM pg_prepared_statements ORDER BY name; + + -- test DEALLOCATE IF EXISTS; + DEALLOCATE IF EXISTS unprepared_statement;