aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/postgres_fdw.c
diff options
context:
space:
mode:
authorEtsuro Fujita <efujita@postgresql.org>2019-01-17 14:37:33 +0900
committerEtsuro Fujita <efujita@postgresql.org>2019-01-17 14:37:33 +0900
commit6c61d7c5935793e218d2335ac540a2cea7eacdce (patch)
tree8cb7a34beea8b6f98bea36755f54dc949e9ca33a /contrib/postgres_fdw/postgres_fdw.c
parentd723f56872a9fd1b898b7ee29ca5d26a9e538058 (diff)
downloadpostgresql-6c61d7c5935793e218d2335ac540a2cea7eacdce.tar.gz
postgresql-6c61d7c5935793e218d2335ac540a2cea7eacdce.zip
postgres_fdw: Remove duplicate code in DML execution callback functions.
postgresExecForeignInsert(), postgresExecForeignUpdate(), and postgresExecForeignDelete() are coded almost identically, except that postgresExecForeignInsert() does not need CTID. Extract that code into a separate function and use it in all the three function implementations. Author: Ashutosh Bapat Reviewed-By: Michael Paquier Discussion: https://postgr.es/m/CAFjFpRcz8yoY7cBTYofcrCLwjaDeCcGKyTUivUbRiA57y3v-bw%40mail.gmail.com
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c283
1 files changed, 103 insertions, 180 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 64efbdff082..685259a0033 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -391,6 +391,11 @@ static PgFdwModifyState *create_foreign_modify(EState *estate,
List *target_attrs,
bool has_returning,
List *retrieved_attrs);
+static TupleTableSlot *execute_foreign_modify(EState *estate,
+ ResultRelInfo *resultRelInfo,
+ CmdType operation,
+ TupleTableSlot *slot,
+ TupleTableSlot *planSlot);
static void prepare_foreign_modify(PgFdwModifyState *fmstate);
static const char **convert_prep_stmt_params(PgFdwModifyState *fmstate,
ItemPointer tupleid,
@@ -1776,58 +1781,8 @@ postgresExecForeignInsert(EState *estate,
TupleTableSlot *slot,
TupleTableSlot *planSlot)
{
- PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
- const char **p_values;
- PGresult *res;
- int n_rows;
-
- /* Set up the prepared statement on the remote server, if we didn't yet */
- if (!fmstate->p_name)
- prepare_foreign_modify(fmstate);
-
- /* Convert parameters needed by prepared statement to text form */
- p_values = convert_prep_stmt_params(fmstate, NULL, slot);
-
- /*
- * Execute the prepared statement.
- */
- if (!PQsendQueryPrepared(fmstate->conn,
- fmstate->p_name,
- fmstate->p_nums,
- p_values,
- NULL,
- NULL,
- 0))
- pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
-
- /*
- * Get the result, and check for success.
- *
- * We don't use a PG_TRY block here, so be careful not to throw error
- * without releasing the PGresult.
- */
- res = pgfdw_get_result(fmstate->conn, fmstate->query);
- if (PQresultStatus(res) !=
- (fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
- pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
-
- /* Check number of rows affected, and fetch RETURNING tuple if any */
- if (fmstate->has_returning)
- {
- n_rows = PQntuples(res);
- if (n_rows > 0)
- store_returning_result(fmstate, slot, res);
- }
- else
- n_rows = atoi(PQcmdTuples(res));
-
- /* And clean up */
- PQclear(res);
-
- MemoryContextReset(fmstate->temp_cxt);
-
- /* Return NULL if nothing was inserted on the remote end */
- return (n_rows > 0) ? slot : NULL;
+ return execute_foreign_modify(estate, resultRelInfo, CMD_INSERT,
+ slot, planSlot);
}
/*
@@ -1840,70 +1795,8 @@ postgresExecForeignUpdate(EState *estate,
TupleTableSlot *slot,
TupleTableSlot *planSlot)
{
- PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
- Datum datum;
- bool isNull;
- const char **p_values;
- PGresult *res;
- int n_rows;
-
- /* Set up the prepared statement on the remote server, if we didn't yet */
- if (!fmstate->p_name)
- prepare_foreign_modify(fmstate);
-
- /* Get the ctid that was passed up as a resjunk column */
- datum = ExecGetJunkAttribute(planSlot,
- fmstate->ctidAttno,
- &isNull);
- /* shouldn't ever get a null result... */
- if (isNull)
- elog(ERROR, "ctid is NULL");
-
- /* Convert parameters needed by prepared statement to text form */
- p_values = convert_prep_stmt_params(fmstate,
- (ItemPointer) DatumGetPointer(datum),
- slot);
-
- /*
- * Execute the prepared statement.
- */
- if (!PQsendQueryPrepared(fmstate->conn,
- fmstate->p_name,
- fmstate->p_nums,
- p_values,
- NULL,
- NULL,
- 0))
- pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
-
- /*
- * Get the result, and check for success.
- *
- * We don't use a PG_TRY block here, so be careful not to throw error
- * without releasing the PGresult.
- */
- res = pgfdw_get_result(fmstate->conn, fmstate->query);
- if (PQresultStatus(res) !=
- (fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
- pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
-
- /* Check number of rows affected, and fetch RETURNING tuple if any */
- if (fmstate->has_returning)
- {
- n_rows = PQntuples(res);
- if (n_rows > 0)
- store_returning_result(fmstate, slot, res);
- }
- else
- n_rows = atoi(PQcmdTuples(res));
-
- /* And clean up */
- PQclear(res);
-
- MemoryContextReset(fmstate->temp_cxt);
-
- /* Return NULL if nothing was updated on the remote end */
- return (n_rows > 0) ? slot : NULL;
+ return execute_foreign_modify(estate, resultRelInfo, CMD_UPDATE,
+ slot, planSlot);
}
/*
@@ -1916,70 +1809,8 @@ postgresExecForeignDelete(EState *estate,
TupleTableSlot *slot,
TupleTableSlot *planSlot)
{
- PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
- Datum datum;
- bool isNull;
- const char **p_values;
- PGresult *res;
- int n_rows;
-
- /* Set up the prepared statement on the remote server, if we didn't yet */
- if (!fmstate->p_name)
- prepare_foreign_modify(fmstate);
-
- /* Get the ctid that was passed up as a resjunk column */
- datum = ExecGetJunkAttribute(planSlot,
- fmstate->ctidAttno,
- &isNull);
- /* shouldn't ever get a null result... */
- if (isNull)
- elog(ERROR, "ctid is NULL");
-
- /* Convert parameters needed by prepared statement to text form */
- p_values = convert_prep_stmt_params(fmstate,
- (ItemPointer) DatumGetPointer(datum),
- NULL);
-
- /*
- * Execute the prepared statement.
- */
- if (!PQsendQueryPrepared(fmstate->conn,
- fmstate->p_name,
- fmstate->p_nums,
- p_values,
- NULL,
- NULL,
- 0))
- pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
-
- /*
- * Get the result, and check for success.
- *
- * We don't use a PG_TRY block here, so be careful not to throw error
- * without releasing the PGresult.
- */
- res = pgfdw_get_result(fmstate->conn, fmstate->query);
- if (PQresultStatus(res) !=
- (fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
- pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
-
- /* Check number of rows affected, and fetch RETURNING tuple if any */
- if (fmstate->has_returning)
- {
- n_rows = PQntuples(res);
- if (n_rows > 0)
- store_returning_result(fmstate, slot, res);
- }
- else
- n_rows = atoi(PQcmdTuples(res));
-
- /* And clean up */
- PQclear(res);
-
- MemoryContextReset(fmstate->temp_cxt);
-
- /* Return NULL if nothing was deleted on the remote end */
- return (n_rows > 0) ? slot : NULL;
+ return execute_foreign_modify(estate, resultRelInfo, CMD_DELETE,
+ slot, planSlot);
}
/*
@@ -3426,6 +3257,98 @@ create_foreign_modify(EState *estate,
}
/*
+ * execute_foreign_modify
+ * Perform foreign-table modification as required, and fetch RETURNING
+ * result if any. (This is the shared guts of postgresExecForeignInsert,
+ * postgresExecForeignUpdate, and postgresExecForeignDelete.)
+ */
+static TupleTableSlot *
+execute_foreign_modify(EState *estate,
+ ResultRelInfo *resultRelInfo,
+ CmdType operation,
+ TupleTableSlot *slot,
+ TupleTableSlot *planSlot)
+{
+ PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
+ ItemPointer ctid = NULL;
+ const char **p_values;
+ PGresult *res;
+ int n_rows;
+
+ /* The operation should be INSERT, UPDATE, or DELETE */
+ Assert(operation == CMD_INSERT ||
+ operation == CMD_UPDATE ||
+ operation == CMD_DELETE);
+
+ /* Set up the prepared statement on the remote server, if we didn't yet */
+ if (!fmstate->p_name)
+ prepare_foreign_modify(fmstate);
+
+ /*
+ * For UPDATE/DELETE, get the ctid that was passed up as a resjunk column
+ */
+ if (operation == CMD_UPDATE || operation == CMD_DELETE)
+ {
+ Datum datum;
+ bool isNull;
+
+ datum = ExecGetJunkAttribute(planSlot,
+ fmstate->ctidAttno,
+ &isNull);
+ /* shouldn't ever get a null result... */
+ if (isNull)
+ elog(ERROR, "ctid is NULL");
+ ctid = (ItemPointer) DatumGetPointer(datum);
+ }
+
+ /* Convert parameters needed by prepared statement to text form */
+ p_values = convert_prep_stmt_params(fmstate, ctid, slot);
+
+ /*
+ * Execute the prepared statement.
+ */
+ if (!PQsendQueryPrepared(fmstate->conn,
+ fmstate->p_name,
+ fmstate->p_nums,
+ p_values,
+ NULL,
+ NULL,
+ 0))
+ pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
+
+ /*
+ * Get the result, and check for success.
+ *
+ * We don't use a PG_TRY block here, so be careful not to throw error
+ * without releasing the PGresult.
+ */
+ res = pgfdw_get_result(fmstate->conn, fmstate->query);
+ if (PQresultStatus(res) !=
+ (fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
+ pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
+
+ /* Check number of rows affected, and fetch RETURNING tuple if any */
+ if (fmstate->has_returning)
+ {
+ n_rows = PQntuples(res);
+ if (n_rows > 0)
+ store_returning_result(fmstate, slot, res);
+ }
+ else
+ n_rows = atoi(PQcmdTuples(res));
+
+ /* And clean up */
+ PQclear(res);
+
+ MemoryContextReset(fmstate->temp_cxt);
+
+ /*
+ * Return NULL if nothing was inserted/updated/deleted on the remote end
+ */
+ return (n_rows > 0) ? slot : NULL;
+}
+
+/*
* prepare_foreign_modify
* Establish a prepared statement for execution of INSERT/UPDATE/DELETE
*/