diff options
author | Etsuro Fujita <efujita@postgresql.org> | 2019-01-17 14:37:33 +0900 |
---|---|---|
committer | Etsuro Fujita <efujita@postgresql.org> | 2019-01-17 14:37:33 +0900 |
commit | 6c61d7c5935793e218d2335ac540a2cea7eacdce (patch) | |
tree | 8cb7a34beea8b6f98bea36755f54dc949e9ca33a /contrib/postgres_fdw/postgres_fdw.c | |
parent | d723f56872a9fd1b898b7ee29ca5d26a9e538058 (diff) | |
download | postgresql-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.c | 283 |
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 */ |