Skip to content

Commit 6c61d7c

Browse files
author
Etsuro Fujita
committed
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
1 parent d723f56 commit 6c61d7c

File tree

1 file changed

+103
-180
lines changed

1 file changed

+103
-180
lines changed

contrib/postgres_fdw/postgres_fdw.c

Lines changed: 103 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,11 @@ static PgFdwModifyState *create_foreign_modify(EState *estate,
391391
List *target_attrs,
392392
bool has_returning,
393393
List *retrieved_attrs);
394+
static TupleTableSlot *execute_foreign_modify(EState *estate,
395+
ResultRelInfo *resultRelInfo,
396+
CmdType operation,
397+
TupleTableSlot *slot,
398+
TupleTableSlot *planSlot);
394399
static void prepare_foreign_modify(PgFdwModifyState *fmstate);
395400
static const char **convert_prep_stmt_params(PgFdwModifyState *fmstate,
396401
ItemPointer tupleid,
@@ -1776,58 +1781,8 @@ postgresExecForeignInsert(EState *estate,
17761781
TupleTableSlot *slot,
17771782
TupleTableSlot *planSlot)
17781783
{
1779-
PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1780-
const char **p_values;
1781-
PGresult *res;
1782-
int n_rows;
1783-
1784-
/* Set up the prepared statement on the remote server, if we didn't yet */
1785-
if (!fmstate->p_name)
1786-
prepare_foreign_modify(fmstate);
1787-
1788-
/* Convert parameters needed by prepared statement to text form */
1789-
p_values = convert_prep_stmt_params(fmstate, NULL, slot);
1790-
1791-
/*
1792-
* Execute the prepared statement.
1793-
*/
1794-
if (!PQsendQueryPrepared(fmstate->conn,
1795-
fmstate->p_name,
1796-
fmstate->p_nums,
1797-
p_values,
1798-
NULL,
1799-
NULL,
1800-
0))
1801-
pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1802-
1803-
/*
1804-
* Get the result, and check for success.
1805-
*
1806-
* We don't use a PG_TRY block here, so be careful not to throw error
1807-
* without releasing the PGresult.
1808-
*/
1809-
res = pgfdw_get_result(fmstate->conn, fmstate->query);
1810-
if (PQresultStatus(res) !=
1811-
(fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
1812-
pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1813-
1814-
/* Check number of rows affected, and fetch RETURNING tuple if any */
1815-
if (fmstate->has_returning)
1816-
{
1817-
n_rows = PQntuples(res);
1818-
if (n_rows > 0)
1819-
store_returning_result(fmstate, slot, res);
1820-
}
1821-
else
1822-
n_rows = atoi(PQcmdTuples(res));
1823-
1824-
/* And clean up */
1825-
PQclear(res);
1826-
1827-
MemoryContextReset(fmstate->temp_cxt);
1828-
1829-
/* Return NULL if nothing was inserted on the remote end */
1830-
return (n_rows > 0) ? slot : NULL;
1784+
return execute_foreign_modify(estate, resultRelInfo, CMD_INSERT,
1785+
slot, planSlot);
18311786
}
18321787

18331788
/*
@@ -1840,70 +1795,8 @@ postgresExecForeignUpdate(EState *estate,
18401795
TupleTableSlot *slot,
18411796
TupleTableSlot *planSlot)
18421797
{
1843-
PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1844-
Datum datum;
1845-
bool isNull;
1846-
const char **p_values;
1847-
PGresult *res;
1848-
int n_rows;
1849-
1850-
/* Set up the prepared statement on the remote server, if we didn't yet */
1851-
if (!fmstate->p_name)
1852-
prepare_foreign_modify(fmstate);
1853-
1854-
/* Get the ctid that was passed up as a resjunk column */
1855-
datum = ExecGetJunkAttribute(planSlot,
1856-
fmstate->ctidAttno,
1857-
&isNull);
1858-
/* shouldn't ever get a null result... */
1859-
if (isNull)
1860-
elog(ERROR, "ctid is NULL");
1861-
1862-
/* Convert parameters needed by prepared statement to text form */
1863-
p_values = convert_prep_stmt_params(fmstate,
1864-
(ItemPointer) DatumGetPointer(datum),
1865-
slot);
1866-
1867-
/*
1868-
* Execute the prepared statement.
1869-
*/
1870-
if (!PQsendQueryPrepared(fmstate->conn,
1871-
fmstate->p_name,
1872-
fmstate->p_nums,
1873-
p_values,
1874-
NULL,
1875-
NULL,
1876-
0))
1877-
pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1878-
1879-
/*
1880-
* Get the result, and check for success.
1881-
*
1882-
* We don't use a PG_TRY block here, so be careful not to throw error
1883-
* without releasing the PGresult.
1884-
*/
1885-
res = pgfdw_get_result(fmstate->conn, fmstate->query);
1886-
if (PQresultStatus(res) !=
1887-
(fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
1888-
pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1889-
1890-
/* Check number of rows affected, and fetch RETURNING tuple if any */
1891-
if (fmstate->has_returning)
1892-
{
1893-
n_rows = PQntuples(res);
1894-
if (n_rows > 0)
1895-
store_returning_result(fmstate, slot, res);
1896-
}
1897-
else
1898-
n_rows = atoi(PQcmdTuples(res));
1899-
1900-
/* And clean up */
1901-
PQclear(res);
1902-
1903-
MemoryContextReset(fmstate->temp_cxt);
1904-
1905-
/* Return NULL if nothing was updated on the remote end */
1906-
return (n_rows > 0) ? slot : NULL;
1798+
return execute_foreign_modify(estate, resultRelInfo, CMD_UPDATE,
1799+
slot, planSlot);
19071800
}
19081801

19091802
/*
@@ -1916,70 +1809,8 @@ postgresExecForeignDelete(EState *estate,
19161809
TupleTableSlot *slot,
19171810
TupleTableSlot *planSlot)
19181811
{
1919-
PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
1920-
Datum datum;
1921-
bool isNull;
1922-
const char **p_values;
1923-
PGresult *res;
1924-
int n_rows;
1925-
1926-
/* Set up the prepared statement on the remote server, if we didn't yet */
1927-
if (!fmstate->p_name)
1928-
prepare_foreign_modify(fmstate);
1929-
1930-
/* Get the ctid that was passed up as a resjunk column */
1931-
datum = ExecGetJunkAttribute(planSlot,
1932-
fmstate->ctidAttno,
1933-
&isNull);
1934-
/* shouldn't ever get a null result... */
1935-
if (isNull)
1936-
elog(ERROR, "ctid is NULL");
1937-
1938-
/* Convert parameters needed by prepared statement to text form */
1939-
p_values = convert_prep_stmt_params(fmstate,
1940-
(ItemPointer) DatumGetPointer(datum),
1941-
NULL);
1942-
1943-
/*
1944-
* Execute the prepared statement.
1945-
*/
1946-
if (!PQsendQueryPrepared(fmstate->conn,
1947-
fmstate->p_name,
1948-
fmstate->p_nums,
1949-
p_values,
1950-
NULL,
1951-
NULL,
1952-
0))
1953-
pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
1954-
1955-
/*
1956-
* Get the result, and check for success.
1957-
*
1958-
* We don't use a PG_TRY block here, so be careful not to throw error
1959-
* without releasing the PGresult.
1960-
*/
1961-
res = pgfdw_get_result(fmstate->conn, fmstate->query);
1962-
if (PQresultStatus(res) !=
1963-
(fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
1964-
pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
1965-
1966-
/* Check number of rows affected, and fetch RETURNING tuple if any */
1967-
if (fmstate->has_returning)
1968-
{
1969-
n_rows = PQntuples(res);
1970-
if (n_rows > 0)
1971-
store_returning_result(fmstate, slot, res);
1972-
}
1973-
else
1974-
n_rows = atoi(PQcmdTuples(res));
1975-
1976-
/* And clean up */
1977-
PQclear(res);
1978-
1979-
MemoryContextReset(fmstate->temp_cxt);
1980-
1981-
/* Return NULL if nothing was deleted on the remote end */
1982-
return (n_rows > 0) ? slot : NULL;
1812+
return execute_foreign_modify(estate, resultRelInfo, CMD_DELETE,
1813+
slot, planSlot);
19831814
}
19841815

19851816
/*
@@ -3425,6 +3256,98 @@ create_foreign_modify(EState *estate,
34253256
return fmstate;
34263257
}
34273258

3259+
/*
3260+
* execute_foreign_modify
3261+
* Perform foreign-table modification as required, and fetch RETURNING
3262+
* result if any. (This is the shared guts of postgresExecForeignInsert,
3263+
* postgresExecForeignUpdate, and postgresExecForeignDelete.)
3264+
*/
3265+
static TupleTableSlot *
3266+
execute_foreign_modify(EState *estate,
3267+
ResultRelInfo *resultRelInfo,
3268+
CmdType operation,
3269+
TupleTableSlot *slot,
3270+
TupleTableSlot *planSlot)
3271+
{
3272+
PgFdwModifyState *fmstate = (PgFdwModifyState *) resultRelInfo->ri_FdwState;
3273+
ItemPointer ctid = NULL;
3274+
const char **p_values;
3275+
PGresult *res;
3276+
int n_rows;
3277+
3278+
/* The operation should be INSERT, UPDATE, or DELETE */
3279+
Assert(operation == CMD_INSERT ||
3280+
operation == CMD_UPDATE ||
3281+
operation == CMD_DELETE);
3282+
3283+
/* Set up the prepared statement on the remote server, if we didn't yet */
3284+
if (!fmstate->p_name)
3285+
prepare_foreign_modify(fmstate);
3286+
3287+
/*
3288+
* For UPDATE/DELETE, get the ctid that was passed up as a resjunk column
3289+
*/
3290+
if (operation == CMD_UPDATE || operation == CMD_DELETE)
3291+
{
3292+
Datum datum;
3293+
bool isNull;
3294+
3295+
datum = ExecGetJunkAttribute(planSlot,
3296+
fmstate->ctidAttno,
3297+
&isNull);
3298+
/* shouldn't ever get a null result... */
3299+
if (isNull)
3300+
elog(ERROR, "ctid is NULL");
3301+
ctid = (ItemPointer) DatumGetPointer(datum);
3302+
}
3303+
3304+
/* Convert parameters needed by prepared statement to text form */
3305+
p_values = convert_prep_stmt_params(fmstate, ctid, slot);
3306+
3307+
/*
3308+
* Execute the prepared statement.
3309+
*/
3310+
if (!PQsendQueryPrepared(fmstate->conn,
3311+
fmstate->p_name,
3312+
fmstate->p_nums,
3313+
p_values,
3314+
NULL,
3315+
NULL,
3316+
0))
3317+
pgfdw_report_error(ERROR, NULL, fmstate->conn, false, fmstate->query);
3318+
3319+
/*
3320+
* Get the result, and check for success.
3321+
*
3322+
* We don't use a PG_TRY block here, so be careful not to throw error
3323+
* without releasing the PGresult.
3324+
*/
3325+
res = pgfdw_get_result(fmstate->conn, fmstate->query);
3326+
if (PQresultStatus(res) !=
3327+
(fmstate->has_returning ? PGRES_TUPLES_OK : PGRES_COMMAND_OK))
3328+
pgfdw_report_error(ERROR, res, fmstate->conn, true, fmstate->query);
3329+
3330+
/* Check number of rows affected, and fetch RETURNING tuple if any */
3331+
if (fmstate->has_returning)
3332+
{
3333+
n_rows = PQntuples(res);
3334+
if (n_rows > 0)
3335+
store_returning_result(fmstate, slot, res);
3336+
}
3337+
else
3338+
n_rows = atoi(PQcmdTuples(res));
3339+
3340+
/* And clean up */
3341+
PQclear(res);
3342+
3343+
MemoryContextReset(fmstate->temp_cxt);
3344+
3345+
/*
3346+
* Return NULL if nothing was inserted/updated/deleted on the remote end
3347+
*/
3348+
return (n_rows > 0) ? slot : NULL;
3349+
}
3350+
34283351
/*
34293352
* prepare_foreign_modify
34303353
* Establish a prepared statement for execution of INSERT/UPDATE/DELETE

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy