aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/ruleutils.c12
-rw-r--r--src/backend/utils/sort/tuplesort.c263
2 files changed, 268 insertions, 7 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index b62559ccdde..47fd957c994 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* out of it's tuple
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.34 1999/12/06 02:37:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.35 1999/12/13 01:27:01 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -1352,9 +1352,13 @@ get_rule_expr(Node *node, deparse_context *context)
{
Aggref *aggref = (Aggref *) node;
- appendStringInfo(buf, "%s(",
- quote_identifier(aggref->aggname));
- get_rule_expr(aggref->target, context);
+ appendStringInfo(buf, "%s(%s",
+ quote_identifier(aggref->aggname),
+ aggref->aggdistinct ? "DISTINCT " : "");
+ if (aggref->aggstar)
+ appendStringInfo(buf, "*");
+ else
+ get_rule_expr(aggref->target, context);
appendStringInfo(buf, ")");
}
break;
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 5297fde36dc..6e9a23f1cd1 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -3,8 +3,8 @@
* tuplesort.c
* Generalized tuple sorting routines.
*
- * This module handles sorting of either heap tuples or index tuples
- * (and could fairly easily support other kinds of sortable objects,
+ * This module handles sorting of heap tuples, index tuples, or single
+ * Datums (and could easily support other kinds of sortable objects,
* if necessary). It works efficiently for both small and large amounts
* of data. Small amounts are sorted in-memory using qsort(). Large
* amounts are sorted using temporary files and a standard external sort
@@ -77,7 +77,7 @@
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.2 1999/10/30 17:27:15 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.3 1999/12/13 01:27:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -87,7 +87,9 @@
#include "access/heapam.h"
#include "access/nbtree.h"
#include "miscadmin.h"
+#include "parser/parse_type.h"
#include "utils/logtape.h"
+#include "utils/lsyscache.h"
#include "utils/tuplesort.h"
/*
@@ -251,6 +253,17 @@ struct Tuplesortstate
*/
Relation indexRel;
bool enforceUnique; /* complain if we find duplicate tuples */
+
+ /*
+ * These variables are specific to the Datum case; they are set
+ * by tuplesort_begin_datum and used only by the DatumTuple routines.
+ */
+ Oid datumType;
+ Oid sortOperator;
+ FmgrInfo sortOpFn; /* cached lookup data for sortOperator */
+ /* we need typelen and byval in order to know how to copy the Datums. */
+ int datumTypeLen;
+ bool datumTypeByVal;
};
#define COMPARETUP(state,a,b) ((*(state)->comparetup) (state, a, b))
@@ -321,7 +334,22 @@ struct Tuplesortstate
*--------------------
*/
+/*
+ * For sorting single Datums, we build "pseudo tuples" that just carry
+ * the datum's value and null flag. For pass-by-reference data types,
+ * the actual data value appears after the DatumTupleHeader (MAXALIGNed,
+ * of course), and the value field in the header is just a pointer to it.
+ */
+
+typedef struct
+{
+ Datum val;
+ bool isNull;
+} DatumTuple;
+
+
static Tuplesortstate *tuplesort_begin_common(bool randomAccess);
+static void puttuple_common(Tuplesortstate *state, void *tuple);
static void inittapes(Tuplesortstate *state);
static void selectnewtape(Tuplesortstate *state);
static void mergeruns(Tuplesortstate *state);
@@ -349,6 +377,13 @@ static void writetup_index(Tuplesortstate *state, int tapenum, void *tup);
static void *readtup_index(Tuplesortstate *state, int tapenum,
unsigned int len);
static unsigned int tuplesize_index(Tuplesortstate *state, void *tup);
+static int comparetup_datum(Tuplesortstate *state,
+ const void *a, const void *b);
+static void *copytup_datum(Tuplesortstate *state, void *tup);
+static void writetup_datum(Tuplesortstate *state, int tapenum, void *tup);
+static void *readtup_datum(Tuplesortstate *state, int tapenum,
+ unsigned int len);
+static unsigned int tuplesize_datum(Tuplesortstate *state, void *tup);
/*
* Since qsort(3) will not pass any context info to qsort_comparetup(),
@@ -369,6 +404,7 @@ static Tuplesortstate *qsort_tuplesortstate;
* have been supplied. After performsort, retrieve the tuples in sorted
* order by calling tuplesort_gettuple until it returns NULL. (If random
* access was requested, rescan, markpos, and restorepos can also be called.)
+ * For Datum sorts, putdatum/getdatum are used instead of puttuple/gettuple.
* Call tuplesort_end to terminate the operation and release memory/disk space.
*/
@@ -444,6 +480,32 @@ tuplesort_begin_index(Relation indexRel,
return state;
}
+Tuplesortstate *
+tuplesort_begin_datum(Oid datumType,
+ Oid sortOperator,
+ bool randomAccess)
+{
+ Tuplesortstate *state = tuplesort_begin_common(randomAccess);
+ Type typeInfo;
+
+ state->comparetup = comparetup_datum;
+ state->copytup = copytup_datum;
+ state->writetup = writetup_datum;
+ state->readtup = readtup_datum;
+ state->tuplesize = tuplesize_datum;
+
+ state->datumType = datumType;
+ state->sortOperator = sortOperator;
+ /* lookup the function that implements the sort operator */
+ fmgr_info(get_opcode(sortOperator), &state->sortOpFn);
+ /* lookup necessary attributes of the datum type */
+ typeInfo = typeidType(datumType);
+ state->datumTypeLen = typeLen(typeInfo);
+ state->datumTypeByVal = typeByVal(typeInfo);
+
+ return state;
+}
+
/*
* tuplesort_end
*
@@ -476,9 +538,60 @@ tuplesort_puttuple(Tuplesortstate *state, void *tuple)
{
/*
* Copy the given tuple into memory we control, and decrease availMem.
+ * Then call the code shared with the Datum case.
*/
tuple = COPYTUP(state, tuple);
+ puttuple_common(state, tuple);
+}
+
+/*
+ * Accept one Datum while collecting input data for sort.
+ *
+ * If the Datum is pass-by-ref type, the value will be copied.
+ */
+void
+tuplesort_putdatum(Tuplesortstate *state, Datum val, bool isNull)
+{
+ DatumTuple *tuple;
+
+ /*
+ * Build pseudo-tuple carrying the datum, and decrease availMem.
+ */
+ if (isNull || state->datumTypeByVal)
+ {
+ USEMEM(state, sizeof(DatumTuple));
+ tuple = (DatumTuple *) palloc(sizeof(DatumTuple));
+ tuple->val = val;
+ tuple->isNull = isNull;
+ }
+ else
+ {
+ int datalen = state->datumTypeLen;
+ int tuplelen;
+ char *newVal;
+
+ if (datalen == -1) /* variable length type? */
+ datalen = VARSIZE((struct varlena *) DatumGetPointer(val));
+ tuplelen = datalen + MAXALIGN(sizeof(DatumTuple));
+ USEMEM(state, tuplelen);
+ newVal = (char *) palloc(tuplelen);
+ tuple = (DatumTuple *) newVal;
+ newVal += MAXALIGN(sizeof(DatumTuple));
+ memcpy(newVal, DatumGetPointer(val), datalen);
+ tuple->val = PointerGetDatum(newVal);
+ tuple->isNull = false;
+ }
+
+ puttuple_common(state, (void *) tuple);
+}
+
+/*
+ * Shared code for tuple and datum cases.
+ */
+static void
+puttuple_common(Tuplesortstate *state, void *tuple)
+{
switch (state->status)
{
case TSS_INITIAL:
@@ -754,6 +867,50 @@ tuplesort_gettuple(Tuplesortstate *state, bool forward,
}
/*
+ * Fetch the next Datum in either forward or back direction.
+ * Returns FALSE if no more datums.
+ *
+ * If the Datum is pass-by-ref type, the returned value is freshly palloc'd
+ * and is now owned by the caller.
+ */
+bool
+tuplesort_getdatum(Tuplesortstate *state, bool forward,
+ Datum *val, bool *isNull)
+{
+ DatumTuple *tuple;
+ bool should_free;
+
+ tuple = (DatumTuple *) tuplesort_gettuple(state, forward, &should_free);
+
+ if (tuple == NULL)
+ return false;
+
+ if (tuple->isNull || state->datumTypeByVal)
+ {
+ *val = tuple->val;
+ *isNull = tuple->isNull;
+ }
+ else
+ {
+ int datalen = state->datumTypeLen;
+ char *newVal;
+
+ if (datalen == -1) /* variable length type? */
+ datalen = VARSIZE((struct varlena *) DatumGetPointer(tuple->val));
+ newVal = (char *) palloc(datalen);
+ memcpy(newVal, DatumGetPointer(tuple->val), datalen);
+ *val = PointerGetDatum(newVal);
+ *isNull = false;
+ }
+
+ if (should_free)
+ pfree(tuple);
+
+ return true;
+}
+
+
+/*
* inittapes - initialize for tape sorting.
*
* This is called only if we have found we don't have room to sort in memory.
@@ -1695,3 +1852,103 @@ tuplesize_index(Tuplesortstate *state, void *tup)
return tuplen;
}
+
+
+/*
+ * Routines specialized for DatumTuple case
+ */
+
+static int
+comparetup_datum(Tuplesortstate *state, const void *a, const void *b)
+{
+ DatumTuple *ltup = (DatumTuple *) a;
+ DatumTuple *rtup = (DatumTuple *) b;
+
+ if (ltup->isNull)
+ {
+ if (!rtup->isNull)
+ return 1; /* NULL sorts after non-NULL */
+ return 0;
+ }
+ else if (rtup->isNull)
+ return -1;
+ else
+ {
+ int result;
+
+ if (!(result = - (int) (*fmgr_faddr(&state->sortOpFn)) (ltup->val,
+ rtup->val)))
+ result = (int) (*fmgr_faddr(&state->sortOpFn)) (rtup->val,
+ ltup->val);
+ return result;
+ }
+}
+
+static void *
+copytup_datum(Tuplesortstate *state, void *tup)
+{
+ /* Not currently needed */
+ elog(ERROR, "copytup_datum() should not be called");
+ return NULL;
+}
+
+static void
+writetup_datum(Tuplesortstate *state, int tapenum, void *tup)
+{
+ DatumTuple *tuple = (DatumTuple *) tup;
+ unsigned int tuplen = tuplesize_datum(state, tup);
+ unsigned int writtenlen = tuplen + sizeof(unsigned int);
+
+ LogicalTapeWrite(state->tapeset, tapenum,
+ (void*) &writtenlen, sizeof(writtenlen));
+ LogicalTapeWrite(state->tapeset, tapenum,
+ (void*) tuple, tuplen);
+ if (state->randomAccess) /* need trailing length word? */
+ LogicalTapeWrite(state->tapeset, tapenum,
+ (void*) &writtenlen, sizeof(writtenlen));
+
+ FREEMEM(state, tuplen);
+ pfree(tuple);
+}
+
+static void *
+readtup_datum(Tuplesortstate *state, int tapenum, unsigned int len)
+{
+ unsigned int tuplen = len - sizeof(unsigned int);
+ DatumTuple *tuple = (DatumTuple *) palloc(tuplen);
+
+ USEMEM(state, tuplen);
+ if (LogicalTapeRead(state->tapeset, tapenum, (void *) tuple,
+ tuplen) != tuplen)
+ elog(ERROR, "tuplesort: unexpected end of data");
+ if (state->randomAccess) /* need trailing length word? */
+ if (LogicalTapeRead(state->tapeset, tapenum, (void *) &tuplen,
+ sizeof(tuplen)) != sizeof(tuplen))
+ elog(ERROR, "tuplesort: unexpected end of data");
+
+ if (!tuple->isNull && !state->datumTypeByVal)
+ tuple->val = PointerGetDatum(((char *) tuple) +
+ MAXALIGN(sizeof(DatumTuple)));
+ return (void *) tuple;
+}
+
+static unsigned int
+tuplesize_datum(Tuplesortstate *state, void *tup)
+{
+ DatumTuple *tuple = (DatumTuple *) tup;
+
+ if (tuple->isNull || state->datumTypeByVal)
+ {
+ return (unsigned int) sizeof(DatumTuple);
+ }
+ else
+ {
+ int datalen = state->datumTypeLen;
+ int tuplelen;
+
+ if (datalen == -1) /* variable length type? */
+ datalen = VARSIZE((struct varlena *) DatumGetPointer(tuple->val));
+ tuplelen = datalen + MAXALIGN(sizeof(DatumTuple));
+ return (unsigned int) tuplelen;
+ }
+}