<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.38 2002/02/17 13:29:00 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.39 2002/03/05 05:33:04 momjian Exp $
PostgreSQL documentation
-->
class="PARAMETER">value</replaceable> | DROP DEFAULT }
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
+ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
+ ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE {PLAIN | EXTERNAL | EXTENDED | MAIN}
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
RENAME [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> TO <replaceable
class="PARAMETER">newcolumn</replaceable>
The <literal>ALTER COLUMN SET STATISTICS</literal> form allows you to
set the statistics-gathering target for subsequent
<xref linkend="sql-analyze" endterm="sql-analyze-title"> operations.
+ The <literal>ALTER COLUMN SET STORAGE</literal> form allows the
+ column storage mode to be set. This controls whether this column is
+ held inline or in a supplementary table, and whether the data
+ should be compressed or not. <literal>PLAIN</literal> must be used
+ for fixed-length values such as <literal>INTEGER</literal> and is
+ inline, uncompressed. <literal>MAIN</literal> is for inline,
+ compressible data. <literal>EXTERNAL</literal> is for external,
+ uncompressed data and <literal>EXTENDED</literal> is for external,
+ compressed data. The use of <literal>EXTERNAL</literal> will make
+ substring operations on a column faster, at the penalty of
+ increased storage space.
The <literal>RENAME</literal> clause causes the name of a table,
column, index, or sequence to change without changing any of the
data. The data will remain of the same type and size after the
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.47 2002/01/20 22:19:56 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.48 2002/03/05 05:33:00 momjian Exp $
-->
<chapter id="xfunc">
this works in both strict and nonstrict functions.
</para>
+ <para>
+ Other options provided in the new-style interface are two
+ variants of the
+ <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
+ macros. The first of these,
+ <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>
+ guarantees to return a copy of the specified parameter which is
+ safe for writing into. (The normal macros will sometimes return a
+ pointer to the value which must not be written to. Using the
+ <function>PG_GETARG_<replaceable>xxx</replaceable>_COPY()</function>
+ macros guarantees a writable result.)
+ </para>
+
+ <para>
+ The second variant consists of the
+ <function>PG_GETARG_<replaceable>xxx</replaceable>_SLICE()</function>
+ macros which take three parameters. The first is the number of the
+ parameter (as above). The second and third are the offset and
+ length of the segment to be returned. Offsets are counted from
+ zero, and a negative length requests that the remainder of the
+ value be returned. These routines provide more efficient access to
+ parts of large values in the case where they have storage type
+ "external". (The storage type of a column can be specified using
+ <command>ALTER TABLE <repaceable>tablename</replaceable> ALTER
+ COLUMN <replaceable>colname</replaceable> SET STORAGE
+ <replaceable>storagetype</replaceable>. Storage type is one of
+ plain, external, extended or main.)
+ </para>
+
<para>
The version-1 function call conventions make it possible to
return <quote>set</quote> results and implement trigger functions and
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.27 2002/01/16 20:29:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.28 2002/03/05 05:33:06 momjian Exp $
*
*
* INTERFACE ROUTINES
HeapTuple oldtup);
static Datum toast_save_datum(Relation rel, Datum value);
static varattrib *toast_fetch_datum(varattrib *attr);
+static varattrib *toast_fetch_datum_slice(varattrib *attr,
+ int32 sliceoffset, int32 length);
/* ----------
}
+/* ----------
+ * heap_tuple_untoast_attr_slice -
+ *
+ * Public entry point to get back part of a toasted value
+ * from compression or external storage.
+ * ----------
+ */
+varattrib *
+heap_tuple_untoast_attr_slice(varattrib *attr, int32 sliceoffset, int32 slicelength)
+{
+ varattrib *preslice;
+ varattrib *result;
+ int32 attrsize;
+
+ if (VARATT_IS_COMPRESSED(attr))
+ {
+ varattrib *tmp;
+
+ if (VARATT_IS_EXTERNAL(attr))
+ {
+ tmp = toast_fetch_datum(attr);
+ }
+ else
+ {
+ tmp = attr; /* compressed in main tuple */
+ }
+
+ preslice = (varattrib *) palloc(attr->va_content.va_external.va_rawsize
+ + VARHDRSZ);
+ VARATT_SIZEP(preslice) = attr->va_content.va_external.va_rawsize + VARHDRSZ;
+ pglz_decompress((PGLZ_Header *) tmp, VARATT_DATA(preslice));
+
+ if (tmp != attr)
+ pfree(tmp);
+ }
+ else
+ {
+ /* Plain value */
+ if (VARATT_IS_EXTERNAL(attr))
+ {
+ /* fast path */
+ return (toast_fetch_datum_slice(attr, sliceoffset, slicelength));
+ }
+ else
+ {
+ preslice = attr;
+ }
+ }
+
+ /* slicing of datum for compressed cases and plain value */
+
+ attrsize = VARSIZE(preslice) - VARHDRSZ;
+ if (sliceoffset >= attrsize)
+ {
+ sliceoffset = 0;
+ slicelength = 0;
+ }
+
+ if (((sliceoffset + slicelength) > attrsize) || slicelength < 0)
+ {
+ slicelength = attrsize - sliceoffset;
+ }
+
+ result = (varattrib *) palloc(slicelength + VARHDRSZ);
+ VARATT_SIZEP(result) = slicelength + VARHDRSZ;
+
+ memcpy(VARDATA(result), VARDATA(preslice) + sliceoffset, slicelength);
+
+ if (preslice != attr) pfree(preslice);
+
+ return result;
+}
+
+
/* ----------
* toast_raw_datum_size -
*
VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;
/*
- * Open the toast relation and it's index
+ * Open the toast relation and its index
*/
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
AccessShareLock);
return result;
}
+/* ----------
+ * toast_fetch_datum_slice -
+ *
+ * Reconstruct a segment of a varattrib from the chunks saved
+ * in the toast relation
+ * ----------
+ */
+static varattrib *
+toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
+{
+ Relation toastrel;
+ Relation toastidx;
+ ScanKeyData toastkey[3];
+ IndexScanDesc toastscan;
+ HeapTupleData toasttup;
+ HeapTuple ttup;
+ TupleDesc toasttupDesc;
+ RetrieveIndexResult indexRes;
+ Buffer buffer;
+
+ varattrib *result;
+ int32 attrsize;
+ int32 nscankeys;
+ int32 residx;
+ int32 nextidx;
+ int numchunks;
+ int startchunk;
+ int endchunk;
+ int32 startoffset;
+ int32 endoffset;
+ int totalchunks;
+ Pointer chunk;
+ bool isnull;
+ int32 chunksize;
+ int32 chcpystrt;
+ int32 chcpyend;
+
+ attrsize = attr->va_content.va_external.va_extsize;
+ totalchunks = ((attrsize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;
+
+ if (sliceoffset >= attrsize)
+ {
+ sliceoffset = 0;
+ length = 0;
+ }
+
+ if (((sliceoffset + length) > attrsize) || length < 0)
+ {
+ length = attrsize - sliceoffset;
+ }
+
+ result = (varattrib *) palloc(length + VARHDRSZ);
+ VARATT_SIZEP(result) = length + VARHDRSZ;
+
+ if (VARATT_IS_COMPRESSED(attr))
+ VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;
+
+ if (length == 0) return (result); /* Can save a lot of work at this point! */
+
+ startchunk = sliceoffset / TOAST_MAX_CHUNK_SIZE;
+ endchunk = (sliceoffset + length - 1) / TOAST_MAX_CHUNK_SIZE;
+ numchunks = (endchunk - startchunk ) + 1;
+
+ startoffset = sliceoffset % TOAST_MAX_CHUNK_SIZE;
+ endoffset = (sliceoffset + length - 1) % TOAST_MAX_CHUNK_SIZE;
+
+ /*
+ * Open the toast relation and it's index
+ */
+ toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
+ AccessShareLock);
+ toasttupDesc = toastrel->rd_att;
+ toastidx = index_open(toastrel->rd_rel->reltoastidxid);
+
+ /*
+ * Setup a scan key to fetch from the index. This is either two keys
+ * or three depending on the number of chunks.
+ */
+ ScanKeyEntryInitialize(&toastkey[0],
+ (bits16) 0,
+ (AttrNumber) 1,
+ (RegProcedure) F_OIDEQ,
+ ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
+ /*
+ * Now dependent on number of chunks:
+ */
+
+ if (numchunks == 1)
+ {
+ ScanKeyEntryInitialize(&toastkey[1],
+ (bits16) 0,
+ (AttrNumber) 2,
+ (RegProcedure) F_INT4EQ,
+ Int32GetDatum(startchunk));
+ nscankeys = 2;
+ }
+ else
+ {
+ ScanKeyEntryInitialize(&toastkey[1],
+ (bits16) 0,
+ (AttrNumber) 2,
+ (RegProcedure) F_INT4GE,
+ Int32GetDatum(startchunk));
+ ScanKeyEntryInitialize(&toastkey[2],
+ (bits16) 0,
+ (AttrNumber) 2,
+ (RegProcedure) F_INT4LE,
+ Int32GetDatum(endchunk));
+ nscankeys = 3;
+ }
+
+ /*
+ * Read the chunks by index
+ *
+ * The index is on (valueid, chunkidx) so they will come in order
+ */
+ nextidx = startchunk;
+ toastscan = index_beginscan(toastidx, false, nscankeys, &toastkey[0]);
+ while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
+ {
+ toasttup.t_self = indexRes->heap_iptr;
+ heap_fetch(toastrel, SnapshotToast, &toasttup, &buffer, toastscan);
+ pfree(indexRes);
+
+ if (toasttup.t_data == NULL)
+ continue;
+ ttup = &toasttup;
+
+ /*
+ * Have a chunk, extract the sequence number and the data
+ */
+ residx = DatumGetInt32(heap_getattr(ttup, 2, toasttupDesc, &isnull));
+ Assert(!isnull);
+ chunk = DatumGetPointer(heap_getattr(ttup, 3, toasttupDesc, &isnull));
+ Assert(!isnull);
+ chunksize = VARATT_SIZE(chunk) - VARHDRSZ;
+
+ /*
+ * Some checks on the data we've found
+ */
+ if ((residx != nextidx) || (residx > endchunk) || (residx < startchunk))
+ elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u",
+ residx, nextidx,
+ attr->va_content.va_external.va_valueid);
+ if (residx < totalchunks - 1)
+ {
+ if (chunksize != TOAST_MAX_CHUNK_SIZE)
+ elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",
+ chunksize, residx,
+ attr->va_content.va_external.va_valueid);
+ }
+ else
+ {
+ if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != attrsize)
+ elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",
+ chunksize, residx,
+ attr->va_content.va_external.va_valueid);
+ }
+
+ /*
+ * Copy the data into proper place in our result
+ */
+ chcpystrt = 0;
+ chcpyend = chunksize - 1;
+ if (residx == startchunk) chcpystrt = startoffset;
+ if (residx == endchunk) chcpyend = endoffset;
+
+ memcpy(((char *) VARATT_DATA(result)) +
+ (residx * TOAST_MAX_CHUNK_SIZE - sliceoffset) +chcpystrt,
+ VARATT_DATA(chunk) + chcpystrt,
+ (chcpyend - chcpystrt) + 1);
+
+ ReleaseBuffer(buffer);
+ nextidx++;
+ }
+
+ /*
+ * Final checks that we successfully fetched the datum
+ */
+ if ( nextidx != (endchunk + 1))
+ elog(ERROR, "missing chunk number %d for toast value %u",
+ nextidx,
+ attr->va_content.va_external.va_valueid);
+
+ /*
+ * End scan and close relations
+ */
+ index_endscan(toastscan);
+ index_close(toastidx);
+ heap_close(toastrel, AccessShareLock);
+
+ return result;
+}
+
#endif /* TUPLE_TOASTER_ACTIVE */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.157 2002/03/02 21:39:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.158 2002/03/05 05:33:08 momjian Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
/*
- * ALTER TABLE ALTER COLUMN SET STATISTICS
+ * ALTER TABLE ALTER COLUMN SET STATISTICS / STORAGE
*/
void
-AlterTableAlterColumnStatistics(const char *relationName,
+AlterTableAlterColumnFlags(const char *relationName,
bool inh, const char *colName,
- Node *statsTarget)
+ Node *flagValue, const char *flagType)
{
Relation rel;
Oid myrelid;
- int newtarget;
+ int newtarget = 1;
+ char newstorage = 'x';
+ char *storagemode;
Relation attrelation;
HeapTuple tuple;
- /* we allow this on system tables */
+ /* we allow statistics case for system tables */
+
+ if (*flagType =='M' && !allowSystemTableMods && IsSystemRelationName(relationName))
+ elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
+ relationName);
+
#ifndef NO_SECURITY
if (!pg_ownercheck(GetUserId(), relationName, RELNAME))
elog(ERROR, "ALTER TABLE: permission denied");
myrelid = RelationGetRelid(rel);
heap_close(rel, NoLock); /* close rel, but keep lock! */
+
+ /*
+ * Check the supplied parameters before anything else
+ */
+ if (*flagType == 'S') /*
+ * STATISTICS
+ */
+ {
+ Assert(IsA(flagValue, Integer));
+ newtarget = intVal(flagValue);
+
+ /*
+ * Limit target to sane range (should we raise an error instead?)
+ */
+ if (newtarget < 0)
+ newtarget = 0;
+ else if (newtarget > 1000)
+ newtarget = 1000;
+ }
+ else if (*flagType == 'M') /*
+ * STORAGE
+ */
+ {
+ Assert(IsA(flagValue, Value));
+
+ storagemode = strVal(flagValue);
+ if (strcasecmp(storagemode, "plain") == 0)
+ newstorage = 'p';
+ else if (strcasecmp(storagemode, "external") == 0)
+ newstorage = 'e';
+ else if (strcasecmp(storagemode, "extended") == 0)
+ newstorage = 'x';
+ else if (strcasecmp(storagemode, "main") == 0)
+ newstorage = 'm';
+ else
+ elog(ERROR, "ALTER TABLE: \"%s\" storage not recognized",
+ storagemode);
+ }
+ else
+ {
+ elog(ERROR, "ALTER TABLE: Invalid column flag: %c",
+ (int) *flagType);
+ }
+
/*
* Propagate to children if desired
*/
if (childrelid == myrelid)
continue;
rel = heap_open(childrelid, AccessExclusiveLock);
- AlterTableAlterColumnStatistics(RelationGetRelationName(rel),
- false, colName, statsTarget);
+ AlterTableAlterColumnFlags(RelationGetRelationName(rel),
+ false, colName, flagValue, flagType);
heap_close(rel, AccessExclusiveLock);
}
}
/* -= now do the thing on this relation =- */
- Assert(IsA(statsTarget, Integer));
- newtarget = intVal(statsTarget);
-
- /* Limit target to sane range (should we raise an error instead?) */
- if (newtarget < 0)
- newtarget = 0;
- else if (newtarget > 1000)
- newtarget = 1000;
-
attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
tuple = SearchSysCacheCopy(ATTNAME,
if (((Form_pg_attribute) GETSTRUCT(tuple))->attnum < 0)
elog(ERROR, "ALTER TABLE: cannot change system attribute \"%s\"",
colName);
-
- ((Form_pg_attribute) GETSTRUCT(tuple))->attstattarget = newtarget;
-
+ /*
+ * Now change the appropriate field
+ */
+ if (*flagType == 'S')
+ ((Form_pg_attribute) GETSTRUCT(tuple))->attstattarget = newtarget;
+ else
+ {
+ if ((newstorage == 'p') ||
+ (((Form_pg_attribute) GETSTRUCT(tuple))->attlen == -1))
+ ((Form_pg_attribute) GETSTRUCT(tuple))->attstorage = newstorage;
+ else
+ {
+ elog(ERROR,
+ "ALTER TABLE: Fixed-length columns can only have storage \"plain\"");
+ }
+ }
simple_heap_update(attrelation, &tuple->t_self, tuple);
/* keep system catalog indices current */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.283 2002/03/02 21:39:27 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.284 2002/03/05 05:33:14 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
OFFSET, OIDS, OPERATOR, OWNER, PASSWORD, PROCEDURAL,
REINDEX, RENAME, RESET, RETURNS, ROW, RULE,
SEQUENCE, SETOF, SHARE, SHOW, START, STATEMENT,
- STATISTICS, STDIN, STDOUT, SYSID,
+ STATISTICS, STDIN, STDOUT, STORAGE, SYSID,
TEMP, TEMPLATE, TOAST, TRUNCATE, TRUSTED,
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
n->def = (Node *) makeInteger($9);
$$ = (Node *)n;
}
+/* ALTER TABLE <relation> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
+ | ALTER TABLE relation_expr ALTER opt_column ColId SET STORAGE ColId
+ {
+ AlterTableStmt *n = makeNode(AlterTableStmt);
+ n->subtype = 'M';
+ n->relname = $3->relname;
+ n->inhOpt = $3->inhOpt;
+ n->name = $6;
+ n->def = (Node *) makeString($9);
+ $$ = (Node *)n;
+ }
/* ALTER TABLE <relation> DROP [COLUMN] <colname> {RESTRICT|CASCADE} */
| ALTER TABLE relation_expr DROP opt_column ColId drop_behavior
{
| STATISTICS { $$ = "statistics"; }
| STDIN { $$ = "stdin"; }
| STDOUT { $$ = "stdout"; }
+ | STORAGE { $$ = "storage"; }
| SYSID { $$ = "sysid"; }
| TEMP { $$ = "temp"; }
| TEMPLATE { $$ = "template"; }
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.100 2002/02/18 23:11:18 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.101 2002/03/05 05:33:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
{"statistics", STATISTICS},
{"stdin", STDIN},
{"stdout", STDOUT},
+ {"storage", STORAGE},
{"substring", SUBSTRING},
{"sysid", SYSID},
{"table", TABLE},
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.128 2002/03/01 22:45:14 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.129 2002/03/05 05:33:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
stmt->def);
break;
case 'S': /* ALTER COLUMN STATISTICS */
- AlterTableAlterColumnStatistics(stmt->relname,
+ case 'M': /* ALTER COLUMN STORAGE */
+ AlterTableAlterColumnFlags(stmt->relname,
interpretInhOption(stmt->inhOpt),
stmt->name,
- stmt->def);
+ stmt->def,
+ &(stmt->subtype));
break;
case 'D': /* DROP COLUMN */
AlterTableDropColumn(stmt->relname,
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.78 2001/11/19 19:15:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.79 2002/03/05 05:33:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
* Changed behavior if starting position is less than one to conform to SQL92 behavior.
* Formerly returned the entire string; now returns a portion.
* - Thomas Lockhart 1998-12-10
+ * Now uses faster TOAST-slicing interface
+ * - John Gray 2002-02-22
*/
Datum
text_substr(PG_FUNCTION_ARGS)
{
- text *string = PG_GETARG_TEXT_P(0);
+ text *string;
int32 m = PG_GETARG_INT32(1);
int32 n = PG_GETARG_INT32(2);
- text *ret;
- int len;
-
+ int32 sm;
+ int32 sn;
+ int eml = 1;
#ifdef MULTIBYTE
int i;
+ int len;
+ text *ret;
char *p;
-#endif
-
- len = VARSIZE(string) - VARHDRSZ;
-#ifdef MULTIBYTE
- len = pg_mbstrlen_with_len(VARDATA(string), len);
-#endif
-
- /* starting position after the end of the string? */
- if (m > len)
- {
- m = 1;
- n = 0;
- }
+#endif
/*
* starting position before the start of the string? then offset into
* the string per SQL92 spec...
*/
- else if (m < 1)
+ if (m < 1)
{
n += (m - 1);
m = 1;
}
+ /* Check for m > octet length is made in TOAST access routine */
/* m will now become a zero-based starting position */
+ sm = m - 1;
+ sn = n;
+
+#ifdef MULTIBYTE
+ eml = pg_database_encoding_max_length ();
+
+ if (eml > 1)
+ {
+ sm = 0;
+ sn = (m + n) * eml + 3; /* +3 to avoid mb characters overhanging slice end */
+ }
+#endif
+
+ string = PG_GETARG_TEXT_P_SLICE (0, sm, sn);
+
+ if (eml == 1)
+ {
+ PG_RETURN_TEXT_P (string);
+ }
+#ifndef MULTIBYTE
+ PG_RETURN_NULL(); /* notreached: suppress compiler warning */
+#endif
+#ifdef MULTIBYTE
+ len = pg_mbstrlen_with_len (VARDATA (string), sn - 3);
+
+ if (m > len)
+ {
+ m = 1;
+ n = 0;
+ }
m--;
if (((m + n) > len) || (n < 0))
n = (len - m);
-#ifdef MULTIBYTE
p = VARDATA(string);
for (i = 0; i < m; i++)
p += pg_mblen(p);
for (i = 0; i < n; i++)
p += pg_mblen(p);
n = p - (VARDATA(string) + m);
-#endif
ret = (text *) palloc(VARHDRSZ + n);
VARATT_SIZEP(ret) = VARHDRSZ + n;
memcpy(VARDATA(ret), VARDATA(string) + m, n);
PG_RETURN_TEXT_P(ret);
+#endif
}
/*
Datum
bytea_substr(PG_FUNCTION_ARGS)
{
- bytea *string = PG_GETARG_BYTEA_P(0);
int32 m = PG_GETARG_INT32(1);
int32 n = PG_GETARG_INT32(2);
- bytea *ret;
- int len;
-
- len = VARSIZE(string) - VARHDRSZ;
-
- /* starting position after the end of the string? */
- if (m > len)
- {
- m = 1;
- n = 0;
- }
/*
* starting position before the start of the string? then offset into
* the string per SQL92 spec...
*/
- else if (m < 1)
+ if (m < 1)
{
n += (m - 1);
m = 1;
/* m will now become a zero-based starting position */
m--;
- if (((m + n) > len) || (n < 0))
- n = (len - m);
-
- ret = (bytea *) palloc(VARHDRSZ + n);
- VARATT_SIZEP(ret) = VARHDRSZ + n;
-
- memcpy(VARDATA(ret), VARDATA(string) + m, n);
- PG_RETURN_BYTEA_P(ret);
+ PG_RETURN_BYTEA_P(PG_GETARG_BYTEA_P_SLICE (0, m, n));
}
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.57 2001/11/05 17:46:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.58 2002/03/05 05:33:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
return result;
}
}
+
+struct varlena *
+pg_detoast_datum_slice(struct varlena * datum, int32 first, int32 count)
+{
+ /* Only get the specified portion from the toast rel */
+ return (struct varlena *) heap_tuple_untoast_attr_slice((varattrib *) datum, first, count);
+}
*
* Copyright (c) 2000, PostgreSQL Development Team
*
- * $Id: tuptoaster.h,v 1.13 2001/11/05 17:46:31 momjian Exp $
+ * $Id: tuptoaster.h,v 1.14 2002/03/05 05:33:25 momjian Exp $
*
*-------------------------------------------------------------------------
*/
*/
extern varattrib *heap_tuple_untoast_attr(varattrib *attr);
+/* ----------
+ * heap_tuple_untoast_attr_slice() -
+ *
+ * Fetches only the specified portion of an attribute.
+ * (Handles all cases for attribute storage)
+ * ----------
+ */
+extern varattrib *heap_tuple_untoast_attr_slice(varattrib *attr,
+ int32 sliceoffset,
+ int32 slicelength);
+
/* ----------
* toast_compress_datum -
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: command.h,v 1.32 2002/02/26 22:47:10 tgl Exp $
+ * $Id: command.h,v 1.33 2002/03/05 05:33:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
bool inh, const char *colName,
Node *newDefault);
-extern void AlterTableAlterColumnStatistics(const char *relationName,
+extern void AlterTableAlterColumnFlags(const char *relationName,
bool inh, const char *colName,
- Node *statsTarget);
+ Node *flagValue, const char *flagType);
extern void AlterTableDropColumn(const char *relationName,
bool inh, const char *colName,
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: fmgr.h,v 1.18 2001/11/05 17:46:31 momjian Exp $
+ * $Id: fmgr.h,v 1.19 2002/03/05 05:33:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
*/
extern struct varlena *pg_detoast_datum(struct varlena * datum);
extern struct varlena *pg_detoast_datum_copy(struct varlena * datum);
+extern struct varlena *pg_detoast_datum_slice(struct varlena * datum,
+ int32 first, int32 count);
#define PG_DETOAST_DATUM(datum) \
pg_detoast_datum((struct varlena *) DatumGetPointer(datum))
#define PG_DETOAST_DATUM_COPY(datum) \
pg_detoast_datum_copy((struct varlena *) DatumGetPointer(datum))
+#define PG_DETOAST_DATUM_SLICE(datum,f,c) \
+ pg_detoast_datum_slice((struct varlena *) DatumGetPointer(datum), \
+ (int32) f, (int32) c)
/*
* Support for cleaning up detoasted copies of inputs. This must only
#define DatumGetTextPCopy(X) ((text *) PG_DETOAST_DATUM_COPY(X))
#define DatumGetBpCharPCopy(X) ((BpChar *) PG_DETOAST_DATUM_COPY(X))
#define DatumGetVarCharPCopy(X) ((VarChar *) PG_DETOAST_DATUM_COPY(X))
+/* Variants which return n bytes starting at pos. m */
+#define DatumGetByteaPSlice(X,m,n) ((bytea *) PG_DETOAST_DATUM_SLICE(X,m,n))
+#define DatumGetTextPSlice(X,m,n) ((text *) PG_DETOAST_DATUM_SLICE(X,m,n))
+#define DatumGetBpCharPSlice(X,m,n) ((BpChar *) PG_DETOAST_DATUM_SLICE(X,m,n))
+#define DatumGetVarCharPSlice(X,m,n) ((VarChar *) PG_DETOAST_DATUM_SLICE(X,m,n))
/* GETARG macros for varlena types will typically look like this: */
#define PG_GETARG_BYTEA_P(n) DatumGetByteaP(PG_GETARG_DATUM(n))
#define PG_GETARG_TEXT_P(n) DatumGetTextP(PG_GETARG_DATUM(n))
#define PG_GETARG_TEXT_P_COPY(n) DatumGetTextPCopy(PG_GETARG_DATUM(n))
#define PG_GETARG_BPCHAR_P_COPY(n) DatumGetBpCharPCopy(PG_GETARG_DATUM(n))
#define PG_GETARG_VARCHAR_P_COPY(n) DatumGetVarCharPCopy(PG_GETARG_DATUM(n))
+/* And a b-byte slice from position a -also OK to write */
+#define PG_GETARG_BYTEA_P_SLICE(n,a,b) DatumGetByteaPSlice(PG_GETARG_DATUM(n),a,b)
+#define PG_GETARG_TEXT_P_SLICE(n,a,b) DatumGetTextPSlice(PG_GETARG_DATUM(n),a,b)
+#define PG_GETARG_BPCHAR_P_SLICE(n,a,b) DatumGetBpCharPSlice(PG_GETARG_DATUM(n),a,b)
+#define PG_GETARG_VARCHAR_P_SLICE(n,a,b) DatumGetVarCharPSlice(PG_GETARG_DATUM(n),a,b)
/* To return a NULL do this: */
#define PG_RETURN_NULL() \
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.155 2002/03/01 22:45:18 petere Exp $
+ * $Id: parsenodes.h,v 1.156 2002/03/05 05:33:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
* A = add column
* T = alter column default
* S = alter column statistics
+ * M = alter column storage
* D = drop column
* C = add constraint
* X = drop constraint