Instead of storing pg_statistic stavalues entries as text strings, store

them as arrays of the internal datatype.  This requires treating the
stavalues columns as 'anyarray' rather than 'text[]', which is not 100%
kosher but seems to work fine for the purposes we need for pg_statistic.
Perhaps in the future 'anyarray' will be allowed more generally.
This commit is contained in:
Tom Lane 2003-03-23 05:14:37 +00:00
parent efeffae245
commit 8d9e025e7f
8 changed files with 67 additions and 88 deletions

View File

@ -1,6 +1,6 @@
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.66 2003/02/22 00:45:03 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.67 2003/03/23 05:14:36 tgl Exp $
-->
<chapter id="catalogs">
@ -3050,12 +3050,14 @@
<row>
<entry>stavaluesN</entry>
<entry><type>text[]</type></entry>
<entry><type>anyarray</type></entry>
<entry></entry>
<entry>Column data values of the appropriate kind for the Nth
<quote>slot</quote>, or NULL if the slot kind does not store any data values.
For data-type independence, all column data values are converted
to external textual form and stored as TEXT datums.
<quote>slot</quote>, or NULL if the slot kind does not store any data
values.
Each array's element values are actually of the specific column's
datatype, so there is no way to define these columns' type more
specifically than <quote>anyarray</>.
</entry>
</row>
</tbody>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.240 2003/03/20 03:34:55 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.241 2003/03/23 05:14:36 tgl Exp $
*
*
* INTERFACE ROUTINES
@ -421,8 +421,12 @@ CheckAttributeType(const char *attname, Oid atttypid)
"\n\tProceeding with relation creation anyway",
attname);
else if (att_typtype == 'p')
elog(ERROR, "Attribute \"%s\" has pseudo-type %s",
attname, format_type_be(atttypid));
{
/* Special hack for pg_statistic: allow ANYARRAY during initdb */
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
elog(ERROR, "Attribute \"%s\" has pseudo-type %s",
attname, format_type_be(atttypid));
}
else if (att_typtype == 'c')
{
Oid typrelid = get_typ_typrelid(atttypid);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.51 2002/11/29 21:39:10 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.52 2003/03/23 05:14:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1694,7 +1694,6 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
for (attno = 0; attno < natts; attno++)
{
VacAttrStats *stats = vacattrstats[attno];
FmgrInfo out_function;
HeapTuple stup,
oldtup;
int i,
@ -1708,8 +1707,6 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
if (!stats->stats_valid)
continue;
fmgr_info(stats->attrtype->typoutput, &out_function);
/*
* Construct a new pg_statistic tuple
*/
@ -1758,33 +1755,16 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
}
for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
{
int ntxt = stats->numvalues[k];
if (ntxt > 0)
if (stats->numvalues[k] > 0)
{
Datum *txtdatums = (Datum *) palloc(ntxt * sizeof(Datum));
ArrayType *arry;
for (n = 0; n < ntxt; n++)
{
/*
* Convert data values to a text string to be inserted
* into the text array.
*/
Datum stringdatum;
stringdatum =
FunctionCall3(&out_function,
stats->stavalues[k][n],
ObjectIdGetDatum(stats->attrtype->typelem),
Int32GetDatum(stats->attr->atttypmod));
txtdatums[n] = DirectFunctionCall1(textin, stringdatum);
pfree(DatumGetPointer(stringdatum));
}
/* XXX knows more than it should about type text: */
arry = construct_array(txtdatums, ntxt,
TEXTOID,
-1, false, 'i');
arry = construct_array(stats->stavalues[k],
stats->numvalues[k],
stats->attr->atttypid,
stats->attrtype->typlen,
stats->attrtype->typbyval,
stats->attrtype->typalign);
values[i++] = PointerGetDatum(arry); /* stavaluesN */
}
else

View File

@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.133 2003/03/23 01:49:02 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.134 2003/03/23 05:14:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1826,16 +1826,11 @@ mergejoinscansel(Query *root, Node *clause,
/*
* Now skip any binary-compatible relabeling; there can only be one level
* since constant-expression folder eliminates adjacent RelabelTypes.
*
* XXX can't enable this quite yet, it exposes regproc uncertainty problems
* in regression tests. FIXME soon.
*/
#if 0
if (IsA(left, RelabelType))
left = (Var *) ((RelabelType *) left)->arg;
if (IsA(right, RelabelType))
right = (Var *) ((RelabelType *) right)->arg;
#endif
/* Can't do anything if inputs are not Vars */
if (!IsA(left, Var) ||

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.90 2003/02/03 21:15:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.91 2003/03/23 05:14:36 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
@ -28,6 +28,7 @@
#include "nodes/makefuncs.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@ -1387,8 +1388,7 @@ get_attstatsslot(HeapTuple statstuple,
ArrayType *statarray;
int narrayelem;
HeapTuple typeTuple;
FmgrInfo inputproc;
Oid typelem;
Form_pg_type typeForm;
for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
{
@ -1408,48 +1408,40 @@ get_attstatsslot(HeapTuple statstuple,
elog(ERROR, "get_attstatsslot: stavalues is null");
statarray = DatumGetArrayTypeP(val);
/*
* Do initial examination of the array. This produces a list of
* text Datums --- ie, pointers into the text array value.
*/
deconstruct_array(statarray,
TEXTOID, -1, false, 'i',
values, nvalues);
narrayelem = *nvalues;
/*
* We now need to replace each text Datum by its internal
* equivalent.
*
* Get the type input proc and typelem for the column datatype.
*/
/* Need to get info about the array element type */
typeTuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(atttype),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "get_attstatsslot: Cache lookup failed for type %u",
atttype);
fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);
typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
ReleaseSysCache(typeTuple);
typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
/* Deconstruct array into Datum elements */
deconstruct_array(statarray,
atttype,
typeForm->typlen,
typeForm->typbyval,
typeForm->typalign,
values, nvalues);
/*
* Do the conversions. The palloc'd array of Datums is reused in
* place.
* If the element type is pass-by-reference, we now have a bunch
* of Datums that are pointers into the syscache value. Copy them
* to avoid problems if syscache decides to drop the entry.
*/
for (j = 0; j < narrayelem; j++)
if (!typeForm->typbyval)
{
char *strval;
strval = DatumGetCString(DirectFunctionCall1(textout,
(*values)[j]));
(*values)[j] = FunctionCall3(&inputproc,
CStringGetDatum(strval),
ObjectIdGetDatum(typelem),
Int32GetDatum(atttypmod));
pfree(strval);
for (j = 0; j < *nvalues; j++)
{
(*values)[j] = datumCopy((*values)[j],
typeForm->typbyval,
typeForm->typlen);
}
}
ReleaseSysCache(typeTuple);
/*
* Free statarray if it's a detoasted copy.
*/

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.182 2003/03/21 01:58:04 tgl Exp $
* $Id: catversion.h,v 1.183 2003/03/23 05:14:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200303201
#define CATALOG_VERSION_NO 200303221
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_statistic.h,v 1.19 2003/03/10 22:28:21 tgl Exp $
* $Id: pg_statistic.h,v 1.20 2003/03/23 05:14:37 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -26,6 +26,12 @@
* ----------------
*/
/*
* Keep C compiler happy with anyarray, below. This will need to go elsewhere
* if we ever use anyarray for more than pg_statistic.
*/
typedef struct varlena anyarray;
/* ----------------
* pg_statistic definition. cpp turns this into
* typedef struct FormData_pg_statistic
@ -109,14 +115,14 @@ CATALOG(pg_statistic) BKI_WITHOUT_OIDS
float4 stanumbers4[1];
/*
* Values in these text arrays are external representations of values
* of the column's data type. To re-create the actual Datum, do
* datatypein(textout(arrayelement)).
* Values in these arrays are values of the column's data type. We
* presently have to cheat quite a bit to allow polymorphic arrays
* of this kind, but perhaps someday it'll be a less bogus facility.
*/
text stavalues1[1];
text stavalues2[1];
text stavalues3[1];
text stavalues4[1];
anyarray stavalues1;
anyarray stavalues2;
anyarray stavalues3;
anyarray stavalues4;
} FormData_pg_statistic;
#define STATISTIC_NUM_SLOTS 4

View File

@ -1267,8 +1267,8 @@ drop table cchild;
-- Check that ruleutils are working
--
SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
viewname | definition
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
viewname | definition
--------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
pg_locks | SELECT l.relation, l."database", l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(relation oid, "database" oid, "transaction" xid, pid integer, "mode" text, granted boolean);
@ -1291,7 +1291,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
pg_statio_user_indexes | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE ((pg_statio_all_indexes.schemaname <> 'pg_catalog'::name) AND (pg_statio_all_indexes.schemaname <> 'pg_toast'::name));
pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE ((pg_statio_all_sequences.schemaname <> 'pg_catalog'::name) AND (pg_statio_all_sequences.schemaname <> 'pg_toast'::name));
pg_statio_user_tables | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE ((pg_statio_all_tables.schemaname <> 'pg_catalog'::name) AND (pg_statio_all_tables.schemaname <> 'pg_toast'::name));
pg_stats | SELECT nspname AS schemaname, relname AS tablename, attname, stanullfrac AS null_frac, stawidth AS avg_width, stadistinct AS n_distinct, CASE WHEN (1 = stakind1) THEN stavalues1 WHEN (1 = stakind2) THEN stavalues2 WHEN (1 = stakind3) THEN stavalues3 WHEN (1 = stakind4) THEN stavalues4 ELSE NULL::text[] END AS most_common_vals, CASE WHEN (1 = stakind1) THEN stanumbers1 WHEN (1 = stakind2) THEN stanumbers2 WHEN (1 = stakind3) THEN stanumbers3 WHEN (1 = stakind4) THEN stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (2 = stakind1) THEN stavalues1 WHEN (2 = stakind2) THEN stavalues2 WHEN (2 = stakind3) THEN stavalues3 WHEN (2 = stakind4) THEN stavalues4 ELSE NULL::text[] END AS histogram_bounds, CASE WHEN (3 = stakind1) THEN stanumbers1[1] WHEN (3 = stakind2) THEN stanumbers2[1] WHEN (3 = stakind3) THEN stanumbers3[1] WHEN (3 = stakind4) THEN stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE has_table_privilege(c.oid, 'select'::text);
pg_stats | SELECT nspname AS schemaname, relname AS tablename, attname, stanullfrac AS null_frac, stawidth AS avg_width, stadistinct AS n_distinct, CASE WHEN (1 = stakind1) THEN stavalues1 WHEN (1 = stakind2) THEN stavalues2 WHEN (1 = stakind3) THEN stavalues3 WHEN (1 = stakind4) THEN stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (1 = stakind1) THEN stanumbers1 WHEN (1 = stakind2) THEN stanumbers2 WHEN (1 = stakind3) THEN stanumbers3 WHEN (1 = stakind4) THEN stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (2 = stakind1) THEN stavalues1 WHEN (2 = stakind2) THEN stavalues2 WHEN (2 = stakind3) THEN stavalues3 WHEN (2 = stakind4) THEN stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (3 = stakind1) THEN stanumbers1[1] WHEN (3 = stakind2) THEN stanumbers2[1] WHEN (3 = stakind3) THEN stanumbers3[1] WHEN (3 = stakind4) THEN stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE has_table_privilege(c.oid, 'select'::text);
pg_tables | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, (c.reltriggers > 0) AS hastriggers FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") OR (c.relkind = 's'::"char"));
pg_user | SELECT pg_shadow.usename, pg_shadow.usesysid, pg_shadow.usecreatedb, pg_shadow.usesuper, pg_shadow.usecatupd, '********'::text AS passwd, pg_shadow.valuntil, pg_shadow.useconfig FROM pg_shadow;
pg_views | SELECT n.nspname AS schemaname, c.relname AS viewname, pg_get_userbyid(c.relowner) AS viewowner, pg_get_viewdef(c.oid) AS definition FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'v'::"char");