Add a new tuplestore API function, tuplestore_putvalues(). This is
authorNeil Conway
Tue, 25 Mar 2008 19:26:54 +0000 (19:26 +0000)
committerNeil Conway
Tue, 25 Mar 2008 19:26:54 +0000 (19:26 +0000)
identical to tuplestore_puttuple(), except it operates on arrays of
Datums + nulls rather than a fully-formed HeapTuple. In several places
that use the tuplestore API, this means we can avoid creating a
HeapTuple altogether, saving a copy.

src/backend/commands/prepare.c
src/backend/executor/execQual.c
src/backend/utils/mmgr/portalmem.c
src/backend/utils/sort/tuplestore.c
src/include/utils/tuplestore.h
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_exec.c

index 2199e109d46ec142c0fa3c0626e9e252a9009975..9db486581ed543362f97c7ae0048e1adf30085df 100644 (file)
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.80 2008/01/01 19:45:49 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.81 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -764,7 +764,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
        hash_seq_init(&hash_seq, prepared_queries);
        while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
        {
-           HeapTuple   tuple;
            Datum       values[5];
            bool        nulls[5];
 
@@ -787,11 +786,9 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
                                          prep_stmt->plansource->num_params);
            values[4] = BoolGetDatum(prep_stmt->from_sql);
 
-           tuple = heap_form_tuple(tupdesc, values, nulls);
-
            /* switch to appropriate context while storing the tuple */
            MemoryContextSwitchTo(per_query_ctx);
-           tuplestore_puttuple(tupstore, tuple);
+           tuplestore_putvalues(tupstore, tupdesc, values, nulls);
        }
    }
 
index 6e7daa40e8fe7ed8b0bf8d2cdb11ac199fc34866..97d22dc2cd345e23f5317627b6d69331faff88fc 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.226 2008/01/01 19:45:49 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.227 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1547,7 +1547,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
    for (;;)
    {
        Datum       result;
-       HeapTuple   tuple;
 
        CHECK_FOR_INTERRUPTS();
 
@@ -1649,15 +1648,15 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
                 */
                tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
                tmptup.t_data = td;
-               tuple = &tmptup;
+
+               oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+               tuplestore_puttuple(tupstore, &tmptup);
            }
            else
            {
-               tuple = heap_form_tuple(tupdesc, &result, &fcinfo.isnull);
+               oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+               tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo.isnull);
            }
-
-           oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
-           tuplestore_puttuple(tupstore, tuple);
            MemoryContextSwitchTo(oldcontext);
 
            /*
@@ -1702,15 +1701,13 @@ no_function_result:
            int         natts = expectedDesc->natts;
            Datum      *nulldatums;
            bool       *nullflags;
-           HeapTuple   tuple;
 
            MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
            nulldatums = (Datum *) palloc0(natts * sizeof(Datum));
            nullflags = (bool *) palloc(natts * sizeof(bool));
            memset(nullflags, true, natts * sizeof(bool));
-           tuple = heap_form_tuple(expectedDesc, nulldatums, nullflags);
            MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
-           tuplestore_puttuple(tupstore, tuple);
+           tuplestore_putvalues(tupstore, expectedDesc, nulldatums, nullflags);
        }
    }
 
index ca5604a61d5162666508912fb707a022ce144bf5..63bf48124a81f7265436fffe0c38d714490d4ed9 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.106 2008/01/01 19:45:55 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.107 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -911,7 +911,6 @@ pg_cursor(PG_FUNCTION_ARGS)
    while ((hentry = hash_seq_search(&hash_seq)) != NULL)
    {
        Portal      portal = hentry->portal;
-       HeapTuple   tuple;
        Datum       values[6];
        bool        nulls[6];
 
@@ -935,11 +934,9 @@ pg_cursor(PG_FUNCTION_ARGS)
        values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
        values[5] = TimestampTzGetDatum(portal->creation_time);
 
-       tuple = heap_form_tuple(tupdesc, values, nulls);
-
        /* switch to appropriate context while storing the tuple */
        MemoryContextSwitchTo(per_query_ctx);
-       tuplestore_puttuple(tupstore, tuple);
+       tuplestore_putvalues(tupstore, tupdesc, values, nulls);
    }
 
    /* clean up and return the tuplestore */
index d6c192993e2de40b1db4821894ec972d07360176..da8de84d684b12c4e0dc09deb453c14622893fa2 100644 (file)
@@ -38,7 +38,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.37 2008/03/10 20:06:27 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.38 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -366,8 +366,6 @@ tuplestore_puttupleslot(Tuplestorestate *state,
 /*
  * "Standard" case to copy from a HeapTuple.  This is actually now somewhat
  * deprecated, but not worth getting rid of in view of the number of callers.
- * (Consider adding something that takes a tupdesc+values/nulls arrays so
- * that we can use heap_form_minimal_tuple() and avoid a copy step.)
  */
 void
 tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
@@ -380,6 +378,22 @@ tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
    tuplestore_puttuple_common(state, (void *) tuple);
 }
 
+/*
+ * Similar to tuplestore_puttuple(), but start from the values + nulls
+ * array. This avoids requiring that the caller construct a HeapTuple,
+ * saving a copy.
+ */
+void
+tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc,
+                    Datum *values, bool *isnull)
+{
+   MinimalTuple tuple;
+
+   tuple = heap_form_minimal_tuple(tdesc, values, isnull);
+
+   tuplestore_puttuple_common(state, (void *) tuple);
+}
+
 static void
 tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
 {
index ee7d22b6114a3fc227ee3170dade67a6dd6b4d52..37f99fea3bd56288adebb64cd98ac22eb4430d74 100644 (file)
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/tuplestore.h,v 1.22 2008/01/01 19:45:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/tuplestore.h,v 1.23 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,8 @@ extern void tuplestore_set_eflags(Tuplestorestate *state, int eflags);
 extern void tuplestore_puttupleslot(Tuplestorestate *state,
                        TupleTableSlot *slot);
 extern void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple);
+extern void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc,
+                                Datum *values, bool *isnull);
 
 /* tuplestore_donestoring() used to be required, but is no longer used */
 #define tuplestore_donestoring(state)  ((void) 0)
index 452c69cec733be72cbd0677d835ef18ba0397ad6..3ce8f60c2625bb03c62e4edee11ec4fc6eec633a 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plperl.c - perl as a procedural language for PostgreSQL
  *
- *   $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.136 2008/01/23 00:55:47 adunstan Exp $
+ *   $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.137 2008/03/25 19:26:53 neilc Exp $
  *
  **********************************************************************/
 
@@ -1869,7 +1869,6 @@ plperl_return_next(SV *sv)
    FunctionCallInfo fcinfo;
    ReturnSetInfo *rsi;
    MemoryContext old_cxt;
-   HeapTuple   tuple;
 
    if (!sv)
        return;
@@ -1944,8 +1943,15 @@ plperl_return_next(SV *sv)
 
    if (prodesc->fn_retistuple)
    {
+       HeapTuple tuple;
+
        tuple = plperl_build_tuple_result((HV *) SvRV(sv),
                                          current_call_data->attinmeta);
+
+       /* Make sure to store the tuple in a long-lived memory context */
+       MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+       tuplestore_puttuple(current_call_data->tuple_store, tuple);
+       MemoryContextSwitchTo(old_cxt);
    }
    else
    {
@@ -1967,14 +1973,14 @@ plperl_return_next(SV *sv)
            isNull = true;
        }
 
-       tuple = heap_form_tuple(current_call_data->ret_tdesc, &ret, &isNull);
+       /* Make sure to store the tuple in a long-lived memory context */
+       MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+       tuplestore_putvalues(current_call_data->tuple_store,
+                            current_call_data->ret_tdesc,
+                            &ret, &isNull);
+       MemoryContextSwitchTo(old_cxt);
    }
 
-   /* Make sure to store the tuple in a long-lived memory context */
-   MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-   tuplestore_puttuple(current_call_data->tuple_store, tuple);
-   MemoryContextSwitchTo(old_cxt);
-
    MemoryContextReset(current_call_data->tmp_cxt);
 }
 
index 976246f67480c5279c1f2334c4cbde38b7a148c3..25702f2a8785aaa006c9c8b5242566cdcb816eb1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.202 2008/01/01 19:46:00 momjian Exp $
+ *   $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.203 2008/03/25 19:26:54 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2007,10 +2007,11 @@ static int
 exec_stmt_return_next(PLpgSQL_execstate *estate,
                      PLpgSQL_stmt_return_next *stmt)
 {
-   TupleDesc   tupdesc;
-   int         natts;
-   HeapTuple   tuple;
-   bool        free_tuple = false;
+   TupleDesc       tupdesc;
+   int             natts;
+   MemoryContext   oldcxt;
+   HeapTuple       tuple = NULL;
+   bool            free_tuple = false;
 
    if (!estate->retisset)
        ereport(ERROR,
@@ -2048,9 +2049,10 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                                                tupdesc->attrs[0]->atttypmod,
                                                    isNull);
 
-                   tuple = heap_form_tuple(tupdesc, &retval, &isNull);
-
-                   free_tuple = true;
+                   oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
+                   tuplestore_putvalues(estate->tuple_store, tupdesc,
+                                        &retval, &isNull);
+                   MemoryContextSwitchTo(oldcxt);
                }
                break;
 
@@ -2087,7 +2089,6 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 
            default:
                elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
-               tuple = NULL;   /* keep compiler quiet */
                break;
        }
    }
@@ -2114,9 +2115,10 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
                                        tupdesc->attrs[0]->atttypmod,
                                        isNull);
 
-       tuple = heap_form_tuple(tupdesc, &retval, &isNull);
-
-       free_tuple = true;
+       oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
+       tuplestore_putvalues(estate->tuple_store, tupdesc,
+                            &retval, &isNull);
+       MemoryContextSwitchTo(oldcxt);
 
        exec_eval_cleanup(estate);
    }
@@ -2125,13 +2127,10 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("RETURN NEXT must have a parameter")));
-       tuple = NULL;           /* keep compiler quiet */
    }
 
    if (HeapTupleIsValid(tuple))
    {
-       MemoryContext oldcxt;
-
        oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
        tuplestore_puttuple(estate->tuple_store, tuple);
        MemoryContextSwitchTo(oldcxt);