diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index c2d62822e5..4baae556b3 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ @@ -3524,6 +3524,13 @@ Output conversion function (binary format), or 0 if none + + typanalyze + regproc + pg_proc.oid + Custom ANALYZE function, or 0 to use the standard function + + typalign char diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index dfb7ab1510..ba63f4378b 100644 --- a/doc/src/sgml/ref/create_type.sgml +++ b/doc/src/sgml/ref/create_type.sgml @@ -1,5 +1,5 @@ @@ -28,6 +28,7 @@ CREATE TYPE name ( OUTPUT = output_function [ , RECEIVE = receive_function ] [ , SEND = send_function ] + [ , ANALYZE = analyze_function ] [ , INTERNALLENGTH = { internallength | VARIABLE } ] [ , PASSEDBYVALUE ] [ , ALIGNMENT = alignment ] @@ -83,8 +84,9 @@ CREATE TYPE name ( input_function and output_function are required, while the functions - receive_function and - send_function + receive_function, + send_function and + analyze_function are optional. Generally these functions have to be coded in C or another low-level language. @@ -152,6 +154,19 @@ CREATE TYPE name ( shell entry with a complete type definition, and the new type can be used. + + The optional analyze_function + performs type-specific statistics collection for columns of the data type. + By default, ANALYZE will attempt to gather statistics using + the type's equals and less-than operators, if there + is a default b-tree operator class for the type. For non-scalar types + this behavior is likely to be unsuitable, so it can be overridden by + specifying a custom analysis function. The analysis function must be + declared to take a single argument of type internal, and return + a boolean result. The detailed API for analysis functions appears + in src/include/commands/vacuum.h. + + While the details of the new type's internal representation are only known to the I/O functions and other functions you create to work with @@ -341,6 +356,16 @@ CREATE TYPE name ( + + analyze_function + + + The name of a function that performs statistical analysis for the + data type. + + + + internallength diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 905aa5b0b2..63595962e4 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.258 2004/02/10 01:55:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.259 2004/02/12 23:41:02 tgl Exp $ * * * INTERFACE ROUTINES @@ -689,6 +689,7 @@ AddNewRelationType(const char *typeName, F_RECORD_OUT, /* output procedure */ F_RECORD_RECV, /* receive procedure */ F_RECORD_SEND, /* send procedure */ + InvalidOid, /* analyze procedure - default */ InvalidOid, /* array element type - irrelevant */ InvalidOid, /* domain base type - irrelevant */ NULL, /* default type value - none */ diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 802b01f759..efd2f61747 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.92 2004/01/07 18:56:25 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.93 2004/02/12 23:41:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -86,6 +86,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace) values[i++] = ObjectIdGetDatum(InvalidOid); /* typoutput */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */ + values[i++] = ObjectIdGetDatum(InvalidOid); /* typanalyze */ values[i++] = CharGetDatum('i'); /* typalign */ values[i++] = CharGetDatum('p'); /* typstorage */ values[i++] = BoolGetDatum(false); /* typnotnull */ @@ -121,6 +122,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace) InvalidOid, InvalidOid, InvalidOid, + InvalidOid, NULL, false); @@ -157,6 +159,7 @@ TypeCreate(const char *typeName, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, + Oid analyzeProcedure, Oid elementType, Oid baseType, const char *defaultTypeValue, /* human readable rep */ @@ -236,6 +239,7 @@ TypeCreate(const char *typeName, values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */ values[i++] = ObjectIdGetDatum(receiveProcedure); /* typreceive */ values[i++] = ObjectIdGetDatum(sendProcedure); /* typsend */ + values[i++] = ObjectIdGetDatum(analyzeProcedure); /* typanalyze */ values[i++] = CharGetDatum(alignment); /* typalign */ values[i++] = CharGetDatum(storage); /* typstorage */ values[i++] = BoolGetDatum(typeNotNull); /* typnotnull */ @@ -332,6 +336,7 @@ TypeCreate(const char *typeName, outputProcedure, receiveProcedure, sendProcedure, + analyzeProcedure, elementType, baseType, (defaultTypeBin ? @@ -366,6 +371,7 @@ GenerateTypeDependencies(Oid typeNamespace, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, + Oid analyzeProcedure, Oid elementType, Oid baseType, Node *defaultExpr, @@ -425,6 +431,14 @@ GenerateTypeDependencies(Oid typeNamespace, recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } + if (OidIsValid(analyzeProcedure)) + { + referenced.classId = RelOid_pg_proc; + referenced.objectId = analyzeProcedure; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + /* * If the type is a rowtype for a relation, mark it as internally * dependent on the relation, *unless* it is a stand-alone composite diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 0c713b3ca6..eb8716b488 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * analyze.c - * the postgres statistics generator + * the Postgres statistics generator * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.67 2004/02/10 03:42:43 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.68 2004/02/12 23:41:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,8 +23,6 @@ #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_operator.h" -#include "catalog/pg_statistic.h" -#include "catalog/pg_type.h" #include "commands/vacuum.h" #include "miscadmin.h" #include "parser/parse_oper.h" @@ -38,91 +36,13 @@ #include "utils/tuplesort.h" -/* - * Analysis algorithms supported - */ -typedef enum -{ - ALG_MINIMAL = 1, /* Compute only most-common-values */ - ALG_SCALAR /* Compute MCV, histogram, sort - * correlation */ -} AlgCode; - -/* - * To avoid consuming too much memory during analysis and/or too much space - * in the resulting pg_statistic rows, we ignore varlena datums that are wider - * than WIDTH_THRESHOLD (after detoasting!). This is legitimate for MCV - * and distinct-value calculations since a wide value is unlikely to be - * duplicated at all, much less be a most-common value. For the same reason, - * ignoring wide values will not affect our estimates of histogram bin - * boundaries very much. - */ -#define WIDTH_THRESHOLD 1024 - -/* - * We build one of these structs for each attribute (column) that is to be - * analyzed. The struct and subsidiary data are in anl_context, - * so they live until the end of the ANALYZE operation. - */ -typedef struct -{ - /* These fields are set up by examine_attribute */ - int attnum; /* attribute number */ - AlgCode algcode; /* Which algorithm to use for this column */ - int minrows; /* Minimum # of rows wanted for stats */ - Form_pg_attribute attr; /* copy of pg_attribute row for column */ - Form_pg_type attrtype; /* copy of pg_type row for column */ - Oid eqopr; /* '=' operator for datatype, if any */ - Oid eqfunc; /* and associated function */ - Oid ltopr; /* '<' operator for datatype, if any */ - - /* - * These fields are filled in by the actual statistics-gathering - * routine - */ - bool stats_valid; - float4 stanullfrac; /* fraction of entries that are NULL */ - int4 stawidth; /* average width */ - float4 stadistinct; /* # distinct values */ - int2 stakind[STATISTIC_NUM_SLOTS]; - Oid staop[STATISTIC_NUM_SLOTS]; - int numnumbers[STATISTIC_NUM_SLOTS]; - float4 *stanumbers[STATISTIC_NUM_SLOTS]; - int numvalues[STATISTIC_NUM_SLOTS]; - Datum *stavalues[STATISTIC_NUM_SLOTS]; -} VacAttrStats; - - -typedef struct -{ - Datum value; /* a data value */ - int tupno; /* position index for tuple it came from */ -} ScalarItem; - -typedef struct -{ - int count; /* # of duplicates */ - int first; /* values[] index of first occurrence */ -} ScalarMCVItem; - - -#define swapInt(a,b) do {int _tmp; _tmp=a; a=b; b=_tmp;} while(0) -#define swapDatum(a,b) do {Datum _tmp; _tmp=a; a=b; b=_tmp;} while(0) - - /* Default statistics target (GUC parameter) */ int default_statistics_target = 10; - static int elevel = -1; static MemoryContext anl_context = NULL; -/* context information for compare_scalars() */ -static FmgrInfo *datumCmpFn; -static SortFunctionKind datumCmpFnKind; -static int *datumCmpTupnoLink; - static VacAttrStats *examine_attribute(Relation onerel, int attnum); static int acquire_sample_rows(Relation onerel, HeapTuple *rows, @@ -131,16 +51,10 @@ static double random_fract(void); static double init_selection_state(int n); static double select_next_random_record(double t, int n, double *stateptr); static int compare_rows(const void *a, const void *b); -static int compare_scalars(const void *a, const void *b); -static int compare_mcvs(const void *a, const void *b); -static void compute_minimal_stats(VacAttrStats *stats, - TupleDesc tupDesc, double totalrows, - HeapTuple *rows, int numrows); -static void compute_scalar_stats(VacAttrStats *stats, - TupleDesc tupDesc, double totalrows, - HeapTuple *rows, int numrows); static void update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats); +static bool std_typanalyze(VacAttrStats *stats); + /* * analyze_rel() -- analyze one relation @@ -345,19 +259,12 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) old_context = MemoryContextSwitchTo(col_context); for (i = 0; i < attr_cnt; i++) { - switch (vacattrstats[i]->algcode) - { - case ALG_MINIMAL: - compute_minimal_stats(vacattrstats[i], - onerel->rd_att, totalrows, - rows, numrows); - break; - case ALG_SCALAR: - compute_scalar_stats(vacattrstats[i], - onerel->rd_att, totalrows, - rows, numrows); - break; - } + (*vacattrstats[i]->compute_stats) (vacattrstats[i], + vacattrstats[i]->tupattnum, + onerel->rd_att, + totalrows, + rows, + numrows); MemoryContextResetAndDeleteChildren(col_context); } MemoryContextSwitchTo(old_context); @@ -390,14 +297,11 @@ static VacAttrStats * examine_attribute(Relation onerel, int attnum) { Form_pg_attribute attr = onerel->rd_att->attrs[attnum - 1]; - Operator func_operator; HeapTuple typtuple; - Oid eqopr = InvalidOid; - Oid eqfunc = InvalidOid; - Oid ltopr = InvalidOid; VacAttrStats *stats; + bool ok; - /* Don't analyze dropped columns */ + /* Never analyze dropped columns */ if (attr->attisdropped) return NULL; @@ -405,23 +309,10 @@ examine_attribute(Relation onerel, int attnum) if (attr->attstattarget == 0) return NULL; - /* If column has no "=" operator, we can't do much of anything */ - func_operator = equality_oper(attr->atttypid, true); - if (func_operator != NULL) - { - eqopr = oprid(func_operator); - eqfunc = oprfuncid(func_operator); - ReleaseSysCache(func_operator); - } - if (!OidIsValid(eqfunc)) - return NULL; - /* - * If we have "=" then we're at least able to do the minimal - * algorithm, so start filling in a VacAttrStats struct. + * Create the VacAttrStats struct. */ stats = (VacAttrStats *) palloc0(sizeof(VacAttrStats)); - stats->attnum = attnum; stats->attr = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); memcpy(stats->attr, attr, ATTRIBUTE_TUPLE_SIZE); typtuple = SearchSysCache(TYPEOID, @@ -432,57 +323,25 @@ examine_attribute(Relation onerel, int attnum) stats->attrtype = (Form_pg_type) palloc(sizeof(FormData_pg_type)); memcpy(stats->attrtype, GETSTRUCT(typtuple), sizeof(FormData_pg_type)); ReleaseSysCache(typtuple); - stats->eqopr = eqopr; - stats->eqfunc = eqfunc; - - /* If the attstattarget column is negative, use the default value */ - if (stats->attr->attstattarget < 0) - stats->attr->attstattarget = default_statistics_target; - - /* Is there a "<" operator with suitable semantics? */ - func_operator = ordering_oper(attr->atttypid, true); - if (func_operator != NULL) - { - ltopr = oprid(func_operator); - ReleaseSysCache(func_operator); - } - stats->ltopr = ltopr; + stats->anl_context = anl_context; + stats->tupattnum = attnum; /* - * Determine the algorithm to use (this will get more complicated - * later) + * Call the type-specific typanalyze function. If none is specified, + * use std_typanalyze(). */ - if (OidIsValid(ltopr)) - { - /* Seems to be a scalar datatype */ - stats->algcode = ALG_SCALAR; - /*-------------------- - * The following choice of minrows is based on the paper - * "Random sampling for histogram construction: how much is enough?" - * by Surajit Chaudhuri, Rajeev Motwani and Vivek Narasayya, in - * Proceedings of ACM SIGMOD International Conference on Management - * of Data, 1998, Pages 436-447. Their Corollary 1 to Theorem 5 - * says that for table size n, histogram size k, maximum relative - * error in bin size f, and error probability gamma, the minimum - * random sample size is - * r = 4 * k * ln(2*n/gamma) / f^2 - * Taking f = 0.5, gamma = 0.01, n = 1 million rows, we obtain - * r = 305.82 * k - * Note that because of the log function, the dependence on n is - * quite weak; even at n = 1 billion, a 300*k sample gives <= 0.59 - * bin size error with probability 0.99. So there's no real need to - * scale for n, which is a good thing because we don't necessarily - * know it at this point. - *-------------------- - */ - stats->minrows = 300 * stats->attr->attstattarget; - } + if (OidIsValid(stats->attrtype->typanalyze)) + ok = DatumGetBool(OidFunctionCall1(stats->attrtype->typanalyze, + PointerGetDatum(stats))); else + ok = std_typanalyze(stats); + + if (!ok || stats->compute_stats == NULL || stats->minrows <= 0) { - /* Can't do much but the minimal stuff */ - stats->algcode = ALG_MINIMAL; - /* Might as well use the same minrows as above */ - stats->minrows = 300 * stats->attr->attstattarget; + pfree(stats->attrtype); + pfree(stats->attr); + pfree(stats); + return NULL; } return stats; @@ -851,6 +710,304 @@ compare_rows(const void *a, const void *b) } +/* + * update_attstats() -- update attribute statistics for one relation + * + * Statistics are stored in several places: the pg_class row for the + * relation has stats about the whole relation, and there is a + * pg_statistic row for each (non-system) attribute that has ever + * been analyzed. The pg_class values are updated by VACUUM, not here. + * + * pg_statistic rows are just added or updated normally. This means + * that pg_statistic will probably contain some deleted rows at the + * completion of a vacuum cycle, unless it happens to get vacuumed last. + * + * To keep things simple, we punt for pg_statistic, and don't try + * to compute or store rows for pg_statistic itself in pg_statistic. + * This could possibly be made to work, but it's not worth the trouble. + * Note analyze_rel() has seen to it that we won't come here when + * vacuuming pg_statistic itself. + * + * Note: if two backends concurrently try to analyze the same relation, + * the second one is likely to fail here with a "tuple concurrently + * updated" error. This is slightly annoying, but no real harm is done. + * We could prevent the problem by using a stronger lock on the + * relation for ANALYZE (ie, ShareUpdateExclusiveLock instead + * of AccessShareLock); but that cure seems worse than the disease, + * especially now that ANALYZE doesn't start a new transaction + * for each relation. The lock could be held for a long time... + */ +static void +update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats) +{ + Relation sd; + int attno; + + sd = heap_openr(StatisticRelationName, RowExclusiveLock); + + for (attno = 0; attno < natts; attno++) + { + VacAttrStats *stats = vacattrstats[attno]; + HeapTuple stup, + oldtup; + int i, + k, + n; + Datum values[Natts_pg_statistic]; + char nulls[Natts_pg_statistic]; + char replaces[Natts_pg_statistic]; + + /* Ignore attr if we weren't able to collect stats */ + if (!stats->stats_valid) + continue; + + /* + * Construct a new pg_statistic tuple + */ + for (i = 0; i < Natts_pg_statistic; ++i) + { + nulls[i] = ' '; + replaces[i] = 'r'; + } + + i = 0; + values[i++] = ObjectIdGetDatum(relid); /* starelid */ + values[i++] = Int16GetDatum(stats->attr->attnum); /* staattnum */ + values[i++] = Float4GetDatum(stats->stanullfrac); /* stanullfrac */ + values[i++] = Int32GetDatum(stats->stawidth); /* stawidth */ + values[i++] = Float4GetDatum(stats->stadistinct); /* stadistinct */ + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) + { + values[i++] = Int16GetDatum(stats->stakind[k]); /* stakindN */ + } + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) + { + values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */ + } + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) + { + int nnum = stats->numnumbers[k]; + + if (nnum > 0) + { + Datum *numdatums = (Datum *) palloc(nnum * sizeof(Datum)); + ArrayType *arry; + + for (n = 0; n < nnum; n++) + numdatums[n] = Float4GetDatum(stats->stanumbers[k][n]); + /* XXX knows more than it should about type float4: */ + arry = construct_array(numdatums, nnum, + FLOAT4OID, + sizeof(float4), false, 'i'); + values[i++] = PointerGetDatum(arry); /* stanumbersN */ + } + else + { + nulls[i] = 'n'; + values[i++] = (Datum) 0; + } + } + for (k = 0; k < STATISTIC_NUM_SLOTS; k++) + { + if (stats->numvalues[k] > 0) + { + ArrayType *arry; + + 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 + { + nulls[i] = 'n'; + values[i++] = (Datum) 0; + } + } + + /* Is there already a pg_statistic tuple for this attribute? */ + oldtup = SearchSysCache(STATRELATT, + ObjectIdGetDatum(relid), + Int16GetDatum(stats->attr->attnum), + 0, 0); + + if (HeapTupleIsValid(oldtup)) + { + /* Yes, replace it */ + stup = heap_modifytuple(oldtup, + sd, + values, + nulls, + replaces); + ReleaseSysCache(oldtup); + simple_heap_update(sd, &stup->t_self, stup); + } + else + { + /* No, insert new tuple */ + stup = heap_formtuple(sd->rd_att, values, nulls); + simple_heap_insert(sd, stup); + } + + /* update indexes too */ + CatalogUpdateIndexes(sd, stup); + + heap_freetuple(stup); + } + + heap_close(sd, RowExclusiveLock); +} + + +/*========================================================================== + * + * Code below this point represents the "standard" type-specific statistics + * analysis algorithms. This code can be replaced on a per-data-type basis + * by setting a nonzero value in pg_type.typanalyze. + * + *========================================================================== + */ + + +/* + * To avoid consuming too much memory during analysis and/or too much space + * in the resulting pg_statistic rows, we ignore varlena datums that are wider + * than WIDTH_THRESHOLD (after detoasting!). This is legitimate for MCV + * and distinct-value calculations since a wide value is unlikely to be + * duplicated at all, much less be a most-common value. For the same reason, + * ignoring wide values will not affect our estimates of histogram bin + * boundaries very much. + */ +#define WIDTH_THRESHOLD 1024 + +#define swapInt(a,b) do {int _tmp; _tmp=a; a=b; b=_tmp;} while(0) +#define swapDatum(a,b) do {Datum _tmp; _tmp=a; a=b; b=_tmp;} while(0) + +/* + * Extra information used by the default analysis routines + */ +typedef struct +{ + Oid eqopr; /* '=' operator for datatype, if any */ + Oid eqfunc; /* and associated function */ + Oid ltopr; /* '<' operator for datatype, if any */ +} StdAnalyzeData; + +typedef struct +{ + Datum value; /* a data value */ + int tupno; /* position index for tuple it came from */ +} ScalarItem; + +typedef struct +{ + int count; /* # of duplicates */ + int first; /* values[] index of first occurrence */ +} ScalarMCVItem; + + +/* context information for compare_scalars() */ +static FmgrInfo *datumCmpFn; +static SortFunctionKind datumCmpFnKind; +static int *datumCmpTupnoLink; + + +static void compute_minimal_stats(VacAttrStats *stats, int attnum, + TupleDesc tupDesc, double totalrows, + HeapTuple *rows, int numrows); +static void compute_scalar_stats(VacAttrStats *stats, int attnum, + TupleDesc tupDesc, double totalrows, + HeapTuple *rows, int numrows); +static int compare_scalars(const void *a, const void *b); +static int compare_mcvs(const void *a, const void *b); + + +/* + * std_typanalyze -- the default type-specific typanalyze function + */ +static bool +std_typanalyze(VacAttrStats *stats) +{ + Form_pg_attribute attr = stats->attr; + Operator func_operator; + Oid eqopr = InvalidOid; + Oid eqfunc = InvalidOid; + Oid ltopr = InvalidOid; + StdAnalyzeData *mystats; + + /* If the attstattarget column is negative, use the default value */ + /* NB: it is okay to scribble on stats->attr since it's a copy */ + if (attr->attstattarget < 0) + attr->attstattarget = default_statistics_target; + + /* If column has no "=" operator, we can't do much of anything */ + func_operator = equality_oper(attr->atttypid, true); + if (func_operator != NULL) + { + eqopr = oprid(func_operator); + eqfunc = oprfuncid(func_operator); + ReleaseSysCache(func_operator); + } + if (!OidIsValid(eqfunc)) + return false; + + /* Is there a "<" operator with suitable semantics? */ + func_operator = ordering_oper(attr->atttypid, true); + if (func_operator != NULL) + { + ltopr = oprid(func_operator); + ReleaseSysCache(func_operator); + } + + /* Save the operator info for compute_stats routines */ + mystats = (StdAnalyzeData *) palloc(sizeof(StdAnalyzeData)); + mystats->eqopr = eqopr; + mystats->eqfunc = eqfunc; + mystats->ltopr = ltopr; + stats->extra_data = mystats; + + /* + * Determine which standard statistics algorithm to use + */ + if (OidIsValid(ltopr)) + { + /* Seems to be a scalar datatype */ + stats->compute_stats = compute_scalar_stats; + /*-------------------- + * The following choice of minrows is based on the paper + * "Random sampling for histogram construction: how much is enough?" + * by Surajit Chaudhuri, Rajeev Motwani and Vivek Narasayya, in + * Proceedings of ACM SIGMOD International Conference on Management + * of Data, 1998, Pages 436-447. Their Corollary 1 to Theorem 5 + * says that for table size n, histogram size k, maximum relative + * error in bin size f, and error probability gamma, the minimum + * random sample size is + * r = 4 * k * ln(2*n/gamma) / f^2 + * Taking f = 0.5, gamma = 0.01, n = 1 million rows, we obtain + * r = 305.82 * k + * Note that because of the log function, the dependence on n is + * quite weak; even at n = 1 billion, a 300*k sample gives <= 0.59 + * bin size error with probability 0.99. So there's no real need to + * scale for n, which is a good thing because we don't necessarily + * know it at this point. + *-------------------- + */ + stats->minrows = 300 * attr->attstattarget; + } + else + { + /* Can't do much but the minimal stuff */ + stats->compute_stats = compute_minimal_stats; + /* Might as well use the same minrows as above */ + stats->minrows = 300 * attr->attstattarget; + } + + return true; +} + /* * compute_minimal_stats() -- compute minimal column statistics * @@ -867,7 +1024,7 @@ compare_rows(const void *a, const void *b) * depend mainly on the length of the list we are willing to keep. */ static void -compute_minimal_stats(VacAttrStats *stats, +compute_minimal_stats(VacAttrStats *stats, int attnum, TupleDesc tupDesc, double totalrows, HeapTuple *rows, int numrows) { @@ -890,6 +1047,7 @@ compute_minimal_stats(VacAttrStats *stats, int track_cnt, track_max; int num_mcv = stats->attr->attstattarget; + StdAnalyzeData *mystats = (StdAnalyzeData *) stats->extra_data; /* * We track up to 2*n values for an n-element MCV list; but at least @@ -901,7 +1059,7 @@ compute_minimal_stats(VacAttrStats *stats, track = (TrackItem *) palloc(track_max * sizeof(TrackItem)); track_cnt = 0; - fmgr_info(stats->eqfunc, &f_cmpeq); + fmgr_info(mystats->eqfunc, &f_cmpeq); for (i = 0; i < numrows; i++) { @@ -914,7 +1072,7 @@ compute_minimal_stats(VacAttrStats *stats, vacuum_delay_point(); - value = heap_getattr(tuple, stats->attnum, tupDesc, &isnull); + value = heap_getattr(tuple, attnum, tupDesc, &isnull); /* Check for null/nonnull */ if (isnull) @@ -1137,7 +1295,7 @@ compute_minimal_stats(VacAttrStats *stats, float4 *mcv_freqs; /* Must copy the target values into anl_context */ - old_context = MemoryContextSwitchTo(anl_context); + old_context = MemoryContextSwitchTo(stats->anl_context); mcv_values = (Datum *) palloc(num_mcv * sizeof(Datum)); mcv_freqs = (float4 *) palloc(num_mcv * sizeof(float4)); for (i = 0; i < num_mcv; i++) @@ -1150,7 +1308,7 @@ compute_minimal_stats(VacAttrStats *stats, MemoryContextSwitchTo(old_context); stats->stakind[0] = STATISTIC_KIND_MCV; - stats->staop[0] = stats->eqopr; + stats->staop[0] = mystats->eqopr; stats->stanumbers[0] = mcv_freqs; stats->numnumbers[0] = num_mcv; stats->stavalues[0] = mcv_values; @@ -1175,7 +1333,7 @@ compute_minimal_stats(VacAttrStats *stats, * data values into order. */ static void -compute_scalar_stats(VacAttrStats *stats, +compute_scalar_stats(VacAttrStats *stats, int attnum, TupleDesc tupDesc, double totalrows, HeapTuple *rows, int numrows) { @@ -1199,12 +1357,13 @@ compute_scalar_stats(VacAttrStats *stats, int track_cnt = 0; int num_mcv = stats->attr->attstattarget; int num_bins = stats->attr->attstattarget; + StdAnalyzeData *mystats = (StdAnalyzeData *) stats->extra_data; values = (ScalarItem *) palloc(numrows * sizeof(ScalarItem)); tupnoLink = (int *) palloc(numrows * sizeof(int)); track = (ScalarMCVItem *) palloc(num_mcv * sizeof(ScalarMCVItem)); - SelectSortFunction(stats->ltopr, &cmpFn, &cmpFnKind); + SelectSortFunction(mystats->ltopr, &cmpFn, &cmpFnKind); fmgr_info(cmpFn, &f_cmpfn); /* Initial scan to find sortable values */ @@ -1216,7 +1375,7 @@ compute_scalar_stats(VacAttrStats *stats, vacuum_delay_point(); - value = heap_getattr(tuple, stats->attnum, tupDesc, &isnull); + value = heap_getattr(tuple, attnum, tupDesc, &isnull); /* Check for null/nonnull */ if (isnull) @@ -1469,7 +1628,7 @@ compute_scalar_stats(VacAttrStats *stats, float4 *mcv_freqs; /* Must copy the target values into anl_context */ - old_context = MemoryContextSwitchTo(anl_context); + old_context = MemoryContextSwitchTo(stats->anl_context); mcv_values = (Datum *) palloc(num_mcv * sizeof(Datum)); mcv_freqs = (float4 *) palloc(num_mcv * sizeof(float4)); for (i = 0; i < num_mcv; i++) @@ -1482,7 +1641,7 @@ compute_scalar_stats(VacAttrStats *stats, MemoryContextSwitchTo(old_context); stats->stakind[slot_idx] = STATISTIC_KIND_MCV; - stats->staop[slot_idx] = stats->eqopr; + stats->staop[slot_idx] = mystats->eqopr; stats->stanumbers[slot_idx] = mcv_freqs; stats->numnumbers[slot_idx] = num_mcv; stats->stavalues[slot_idx] = mcv_values; @@ -1555,7 +1714,7 @@ compute_scalar_stats(VacAttrStats *stats, Assert(nvals >= num_hist); /* Must copy the target values into anl_context */ - old_context = MemoryContextSwitchTo(anl_context); + old_context = MemoryContextSwitchTo(stats->anl_context); hist_values = (Datum *) palloc(num_hist * sizeof(Datum)); for (i = 0; i < num_hist; i++) { @@ -1569,7 +1728,7 @@ compute_scalar_stats(VacAttrStats *stats, MemoryContextSwitchTo(old_context); stats->stakind[slot_idx] = STATISTIC_KIND_HISTOGRAM; - stats->staop[slot_idx] = stats->ltopr; + stats->staop[slot_idx] = mystats->ltopr; stats->stavalues[slot_idx] = hist_values; stats->numvalues[slot_idx] = num_hist; slot_idx++; @@ -1584,7 +1743,7 @@ compute_scalar_stats(VacAttrStats *stats, corr_x2sum; /* Must copy the target values into anl_context */ - old_context = MemoryContextSwitchTo(anl_context); + old_context = MemoryContextSwitchTo(stats->anl_context); corrs = (float4 *) palloc(sizeof(float4)); MemoryContextSwitchTo(old_context); @@ -1607,7 +1766,7 @@ compute_scalar_stats(VacAttrStats *stats, (values_cnt * corr_x2sum - corr_xsum * corr_xsum); stats->stakind[slot_idx] = STATISTIC_KIND_CORRELATION; - stats->staop[slot_idx] = stats->ltopr; + stats->staop[slot_idx] = mystats->ltopr; stats->stanumbers[slot_idx] = corrs; stats->numnumbers[slot_idx] = 1; slot_idx++; @@ -1665,155 +1824,3 @@ compare_mcvs(const void *a, const void *b) return da - db; } - - -/* - * update_attstats() -- update attribute statistics for one relation - * - * Statistics are stored in several places: the pg_class row for the - * relation has stats about the whole relation, and there is a - * pg_statistic row for each (non-system) attribute that has ever - * been analyzed. The pg_class values are updated by VACUUM, not here. - * - * pg_statistic rows are just added or updated normally. This means - * that pg_statistic will probably contain some deleted rows at the - * completion of a vacuum cycle, unless it happens to get vacuumed last. - * - * To keep things simple, we punt for pg_statistic, and don't try - * to compute or store rows for pg_statistic itself in pg_statistic. - * This could possibly be made to work, but it's not worth the trouble. - * Note analyze_rel() has seen to it that we won't come here when - * vacuuming pg_statistic itself. - * - * Note: if two backends concurrently try to analyze the same relation, - * the second one is likely to fail here with a "tuple concurrently - * updated" error. This is slightly annoying, but no real harm is done. - * We could prevent the problem by using a stronger lock on the - * relation for ANALYZE (ie, ShareUpdateExclusiveLock instead - * of AccessShareLock); but that cure seems worse than the disease, - * especially now that ANALYZE doesn't start a new transaction - * for each relation. The lock could be held for a long time... - */ -static void -update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats) -{ - Relation sd; - int attno; - - sd = heap_openr(StatisticRelationName, RowExclusiveLock); - - for (attno = 0; attno < natts; attno++) - { - VacAttrStats *stats = vacattrstats[attno]; - HeapTuple stup, - oldtup; - int i, - k, - n; - Datum values[Natts_pg_statistic]; - char nulls[Natts_pg_statistic]; - char replaces[Natts_pg_statistic]; - - /* Ignore attr if we weren't able to collect stats */ - if (!stats->stats_valid) - continue; - - /* - * Construct a new pg_statistic tuple - */ - for (i = 0; i < Natts_pg_statistic; ++i) - { - nulls[i] = ' '; - replaces[i] = 'r'; - } - - i = 0; - values[i++] = ObjectIdGetDatum(relid); /* starelid */ - values[i++] = Int16GetDatum(stats->attnum); /* staattnum */ - values[i++] = Float4GetDatum(stats->stanullfrac); /* stanullfrac */ - values[i++] = Int32GetDatum(stats->stawidth); /* stawidth */ - values[i++] = Float4GetDatum(stats->stadistinct); /* stadistinct */ - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - values[i++] = Int16GetDatum(stats->stakind[k]); /* stakindN */ - } - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */ - } - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - int nnum = stats->numnumbers[k]; - - if (nnum > 0) - { - Datum *numdatums = (Datum *) palloc(nnum * sizeof(Datum)); - ArrayType *arry; - - for (n = 0; n < nnum; n++) - numdatums[n] = Float4GetDatum(stats->stanumbers[k][n]); - /* XXX knows more than it should about type float4: */ - arry = construct_array(numdatums, nnum, - FLOAT4OID, - sizeof(float4), false, 'i'); - values[i++] = PointerGetDatum(arry); /* stanumbersN */ - } - else - { - nulls[i] = 'n'; - values[i++] = (Datum) 0; - } - } - for (k = 0; k < STATISTIC_NUM_SLOTS; k++) - { - if (stats->numvalues[k] > 0) - { - ArrayType *arry; - - 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 - { - nulls[i] = 'n'; - values[i++] = (Datum) 0; - } - } - - /* Is there already a pg_statistic tuple for this attribute? */ - oldtup = SearchSysCache(STATRELATT, - ObjectIdGetDatum(relid), - Int16GetDatum(stats->attnum), - 0, 0); - - if (HeapTupleIsValid(oldtup)) - { - /* Yes, replace it */ - stup = heap_modifytuple(oldtup, - sd, - values, - nulls, - replaces); - ReleaseSysCache(oldtup); - simple_heap_update(sd, &stup->t_self, stup); - } - else - { - /* No, insert new tuple */ - stup = heap_formtuple(sd->rd_att, values, nulls); - simple_heap_insert(sd, stup); - } - - /* update indexes too */ - CatalogUpdateIndexes(sd, stup); - - heap_freetuple(stup); - } - - heap_close(sd, RowExclusiveLock); -} diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 530fb1f573..d081c38b70 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.52 2004/01/10 23:28:44 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.53 2004/02/12 23:41:02 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -77,6 +77,7 @@ static Oid findTypeInputFunction(List *procname, Oid typeOid); static Oid findTypeOutputFunction(List *procname, Oid typeOid); static Oid findTypeReceiveFunction(List *procname, Oid typeOid); static Oid findTypeSendFunction(List *procname, Oid typeOid); +static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid); static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode); static void domainOwnerCheck(HeapTuple tup, TypeName *typename); static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, @@ -101,6 +102,7 @@ DefineType(List *names, List *parameters) List *outputName = NIL; List *receiveName = NIL; List *sendName = NIL; + List *analyzeName = NIL; char *defaultValue = NULL; bool byValue = false; char delimiter = DEFAULT_TYPDELIM; @@ -110,6 +112,7 @@ DefineType(List *names, List *parameters) Oid outputOid; Oid receiveOid = InvalidOid; Oid sendOid = InvalidOid; + Oid analyzeOid = InvalidOid; char *shadow_type; List *pl; Oid typoid; @@ -151,6 +154,9 @@ DefineType(List *names, List *parameters) receiveName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "send") == 0) sendName = defGetQualifiedName(defel); + else if (strcasecmp(defel->defname, "analyze") == 0 || + strcasecmp(defel->defname, "analyse") == 0) + analyzeName = defGetQualifiedName(defel); else if (strcasecmp(defel->defname, "delimiter") == 0) { char *p = defGetString(defel); @@ -318,6 +324,13 @@ DefineType(List *names, List *parameters) NameListToString(sendName)))); } + /* + * Convert analysis function proc name to an OID. If no analysis function + * is specified, we'll use zero to select the built-in default algorithm. + */ + if (analyzeName) + analyzeOid = findTypeAnalyzeFunction(analyzeName, typoid); + /* * now have TypeCreate do all the real work. */ @@ -334,6 +347,7 @@ DefineType(List *names, List *parameters) outputOid, /* output procedure */ receiveOid, /* receive procedure */ sendOid, /* send procedure */ + analyzeOid, /* analyze procedure */ elemType, /* element type ID */ InvalidOid, /* base type ID (only for domains) */ defaultValue, /* default type value */ @@ -366,6 +380,7 @@ DefineType(List *names, List *parameters) F_ARRAY_OUT, /* output procedure */ F_ARRAY_RECV, /* receive procedure */ F_ARRAY_SEND, /* send procedure */ + InvalidOid, /* analyze procedure - default */ typoid, /* element type ID */ InvalidOid, /* base type ID */ NULL, /* never a default type value */ @@ -473,6 +488,7 @@ DefineDomain(CreateDomainStmt *stmt) Oid outputProcedure; Oid receiveProcedure; Oid sendProcedure; + Oid analyzeProcedure; bool byValue; char delimiter; char alignment; @@ -562,6 +578,9 @@ DefineDomain(CreateDomainStmt *stmt) receiveProcedure = baseType->typreceive; sendProcedure = baseType->typsend; + /* Analysis function */ + analyzeProcedure = baseType->typanalyze; + /* Inherited default value */ datum = SysCacheGetAttr(TYPEOID, typeTup, Anum_pg_type_typdefault, &isnull); @@ -714,6 +733,7 @@ DefineDomain(CreateDomainStmt *stmt) outputProcedure, /* output procedure */ receiveProcedure, /* receive procedure */ sendProcedure, /* send procedure */ + analyzeProcedure, /* analyze procedure */ basetypelem, /* element type ID */ basetypeoid, /* base type ID */ defaultValue, /* default type value (text) */ @@ -1033,6 +1053,35 @@ findTypeSendFunction(List *procname, Oid typeOid) return InvalidOid; /* keep compiler quiet */ } +static Oid +findTypeAnalyzeFunction(List *procname, Oid typeOid) +{ + Oid argList[FUNC_MAX_ARGS]; + Oid procOid; + + /* + * Analyze functions always take one INTERNAL argument and return bool. + */ + MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid)); + + argList[0] = INTERNALOID; + + procOid = LookupFuncName(procname, 1, argList, true); + if (!OidIsValid(procOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(procname, 1, argList)))); + + if (get_func_rettype(procOid) != BOOLOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("type analyze function %s must return type \"boolean\"", + NameListToString(procname)))); + + return procOid; +} + /*------------------------------------------------------------------- * DefineCompositeType @@ -1192,6 +1241,7 @@ AlterDomainDefault(List *names, Node *defaultRaw) typTup->typoutput, typTup->typreceive, typTup->typsend, + typTup->typanalyze, typTup->typelem, typTup->typbasetype, defaultExpr, diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index a6c8997c39..096a175dc7 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -12,7 +12,7 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.363 2004/01/22 19:09:32 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.364 2004/02/12 23:41:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1648,9 +1648,9 @@ getTypes(int *numTypes) /* * Make sure there are dependencies from the type to its input and - * output functions. (We don't worry about typsend/typreceive since - * those are only valid in 7.4 and later, wherein the standard - * dependency mechanism will pick them up.) + * output functions. (We don't worry about typsend, typreceive, or + * typanalyze since those are only valid in 7.4 and later, wherein + * the standard dependency mechanism will pick them up.) */ funcInfo = findFuncByOid(tinfo[i].typinput); if (funcInfo) @@ -4148,10 +4148,12 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) char *typoutput; char *typreceive; char *typsend; + char *typanalyze; Oid typinputoid; Oid typoutputoid; Oid typreceiveoid; Oid typsendoid; + Oid typanalyzeoid; char *typdelim; char *typdefault; char *typbyval; @@ -4162,14 +4164,32 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) selectSourceSchema(tinfo->typnamespace->nspname); /* Fetch type-specific details */ - if (fout->remoteVersion >= 70400) + if (fout->remoteVersion >= 70500) { appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, typreceive, typsend, " + "typanalyze, " "typinput::pg_catalog.oid as typinputoid, " "typoutput::pg_catalog.oid as typoutputoid, " "typreceive::pg_catalog.oid as typreceiveoid, " "typsend::pg_catalog.oid as typsendoid, " + "typanalyze::pg_catalog.oid as typanalyzeoid, " + "typdelim, typdefault, typbyval, typalign, " + "typstorage " + "FROM pg_catalog.pg_type " + "WHERE oid = '%u'::pg_catalog.oid", + tinfo->dobj.catId.oid); + } + else if (fout->remoteVersion >= 70400) + { + appendPQExpBuffer(query, "SELECT typlen, " + "typinput, typoutput, typreceive, typsend, " + "'-' as typanalyze, " + "typinput::pg_catalog.oid as typinputoid, " + "typoutput::pg_catalog.oid as typoutputoid, " + "typreceive::pg_catalog.oid as typreceiveoid, " + "typsend::pg_catalog.oid as typsendoid, " + "0 as typanalyzeoid, " "typdelim, typdefault, typbyval, typalign, " "typstorage " "FROM pg_catalog.pg_type " @@ -4181,9 +4201,11 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, " "'-' as typreceive, '-' as typsend, " + "'-' as typanalyze, " "typinput::pg_catalog.oid as typinputoid, " "typoutput::pg_catalog.oid as typoutputoid, " "0 as typreceiveoid, 0 as typsendoid, " + "0 as typanalyzeoid, " "typdelim, typdefault, typbyval, typalign, " "typstorage " "FROM pg_catalog.pg_type " @@ -4199,9 +4221,11 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, " "'-' as typreceive, '-' as typsend, " + "'-' as typanalyze, " "typinput::oid as typinputoid, " "typoutput::oid as typoutputoid, " "0 as typreceiveoid, 0 as typsendoid, " + "0 as typanalyzeoid, " "typdelim, typdefault, typbyval, typalign, " "typstorage " "FROM pg_type " @@ -4213,9 +4237,11 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) appendPQExpBuffer(query, "SELECT typlen, " "typinput, typoutput, " "'-' as typreceive, '-' as typsend, " + "'-' as typanalyze, " "typinput::oid as typinputoid, " "typoutput::oid as typoutputoid, " "0 as typreceiveoid, 0 as typsendoid, " + "0 as typanalyzeoid, " "typdelim, typdefault, typbyval, typalign, " "'p'::char as typstorage " "FROM pg_type " @@ -4240,10 +4266,12 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput")); typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive")); typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend")); + typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze")); typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid"))); typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid"))); typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid"))); typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid"))); + typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid"))); typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim")); if (PQgetisnull(res, 0, PQfnumber(res, "typdefault"))) typdefault = NULL; @@ -4270,13 +4298,15 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) if (fout->remoteVersion >= 70300) { - /* regproc result is correctly quoted in 7.3 */ + /* regproc result is correctly quoted as of 7.3 */ appendPQExpBuffer(q, ",\n INPUT = %s", typinput); appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput); if (OidIsValid(typreceiveoid)) appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive); if (OidIsValid(typsendoid)) appendPQExpBuffer(q, ",\n SEND = %s", typsend); + if (OidIsValid(typanalyzeoid)) + appendPQExpBuffer(q, ",\n ANALYZE = %s", typanalyze); } else { @@ -4284,7 +4314,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo) /* cannot combine these because fmtId uses static result area */ appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput)); appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput)); - /* no chance that receive/send need be printed */ + /* no chance that receive/send/analyze need be printed */ } if (typdefault != NULL) diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index fa6a7f1e60..7fdadf5206 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.217 2004/02/03 08:29:56 joe Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.218 2004/02/12 23:41:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200402021 +#define CATALOG_VERSION_NO 200402121 #endif diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 6098f92d89..754878f014 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.107 2004/01/06 23:55:19 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.108 2004/02/12 23:41:04 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -240,14 +240,15 @@ typedef FormData_pg_attribute *Form_pg_attribute; { 1247, {"typoutput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ { 1247, {"typreceive"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ { 1247, {"typsend"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typalign"}, 18, -1, 1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typstorage"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typnotnull"}, 16, -1, 1, 17, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ -{ 1247, {"typbasetype"}, 26, -1, 4, 18, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typtypmod"}, 23, -1, 4, 19, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typndims"}, 23, -1, 4, 20, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ -{ 1247, {"typdefaultbin"}, 25, -1, -1, 21, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \ -{ 1247, {"typdefault"}, 25, -1, -1, 22, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 } +{ 1247, {"typanalyze"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ +{ 1247, {"typalign"}, 18, -1, 1, 16, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ +{ 1247, {"typstorage"}, 18, -1, 1, 17, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ +{ 1247, {"typnotnull"}, 16, -1, 1, 18, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \ +{ 1247, {"typbasetype"}, 26, -1, 4, 19, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ +{ 1247, {"typtypmod"}, 23, -1, 4, 20, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ +{ 1247, {"typndims"}, 23, -1, 4, 21, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \ +{ 1247, {"typdefaultbin"}, 25, -1, -1, 22, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \ +{ 1247, {"typdefault"}, 25, -1, -1, 23, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 } DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f t 0)); @@ -264,14 +265,15 @@ DATA(insert ( 1247 typinput 24 -1 4 11 0 -1 -1 t p f i t f f t 0)); DATA(insert ( 1247 typoutput 24 -1 4 12 0 -1 -1 t p f i t f f t 0)); DATA(insert ( 1247 typreceive 24 -1 4 13 0 -1 -1 t p f i t f f t 0)); DATA(insert ( 1247 typsend 24 -1 4 14 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typalign 18 -1 1 15 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typstorage 18 -1 1 16 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typnotnull 16 -1 1 17 0 -1 -1 t p f c t f f t 0)); -DATA(insert ( 1247 typbasetype 26 -1 4 18 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typtypmod 23 -1 4 19 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typndims 23 -1 4 20 0 -1 -1 t p f i t f f t 0)); -DATA(insert ( 1247 typdefaultbin 25 -1 -1 21 0 -1 -1 f x f i f f f t 0)); -DATA(insert ( 1247 typdefault 25 -1 -1 22 0 -1 -1 f x f i f f f t 0)); +DATA(insert ( 1247 typanalyze 24 -1 4 15 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1247 typalign 18 -1 1 16 0 -1 -1 t p f c t f f t 0)); +DATA(insert ( 1247 typstorage 18 -1 1 17 0 -1 -1 t p f c t f f t 0)); +DATA(insert ( 1247 typnotnull 16 -1 1 18 0 -1 -1 t p f c t f f t 0)); +DATA(insert ( 1247 typbasetype 26 -1 4 19 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1247 typtypmod 23 -1 4 20 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1247 typndims 23 -1 4 21 0 -1 -1 t p f i t f f t 0)); +DATA(insert ( 1247 typdefaultbin 25 -1 -1 22 0 -1 -1 f x f i f f f t 0)); +DATA(insert ( 1247 typdefault 25 -1 -1 23 0 -1 -1 f x f i f f f t 0)); DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p f i t f f t 0)); DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p f i t f f t 0)); DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p f i t f f t 0)); diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 0743976ddc..eafe5ceb32 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.79 2004/01/06 23:55:19 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.80 2004/02/12 23:41:04 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -134,7 +134,7 @@ typedef FormData_pg_class *Form_pg_class; * ---------------- */ -DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 22 0 0 0 0 0 t f f f _null_ )); +DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 23 0 0 0 0 0 t f f f _null_ )); DESCR(""); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 18 0 0 0 0 0 f f f f _null_ )); DESCR(""); diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h index 07a7f59946..254ffbfa8d 100644 --- a/src/include/catalog/pg_statistic.h +++ b/src/include/catalog/pg_statistic.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_statistic.h,v 1.23 2003/11/29 22:40:58 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_statistic.h,v 1.24 2004/02/12 23:41:04 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -164,11 +164,30 @@ typedef FormData_pg_statistic *Form_pg_statistic; /* * Currently, three statistical slot "kinds" are defined: most common values, * histogram, and correlation. Additional "kinds" will probably appear in - * future to help cope with non-scalar datatypes. + * future to help cope with non-scalar datatypes. Also, custom data types + * can define their own "kind" codes by mutual agreement between a custom + * typanalyze routine and the selectivity estimation functions of the type's + * operators. * * Code reading the pg_statistic relation should not assume that a particular * data "kind" will appear in any particular slot. Instead, search the - * stakind fields to see if the desired data is available. + * stakind fields to see if the desired data is available. (The standard + * function get_attstatsslot() may be used for this.) + */ + +/* + * The present allocation of "kind" codes is: + * + * 1-99: reserved for assignment by the core PostgreSQL project + * (values in this range will be documented in this file) + * 100-199: reserved for assignment by the PostGIS project + * (values to be documented in PostGIS documentation) + * 200-9999: reserved for future public assignments + * + * For private use you may choose a "kind" code at random in the range + * 10000-30000. However, for code that is to be widely disseminated it is + * better to obtain a publicly defined "kind" code by request from the + * PostgreSQL Global Development Group. */ /* diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 7b0e384f58..6daf1579df 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.148 2003/11/29 22:40:58 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.149 2004/02/12 23:41:04 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -104,6 +104,11 @@ CATALOG(pg_type) BOOTSTRAP regproc typreceive; /* binary format (optional) */ regproc typsend; + /* + * Custom ANALYZE procedure for the datatype (0 selects the default). + */ + regproc typanalyze; + /* ---------------- * typalign is the alignment required when storing a value of this * type. It applies to storage on disk as well as most @@ -200,7 +205,7 @@ typedef FormData_pg_type *Form_pg_type; * compiler constants for pg_type * ---------------- */ -#define Natts_pg_type 22 +#define Natts_pg_type 23 #define Anum_pg_type_typname 1 #define Anum_pg_type_typnamespace 2 #define Anum_pg_type_typowner 3 @@ -215,14 +220,15 @@ typedef FormData_pg_type *Form_pg_type; #define Anum_pg_type_typoutput 12 #define Anum_pg_type_typreceive 13 #define Anum_pg_type_typsend 14 -#define Anum_pg_type_typalign 15 -#define Anum_pg_type_typstorage 16 -#define Anum_pg_type_typnotnull 17 -#define Anum_pg_type_typbasetype 18 -#define Anum_pg_type_typtypmod 19 -#define Anum_pg_type_typndims 20 -#define Anum_pg_type_typdefaultbin 21 -#define Anum_pg_type_typdefault 22 +#define Anum_pg_type_typanalyze 15 +#define Anum_pg_type_typalign 16 +#define Anum_pg_type_typstorage 17 +#define Anum_pg_type_typnotnull 18 +#define Anum_pg_type_typbasetype 19 +#define Anum_pg_type_typtypmod 20 +#define Anum_pg_type_typndims 21 +#define Anum_pg_type_typdefaultbin 22 +#define Anum_pg_type_typdefault 23 /* ---------------- @@ -238,82 +244,82 @@ typedef FormData_pg_type *Form_pg_type; */ /* OIDS 1 - 99 */ -DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b t \054 0 0 boolin boolout boolrecv boolsend c p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b t \054 0 0 boolin boolout boolrecv boolsend - c p f 0 -1 0 _null_ _null_ )); DESCR("boolean, 'true'/'false'"); #define BOOLOID 16 -DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b t \054 0 0 byteain byteaout bytearecv byteasend i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b t \054 0 0 byteain byteaout bytearecv byteasend - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length string, binary values escaped"); #define BYTEAOID 17 -DATA(insert OID = 18 ( char PGNSP PGUID 1 t b t \054 0 0 charin charout charrecv charsend c p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 18 ( char PGNSP PGUID 1 t b t \054 0 0 charin charout charrecv charsend - c p f 0 -1 0 _null_ _null_ )); DESCR("single character"); #define CHAROID 18 -DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout namerecv namesend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout namerecv namesend - i p f 0 -1 0 _null_ _null_ )); DESCR("63-character type for storing system identifiers"); #define NAMEOID 19 -DATA(insert OID = 20 ( int8 PGNSP PGUID 8 f b t \054 0 0 int8in int8out int8recv int8send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 20 ( int8 PGNSP PGUID 8 f b t \054 0 0 int8in int8out int8recv int8send - d p f 0 -1 0 _null_ _null_ )); DESCR("~18 digit integer, 8-byte storage"); #define INT8OID 20 -DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b t \054 0 0 int2in int2out int2recv int2send s p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b t \054 0 0 int2in int2out int2recv int2send - s p f 0 -1 0 _null_ _null_ )); DESCR("-32 thousand to 32 thousand, 2-byte storage"); #define INT2OID 21 -DATA(insert OID = 22 ( int2vector PGNSP PGUID INDEX_MAX_KEYS*2 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 22 ( int2vector PGNSP PGUID INDEX_MAX_KEYS*2 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend - i p f 0 -1 0 _null_ _null_ )); DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables"); #define INT2VECTOROID 22 -DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b t \054 0 0 int4in int4out int4recv int4send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b t \054 0 0 int4in int4out int4recv int4send - i p f 0 -1 0 _null_ _null_ )); DESCR("-2 billion to 2 billion integer, 4-byte storage"); #define INT4OID 23 -DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b t \054 0 0 regprocin regprocout regprocrecv regprocsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b t \054 0 0 regprocin regprocout regprocrecv regprocsend - i p f 0 -1 0 _null_ _null_ )); DESCR("registered procedure"); #define REGPROCOID 24 -DATA(insert OID = 25 ( text PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 25 ( text PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length string, no limit specified"); #define TEXTOID 25 -DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b t \054 0 0 oidin oidout oidrecv oidsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b t \054 0 0 oidin oidout oidrecv oidsend - i p f 0 -1 0 _null_ _null_ )); DESCR("object identifier(oid), maximum 4 billion"); #define OIDOID 26 -DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b t \054 0 0 tidin tidout tidrecv tidsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b t \054 0 0 tidin tidout tidrecv tidsend - i p f 0 -1 0 _null_ _null_ )); DESCR("(Block, offset), physical location of tuple"); #define TIDOID 27 -DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b t \054 0 0 xidin xidout xidrecv xidsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b t \054 0 0 xidin xidout xidrecv xidsend - i p f 0 -1 0 _null_ _null_ )); DESCR("transaction id"); #define XIDOID 28 -DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b t \054 0 0 cidin cidout cidrecv cidsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b t \054 0 0 cidin cidout cidrecv cidsend - i p f 0 -1 0 _null_ _null_ )); DESCR("command identifier type, sequence in transaction id"); #define CIDOID 29 -DATA(insert OID = 30 ( oidvector PGNSP PGUID INDEX_MAX_KEYS*4 f b t \054 0 26 oidvectorin oidvectorout oidvectorrecv oidvectorsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 30 ( oidvector PGNSP PGUID INDEX_MAX_KEYS*4 f b t \054 0 26 oidvectorin oidvectorout oidvectorrecv oidvectorsend - i p f 0 -1 0 _null_ _null_ )); DESCR("array of INDEX_MAX_KEYS oids, used in system tables"); #define OIDVECTOROID 30 -DATA(insert OID = 32 ( SET PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 32 ( SET PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout - - - i p f 0 -1 0 _null_ _null_ )); DESCR("set of tuples"); -DATA(insert OID = 71 ( pg_type PGNSP PGUID 4 t c t \054 1247 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 75 ( pg_attribute PGNSP PGUID 4 t c t \054 1249 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 81 ( pg_proc PGNSP PGUID 4 t c t \054 1255 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 83 ( pg_class PGNSP PGUID 4 t c t \054 1259 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 86 ( pg_shadow PGNSP PGUID 4 t c t \054 1260 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 87 ( pg_group PGNSP PGUID 4 t c t \054 1261 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 88 ( pg_database PGNSP PGUID 4 t c t \054 1262 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 71 ( pg_type PGNSP PGUID 4 t c t \054 1247 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 75 ( pg_attribute PGNSP PGUID 4 t c t \054 1249 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 81 ( pg_proc PGNSP PGUID 4 t c t \054 1255 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 83 ( pg_class PGNSP PGUID 4 t c t \054 1259 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 86 ( pg_shadow PGNSP PGUID 4 t c t \054 1260 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 87 ( pg_group PGNSP PGUID 4 t c t \054 1261 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 88 ( pg_database PGNSP PGUID 4 t c t \054 1262 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); /* OIDS 100 - 199 */ /* OIDS 200 - 299 */ -DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b t \054 0 0 smgrin smgrout - - s p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b t \054 0 0 smgrin smgrout - - - s p f 0 -1 0 _null_ _null_ )); DESCR("storage manager"); /* OIDS 300 - 399 */ @@ -323,192 +329,192 @@ DESCR("storage manager"); /* OIDS 500 - 599 */ /* OIDS 600 - 699 */ -DATA(insert OID = 600 ( point PGNSP PGUID 16 f b t \054 0 701 point_in point_out point_recv point_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 600 ( point PGNSP PGUID 16 f b t \054 0 701 point_in point_out point_recv point_send - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric point '(x, y)'"); #define POINTOID 600 -DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b t \054 0 600 lseg_in lseg_out lseg_recv lseg_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b t \054 0 600 lseg_in lseg_out lseg_recv lseg_send - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric line segment '(pt1,pt2)'"); #define LSEGOID 601 -DATA(insert OID = 602 ( path PGNSP PGUID -1 f b t \054 0 0 path_in path_out path_recv path_send d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 602 ( path PGNSP PGUID -1 f b t \054 0 0 path_in path_out path_recv path_send - d x f 0 -1 0 _null_ _null_ )); DESCR("geometric path '(pt1,...)'"); #define PATHOID 602 -DATA(insert OID = 603 ( box PGNSP PGUID 32 f b t \073 0 600 box_in box_out box_recv box_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 603 ( box PGNSP PGUID 32 f b t \073 0 600 box_in box_out box_recv box_send - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric box '(lower left,upper right)'"); #define BOXOID 603 -DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b t \054 0 0 poly_in poly_out poly_recv poly_send d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b t \054 0 0 poly_in poly_out poly_recv poly_send - d x f 0 -1 0 _null_ _null_ )); DESCR("geometric polygon '(pt1,...)'"); #define POLYGONOID 604 -DATA(insert OID = 628 ( line PGNSP PGUID 32 f b t \054 0 701 line_in line_out line_recv line_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 628 ( line PGNSP PGUID 32 f b t \054 0 701 line_in line_out line_recv line_send - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric line (not implemented)'"); #define LINEOID 628 -DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b t \054 0 628 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b t \054 0 628 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); DESCR(""); /* OIDS 700 - 799 */ -DATA(insert OID = 700 ( float4 PGNSP PGUID 4 f b t \054 0 0 float4in float4out float4recv float4send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 700 ( float4 PGNSP PGUID 4 f b t \054 0 0 float4in float4out float4recv float4send - i p f 0 -1 0 _null_ _null_ )); DESCR("single-precision floating point number, 4-byte storage"); #define FLOAT4OID 700 -DATA(insert OID = 701 ( float8 PGNSP PGUID 8 f b t \054 0 0 float8in float8out float8recv float8send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 701 ( float8 PGNSP PGUID 8 f b t \054 0 0 float8in float8out float8recv float8send - d p f 0 -1 0 _null_ _null_ )); DESCR("double-precision floating point number, 8-byte storage"); #define FLOAT8OID 701 -DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b t \054 0 0 abstimein abstimeout abstimerecv abstimesend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b t \054 0 0 abstimein abstimeout abstimerecv abstimesend - i p f 0 -1 0 _null_ _null_ )); DESCR("absolute, limited-range date and time (Unix system time)"); #define ABSTIMEOID 702 -DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b t \054 0 0 reltimein reltimeout reltimerecv reltimesend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b t \054 0 0 reltimein reltimeout reltimerecv reltimesend - i p f 0 -1 0 _null_ _null_ )); DESCR("relative, limited-range time interval (Unix delta time)"); #define RELTIMEOID 703 -DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b t \054 0 0 tintervalin tintervalout tintervalrecv tintervalsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b t \054 0 0 tintervalin tintervalout tintervalrecv tintervalsend - i p f 0 -1 0 _null_ _null_ )); DESCR("(abstime,abstime), time interval"); #define TINTERVALOID 704 -DATA(insert OID = 705 ( unknown PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 705 ( unknown PGNSP PGUID -1 f b t \054 0 0 unknownin unknownout unknownrecv unknownsend - i p f 0 -1 0 _null_ _null_ )); DESCR(""); #define UNKNOWNOID 705 -DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b t \054 0 0 circle_in circle_out circle_recv circle_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b t \054 0 0 circle_in circle_out circle_recv circle_send - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric circle '(center,radius)'"); #define CIRCLEOID 718 -DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b t \054 0 718 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 790 ( money PGNSP PGUID 4 f b t \054 0 0 cash_in cash_out cash_recv cash_send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b t \054 0 718 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 790 ( money PGNSP PGUID 4 f b t \054 0 0 cash_in cash_out cash_recv cash_send - i p f 0 -1 0 _null_ _null_ )); DESCR("monetary amounts, $d,ddd.cc"); #define CASHOID 790 -DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b t \054 0 790 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b t \054 0 790 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); /* OIDS 800 - 899 */ -DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b t \054 0 0 macaddr_in macaddr_out macaddr_recv macaddr_send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b t \054 0 0 macaddr_in macaddr_out macaddr_recv macaddr_send - i p f 0 -1 0 _null_ _null_ )); DESCR("XX:XX:XX:XX:XX:XX, MAC address"); #define MACADDROID 829 -DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b t \054 0 0 inet_in inet_out inet_recv inet_send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b t \054 0 0 inet_in inet_out inet_recv inet_send - i p f 0 -1 0 _null_ _null_ )); DESCR("IP address/netmask, host address, netmask optional"); #define INETOID 869 -DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b t \054 0 0 cidr_in cidr_out cidr_recv cidr_send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b t \054 0 0 cidr_in cidr_out cidr_recv cidr_send - i p f 0 -1 0 _null_ _null_ )); DESCR("network IP address/netmask, network address"); #define CIDROID 650 /* OIDS 900 - 999 */ /* OIDS 1000 - 1099 */ -DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b t \054 0 16 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b t \054 0 17 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b t \054 0 18 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b t \054 0 19 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b t \054 0 21 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b t \054 0 22 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b t \054 0 23 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b t \054 0 24 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b t \054 0 25 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b t \054 0 26 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b t \054 0 27 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b t \054 0 28 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b t \054 0 29 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b t \054 0 30 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b t \054 0 1042 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b t \054 0 1043 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b t \054 0 20 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b t \054 0 600 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b t \054 0 601 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b t \054 0 602 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b t \073 0 603 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b t \054 0 700 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b t \054 0 701 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b t \054 0 702 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b t \054 0 703 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b t \054 0 704 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b t \054 0 604 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b t \054 0 0 aclitemin aclitemout - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b t \054 0 16 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b t \054 0 17 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b t \054 0 18 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b t \054 0 19 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b t \054 0 21 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b t \054 0 22 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b t \054 0 23 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b t \054 0 24 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b t \054 0 25 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b t \054 0 26 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b t \054 0 27 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b t \054 0 28 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b t \054 0 29 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b t \054 0 30 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b t \054 0 1042 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b t \054 0 1043 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b t \054 0 20 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b t \054 0 600 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b t \054 0 601 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b t \054 0 602 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b t \073 0 603 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b t \054 0 700 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b t \054 0 701 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b t \054 0 702 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b t \054 0 703 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b t \054 0 704 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b t \054 0 604 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b t \054 0 0 aclitemin aclitemout - - - i p f 0 -1 0 _null_ _null_ )); DESCR("access control list"); #define ACLITEMOID 1033 -DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b t \054 0 1033 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b t \054 0 829 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b t \054 0 869 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b t \054 0 650 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b t \054 0 0 bpcharin bpcharout bpcharrecv bpcharsend i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b t \054 0 1033 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b t \054 0 829 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b t \054 0 869 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b t \054 0 650 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b t \054 0 0 bpcharin bpcharout bpcharrecv bpcharsend - i x f 0 -1 0 _null_ _null_ )); DESCR("char(length), blank-padded string, fixed storage length"); #define BPCHAROID 1042 -DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b t \054 0 0 varcharin varcharout varcharrecv varcharsend i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b t \054 0 0 varcharin varcharout varcharrecv varcharsend - i x f 0 -1 0 _null_ _null_ )); DESCR("varchar(length), non-blank-padded string, variable storage length"); #define VARCHAROID 1043 -DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b t \054 0 0 date_in date_out date_recv date_send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b t \054 0 0 date_in date_out date_recv date_send - i p f 0 -1 0 _null_ _null_ )); DESCR("ANSI SQL date"); #define DATEOID 1082 -DATA(insert OID = 1083 ( time PGNSP PGUID 8 f b t \054 0 0 time_in time_out time_recv time_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1083 ( time PGNSP PGUID 8 f b t \054 0 0 time_in time_out time_recv time_send - d p f 0 -1 0 _null_ _null_ )); DESCR("hh:mm:ss, ANSI SQL time"); #define TIMEOID 1083 /* OIDS 1100 - 1199 */ -DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 f b t \054 0 0 timestamp_in timestamp_out timestamp_recv timestamp_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 f b t \054 0 0 timestamp_in timestamp_out timestamp_recv timestamp_send - d p f 0 -1 0 _null_ _null_ )); DESCR("date and time"); #define TIMESTAMPOID 1114 -DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b t \054 0 1114 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b t \054 0 1082 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b t \054 0 1083 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 f b t \054 0 0 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b t \054 0 1114 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b t \054 0 1082 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b t \054 0 1083 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 f b t \054 0 0 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send - d p f 0 -1 0 _null_ _null_ )); DESCR("date and time with time zone"); #define TIMESTAMPTZOID 1184 -DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b t \054 0 1184 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1186 ( interval PGNSP PGUID 12 f b t \054 0 0 interval_in interval_out interval_recv interval_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b t \054 0 1184 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1186 ( interval PGNSP PGUID 12 f b t \054 0 0 interval_in interval_out interval_recv interval_send - d p f 0 -1 0 _null_ _null_ )); DESCR("@ , time interval"); #define INTERVALOID 1186 -DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b t \054 0 1186 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b t \054 0 1186 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); /* OIDS 1200 - 1299 */ -DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b t \054 0 1700 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b t \054 0 0 timetz_in timetz_out timetz_recv timetz_send d p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b t \054 0 1700 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b t \054 0 0 timetz_in timetz_out timetz_recv timetz_send - d p f 0 -1 0 _null_ _null_ )); DESCR("hh:mm:ss, ANSI SQL time"); #define TIMETZOID 1266 -DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b t \054 0 1266 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b t \054 0 1266 array_in array_out array_recv array_send - d x f 0 -1 0 _null_ _null_ )); /* OIDS 1500 - 1599 */ -DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b t \054 0 0 bit_in bit_out bit_recv bit_send i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b t \054 0 0 bit_in bit_out bit_recv bit_send - i x f 0 -1 0 _null_ _null_ )); DESCR("fixed-length bit string"); #define BITOID 1560 -DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b t \054 0 1560 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b t \054 0 0 varbit_in varbit_out varbit_recv varbit_send i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b t \054 0 1560 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b t \054 0 0 varbit_in varbit_out varbit_recv varbit_send - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length bit string"); #define VARBITOID 1562 -DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b t \054 0 1562 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b t \054 0 1562 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); /* OIDS 1600 - 1699 */ /* OIDS 1700 - 1799 */ -DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b t \054 0 0 numeric_in numeric_out numeric_recv numeric_send i m f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b t \054 0 0 numeric_in numeric_out numeric_recv numeric_send - i m f 0 -1 0 _null_ _null_ )); DESCR("numeric(precision, decimal), arbitrary precision number"); #define NUMERICOID 1700 -DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b t \054 0 0 textin textout textrecv textsend - i x f 0 -1 0 _null_ _null_ )); DESCR("reference cursor (portal name)"); #define REFCURSOROID 1790 /* OIDS 2200 - 2299 */ -DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b t \054 0 1790 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b t \054 0 1790 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b t \054 0 0 regprocedurein regprocedureout regprocedurerecv regproceduresend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b t \054 0 0 regprocedurein regprocedureout regprocedurerecv regproceduresend - i p f 0 -1 0 _null_ _null_ )); DESCR("registered procedure (with args)"); #define REGPROCEDUREOID 2202 -DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b t \054 0 0 regoperin regoperout regoperrecv regopersend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b t \054 0 0 regoperin regoperout regoperrecv regopersend - i p f 0 -1 0 _null_ _null_ )); DESCR("registered operator"); #define REGOPEROID 2203 -DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b t \054 0 0 regoperatorin regoperatorout regoperatorrecv regoperatorsend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b t \054 0 0 regoperatorin regoperatorout regoperatorrecv regoperatorsend - i p f 0 -1 0 _null_ _null_ )); DESCR("registered operator (with args)"); #define REGOPERATOROID 2204 -DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b t \054 0 0 regclassin regclassout regclassrecv regclasssend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b t \054 0 0 regclassin regclassout regclassrecv regclasssend - i p f 0 -1 0 _null_ _null_ )); DESCR("registered class"); #define REGCLASSOID 2205 -DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b t \054 0 0 regtypein regtypeout regtyperecv regtypesend i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b t \054 0 0 regtypein regtypeout regtyperecv regtypesend - i p f 0 -1 0 _null_ _null_ )); DESCR("registered type"); #define REGTYPEOID 2206 -DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b t \054 0 2202 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b t \054 0 2203 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b t \054 0 2204 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b t \054 0 2205 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); -DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b t \054 0 2202 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b t \054 0 2203 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b t \054 0 2204 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b t \054 0 2205 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ )); /* * pseudo-types @@ -519,25 +525,25 @@ DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b t \054 0 2206 array_in a * argument and result types (if supported by the function's implementation * language). */ -DATA(insert OID = 2249 ( record PGNSP PGUID 4 t p t \054 0 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2249 ( record PGNSP PGUID 4 t p t \054 0 0 record_in record_out record_recv record_send - i p f 0 -1 0 _null_ _null_ )); #define RECORDOID 2249 -DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out cstring_recv cstring_send c p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out cstring_recv cstring_send - c p f 0 -1 0 _null_ _null_ )); #define CSTRINGOID 2275 -DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p t \054 0 0 any_in any_out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p t \054 0 0 any_in any_out - - - i p f 0 -1 0 _null_ _null_ )); #define ANYOID 2276 -DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send i x f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - i x f 0 -1 0 _null_ _null_ )); #define ANYARRAYOID 2277 -DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p t \054 0 0 void_in void_out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p t \054 0 0 void_in void_out - - - i p f 0 -1 0 _null_ _null_ )); #define VOIDOID 2278 -DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p t \054 0 0 trigger_in trigger_out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p t \054 0 0 trigger_in trigger_out - - - i p f 0 -1 0 _null_ _null_ )); #define TRIGGEROID 2279 -DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p t \054 0 0 language_handler_in language_handler_out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p t \054 0 0 language_handler_in language_handler_out - - - i p f 0 -1 0 _null_ _null_ )); #define LANGUAGE_HANDLEROID 2280 -DATA(insert OID = 2281 ( internal PGNSP PGUID 4 t p t \054 0 0 internal_in internal_out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2281 ( internal PGNSP PGUID 4 t p t \054 0 0 internal_in internal_out - - - i p f 0 -1 0 _null_ _null_ )); #define INTERNALOID 2281 -DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p t \054 0 0 opaque_in opaque_out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p t \054 0 0 opaque_in opaque_out - - - i p f 0 -1 0 _null_ _null_ )); #define OPAQUEOID 2282 -DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - i p f 0 -1 0 _null_ _null_ )); +DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p t \054 0 0 anyelement_in anyelement_out - - - i p f 0 -1 0 _null_ _null_ )); #define ANYELEMENTOID 2283 /* @@ -557,6 +563,7 @@ extern Oid TypeCreate(const char *typeName, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, + Oid analyzeProcedure, Oid elementType, Oid baseType, const char *defaultTypeValue, @@ -576,6 +583,7 @@ extern void GenerateTypeDependencies(Oid typeNamespace, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, + Oid analyzeProcedure, Oid elementType, Oid baseType, Node *defaultExpr, diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 61985b0d39..b80f068356 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.48 2004/02/10 03:42:45 tgl Exp $ + * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.49 2004/02/12 23:41:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,10 +23,86 @@ #include "rusagestub.h" #endif +#include "access/htup.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_statistic.h" +#include "catalog/pg_type.h" #include "nodes/parsenodes.h" #include "utils/rel.h" +/*---------- + * ANALYZE builds one of these structs for each attribute (column) that is + * to be analyzed. The struct and subsidiary data are in anl_context, + * so they live until the end of the ANALYZE operation. + * + * The type-specific typanalyze function is passed a pointer to this struct + * and must return TRUE to continue analysis, FALSE to skip analysis of this + * column. In the TRUE case it must set the compute_stats and minrows fields, + * and can optionally set extra_data to pass additional info to compute_stats. + * + * The compute_stats routine will be called after sample rows have been + * gathered. Aside from this struct, it is passed: + * attnum: attribute number within the supplied tuples + * tupDesc: tuple descriptor for the supplied tuples + * totalrows: estimated total number of rows in relation + * rows: an array of the sample tuples + * numrows: the number of sample tuples + * Note that the passed attnum and tupDesc could possibly be different from + * what one would expect by looking at the pg_attribute row. It is important + * to use these values for extracting attribute values from the given rows + * (and not for any other purpose). + * + * compute_stats should set stats_valid TRUE if it is able to compute + * any useful statistics. If it does, the remainder of the struct holds + * the information to be stored in a pg_statistic row for the column. Be + * careful to allocate any pointed-to data in anl_context, which will NOT + * be CurrentMemoryContext when compute_stats is called. + *---------- + */ +typedef struct VacAttrStats +{ + /* + * These fields are set up by the main ANALYZE code before invoking + * the type-specific typanalyze function. + */ + Form_pg_attribute attr; /* copy of pg_attribute row for column */ + Form_pg_type attrtype; /* copy of pg_type row for column */ + MemoryContext anl_context; /* where to save long-lived data */ + + /* + * These fields must be filled in by the typanalyze routine, + * unless it returns FALSE. + */ + void (*compute_stats) (struct VacAttrStats *stats, int attnum, + TupleDesc tupDesc, double totalrows, + HeapTuple *rows, int numrows); + int minrows; /* Minimum # of rows wanted for stats */ + void *extra_data; /* for extra type-specific data */ + + /* + * These fields are to be filled in by the compute_stats routine. + * (They are initialized to zero when the struct is created.) + */ + bool stats_valid; + float4 stanullfrac; /* fraction of entries that are NULL */ + int4 stawidth; /* average width of column values */ + float4 stadistinct; /* # distinct values */ + int2 stakind[STATISTIC_NUM_SLOTS]; + Oid staop[STATISTIC_NUM_SLOTS]; + int numnumbers[STATISTIC_NUM_SLOTS]; + float4 *stanumbers[STATISTIC_NUM_SLOTS]; + int numvalues[STATISTIC_NUM_SLOTS]; + Datum *stavalues[STATISTIC_NUM_SLOTS]; + + /* + * These fields are private to the main ANALYZE code and should not + * be looked at by type-specific functions. + */ + int tupattnum; /* attribute number within tuples */ +} VacAttrStats; + + /* State structure for vac_init_rusage/vac_show_rusage */ typedef struct VacRUsage {