From 6ab1e806ab0708a0b139a985be81dd090cbf992f Mon Sep 17 00:00:00 2001 From: erthalion <9erthalion6@gmail.com> Date: Wed, 17 Apr 2019 17:48:43 +0200 Subject: [PATCH 1/2] Optional tableam Make insert/update/delete table am optional --- src/backend/access/table/tableamapi.c | 12 ------------ src/backend/commands/copy.c | 8 ++++++++ src/backend/parser/analyze.c | 29 +++++++++++++++++++++++++++++ src/backend/tcop/utility.c | 1 + src/include/access/tableam.h | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c index bfd713f3af..0a58123a0a 100644 --- a/src/backend/access/table/tableamapi.c +++ b/src/backend/access/table/tableamapi.c @@ -63,18 +63,6 @@ GetTableAmRoutine(Oid amhandler) Assert(routine->tuple_fetch_row_version != NULL); Assert(routine->tuple_satisfies_snapshot != NULL); - Assert(routine->tuple_insert != NULL); - - /* - * Could be made optional, but would require throwing error during - * parse-analysis. - */ - Assert(routine->tuple_insert_speculative != NULL); - Assert(routine->tuple_complete_speculative != NULL); - - Assert(routine->multi_insert != NULL); - Assert(routine->tuple_delete != NULL); - Assert(routine->tuple_update != NULL); Assert(routine->tuple_lock != NULL); Assert(routine->relation_set_new_filenode != NULL); diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index c39218f8db..36e2dbf1b8 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -41,6 +41,7 @@ #include "miscadmin.h" #include "optimizer/optimizer.h" #include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" #include "parser/parse_coerce.h" #include "parser/parse_collate.h" #include "parser/parse_expr.h" @@ -901,6 +902,13 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, NULL, false, false); rte->requiredPerms = (is_from ? ACL_INSERT : ACL_SELECT); + if (is_from && !table_support_multi_insert(rel)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Table access method doesn't support the operation"), + parser_errposition(pstate, + exprLocation((Node *) stmt)))); + if (stmt->whereClause) { /* add rte to column namespace */ diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 400558b552..b320ff1b26 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -25,6 +25,7 @@ #include "postgres.h" #include "access/sysattr.h" +#include "access/tableam.h" #include "catalog/pg_type.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -416,6 +417,13 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) true, ACL_DELETE); + if (!table_support_delete(pstate->p_target_relation)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Table access method doesn't support the operation"), + parser_errposition(pstate, + exprLocation((Node *) stmt)))); + /* grab the namespace item made by setTargetTable */ nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace); @@ -553,6 +561,20 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) qry->resultRelation = setTargetTable(pstate, stmt->relation, false, false, targetPerms); + if (!table_support_insert(pstate->p_target_relation)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Table access method doesn't support the operation"), + parser_errposition(pstate, + exprLocation((Node *) stmt)))); + + if (!table_support_speculative(pstate->p_target_relation) && isOnConflictUpdate) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Table access method doesn't support the operation"), + parser_errposition(pstate, + exprLocation((Node *) stmt)))); + /* Validate stmt->cols list, or build default list if no list given */ icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos); Assert(list_length(icolumns) == list_length(attrnos)); @@ -2237,6 +2259,13 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) true, ACL_UPDATE); + if (!table_support_update(pstate->p_target_relation)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Table access method doesn't support the operation"), + parser_errposition(pstate, + exprLocation((Node *) stmt)))); + /* grab the namespace item made by setTargetTable */ nsitem = (ParseNamespaceItem *) llast(pstate->p_namespace); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index edf24c438c..b90f047e6e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -18,6 +18,7 @@ #include "access/htup_details.h" #include "access/reloptions.h" +#include "access/tableam.h" #include "access/twophase.h" #include "access/xact.h" #include "access/xlog.h" diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index 6fbfcb96c9..d11cade4a0 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -1050,6 +1050,12 @@ table_insert(Relation rel, TupleTableSlot *slot, CommandId cid, bistate); } +static inline bool +table_support_insert(Relation rel) +{ + return rel->rd_tableam == NULL || rel->rd_tableam->tuple_insert != NULL; +} + /* * Perform a "speculative insertion". These can be backed out afterwards * without aborting the whole transaction. Other sessions can wait for the @@ -1082,6 +1088,14 @@ table_complete_speculative(Relation rel, TupleTableSlot *slot, succeeded); } +static inline bool +table_support_speculative(Relation rel) +{ + return rel->rd_tableam == NULL || + (rel->rd_tableam->tuple_insert_speculative != NULL && + rel->rd_tableam->tuple_complete_speculative != NULL); +} + /* * Insert multiple tuples into a table. * @@ -1104,6 +1118,14 @@ table_multi_insert(Relation rel, TupleTableSlot **slots, int nslots, cid, options, bistate); } +static inline bool +table_support_multi_insert(Relation rel) +{ + return rel->rd_tableam == NULL || + (rel->rd_tableam->multi_insert != NULL && + rel->rd_tableam->finish_bulk_insert != NULL); +} + /* * Delete a tuple. * @@ -1140,6 +1162,12 @@ table_delete(Relation rel, ItemPointer tid, CommandId cid, wait, tmfd, changingPart); } +static inline bool +table_support_delete(Relation rel) +{ + return rel->rd_tableam == NULL || rel->rd_tableam->tuple_delete != NULL; +} + /* * Update a tuple. * @@ -1186,6 +1214,12 @@ table_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, lockmode, update_indexes); } +static inline TM_Result +table_support_update(Relation rel) +{ + return rel->rd_tableam == NULL || rel->rd_tableam->tuple_update; +} + /* * Lock a tuple in the specified mode. * -- 2.16.4