cross-col-syntax.patch
text/plain
Filename: cross-col-syntax.patch
Type: text/plain
Part: 1
diff -dcrpN postgresql.4/src/backend/commands/analyze.c postgresql.5/src/backend/commands/analyze.c
*** postgresql.4/src/backend/commands/analyze.c 2011-08-02 11:51:06.071322632 +0200
--- postgresql.5/src/backend/commands/analyze.c 2011-08-02 14:59:37.136374568 +0200
***************
*** 21,26 ****
--- 21,27 ----
#include "access/tupconvert.h"
#include "access/tuptoaster.h"
#include "access/xact.h"
+ #include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
***************
*** 28,33 ****
--- 29,35 ----
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
+ #include "commands/defrem.h"
#include "commands/vacuum.h"
#include "executor/executor.h"
#include "miscadmin.h"
*************** compare_mcvs(const void *a, const void *
*** 2779,2781 ****
--- 2781,2852 ----
return da - db;
}
+
+ /*
+ * ExtraColStat
+ * Add or remove one extra entry in pg_statistics
+ */
+ void ExtraStatistics(ExtraStatStmt *stmt)
+ {
+ Oid relId;
+ int len, i, j;
+ bool differ = false;
+ AttrNumber *attnums;
+ AttrNumber *sorted_attnums;
+ ListCell *l;
+
+ relId = RangeVarGetRelid(stmt->relation, AccessExclusiveLock, false, false);
+
+ len = list_length(stmt->columns);
+ if (len < 2)
+ elog(ERROR, "cross column statistics need at least two columns");
+
+ attnums = (int2 *)palloc(len * sizeof(AttrNumber));
+ sorted_attnums = (int2 *)palloc(len * sizeof(AttrNumber));
+
+ i = 0;
+ foreach(l, stmt->columns)
+ {
+ Node *node = (Node *) lfirst(l);
+ Var *var;
+
+ if (!IsA(node, Var))
+ elog(ERROR, "not a column reference");
+
+ var = (Var *) node;
+
+ if (var->varattno == 0)
+ elog(ERROR, "row expansion via \"*\" is not supported here");
+
+ sorted_attnums[i] = attnums[i] = var->varattno;
+
+ i++;
+ }
+
+ for (i = 0; i < len - 1; i++)
+ for (j = i+1; j < len; j++)
+ if (sorted_attnums[i] > sorted_attnums[j])
+ {
+ AttrNumber tmp = sorted_attnums[i];
+
+ sorted_attnums[i] = sorted_attnums[j];
+ sorted_attnums[j] = tmp;
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ if (!differ && attnums[i] != sorted_attnums[i])
+ differ = true;
+
+ if ((i < len - 1) && sorted_attnums[i] == sorted_attnums[i+1])
+ elog(ERROR, "column list must contain every column exactly once");
+
+ }
+ if (differ)
+ elog(WARNING, "the column list was reordered in the order of table attributes");
+
+ if (stmt->create)
+ AddStatistics(relId, sorted_attnums, len, false, stmt->statistics_target);
+ else
+ RemoveStatistics(relId, sorted_attnums, len);
+ }
diff -dcrpN postgresql.4/src/backend/nodes/copyfuncs.c postgresql.5/src/backend/nodes/copyfuncs.c
*** postgresql.4/src/backend/nodes/copyfuncs.c 2011-07-24 18:16:45.269678833 +0200
--- postgresql.5/src/backend/nodes/copyfuncs.c 2011-08-02 14:07:24.223043799 +0200
*************** _copyCreateForeignTableStmt(CreateForeig
*** 3459,3464 ****
--- 3459,3477 ----
return newnode;
}
+ static ExtraStatStmt *
+ _copyExtraStatStmt(ExtraStatStmt *from)
+ {
+ ExtraStatStmt *newnode = makeNode(ExtraStatStmt);
+
+ COPY_SCALAR_FIELD(create);
+ newnode->relation = _copyRangeVar(from->relation);
+ COPY_NODE_FIELD(columns);
+ COPY_SCALAR_FIELD(statistics_target);
+
+ return newnode;
+ }
+
static CreateTrigStmt *
_copyCreateTrigStmt(CreateTrigStmt *from)
{
*************** copyObject(void *from)
*** 4378,4383 ****
--- 4391,4399 ----
case T_CreateForeignTableStmt:
retval = _copyCreateForeignTableStmt(from);
break;
+ case T_ExtraStatStmt:
+ retval = _copyExtraStatStmt(from);
+ break;
case T_CreateTrigStmt:
retval = _copyCreateTrigStmt(from);
break;
diff -dcrpN postgresql.4/src/backend/nodes/equalfuncs.c postgresql.5/src/backend/nodes/equalfuncs.c
*** postgresql.4/src/backend/nodes/equalfuncs.c 2011-07-24 18:16:45.269678833 +0200
--- postgresql.5/src/backend/nodes/equalfuncs.c 2011-08-02 14:07:24.246042121 +0200
*************** _equalCreateForeignTableStmt(CreateForei
*** 1796,1801 ****
--- 1796,1813 ----
}
static bool
+ _equalExtraStatStmt(ExtraStatStmt *a, ExtraStatStmt *b)
+ {
+ COMPARE_SCALAR_FIELD(create);
+ if (!_equalRangeVar(a->relation, b->relation))
+ return FALSE;
+ COMPARE_NODE_FIELD(columns);
+ COMPARE_SCALAR_FIELD(statistics_target);
+
+ return true;
+ }
+
+ static bool
_equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
{
COMPARE_STRING_FIELD(trigname);
*************** equal(void *a, void *b)
*** 2931,2936 ****
--- 2943,2951 ----
case T_CreateForeignTableStmt:
retval = _equalCreateForeignTableStmt(a, b);
break;
+ case T_ExtraStatStmt:
+ retval = _equalExtraStatStmt(a, b);
+ break;
case T_CreateTrigStmt:
retval = _equalCreateTrigStmt(a, b);
break;
diff -dcrpN postgresql.4/src/backend/parser/gram.y postgresql.5/src/backend/parser/gram.y
*** postgresql.4/src/backend/parser/gram.y 2011-07-24 18:16:45.272678682 +0200
--- postgresql.5/src/backend/parser/gram.y 2011-08-02 14:07:24.282039495 +0200
*************** static void processCASbits(int cas_bits,
*** 214,220 ****
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
! DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
--- 214,220 ----
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
! DropForeignServerStmt DropUserMappingStmt ExplainStmt ExtraStatStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
*************** static void processCASbits(int cas_bits,
*** 246,252 ****
transaction_mode_item
create_extension_opt_item alter_extension_opt_item
! %type <ival> opt_lock lock_type cast_context
%type <ival> vacuum_option_list vacuum_option_elem
%type <boolean> opt_force opt_or_replace
opt_grant_grant_option opt_grant_admin_option
--- 246,252 ----
transaction_mode_item
create_extension_opt_item alter_extension_opt_item
! %type <ival> opt_lock lock_type cast_context opt_stattarget
%type <ival> vacuum_option_list vacuum_option_elem
%type <boolean> opt_force opt_or_replace
opt_grant_grant_option opt_grant_admin_option
*************** static void processCASbits(int cas_bits,
*** 325,330 ****
--- 325,332 ----
%type <list> opt_fdw_options fdw_options
%type <defelt> fdw_option
+ %type <list> cc_column_list
+
%type <range> OptTempTableName
%type <into> into_clause create_as_target
*************** stmt :
*** 756,761 ****
--- 758,764 ----
| DropdbStmt
| ExecuteStmt
| ExplainStmt
+ | ExtraStatStmt
| FetchStmt
| GrantStmt
| GrantRoleStmt
*************** schema_stmt:
*** 1200,1205 ****
--- 1203,1276 ----
/*****************************************************************************
*
+ * Add / drop extra statistics
+ *
+ *****************************************************************************/
+
+ ExtraStatStmt:
+ CREATE CROSS COLUMN STATISTICS ON TABLE qualified_name '(' cc_column_list ')' opt_stattarget
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+
+ n->relkind = 'r';
+ n->create = true;
+ n->relation = $7;
+ n->columns = $9;
+ n->statistics_target = $11;
+ $$ = (Node *)n;
+ }
+ | DROP CROSS COLUMN STATISTICS ON TABLE qualified_name '(' cc_column_list ')'
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+
+ n->relkind = 'r';
+ n->create = false;
+ n->relation = $7;
+ n->columns = $9;
+ $$ = (Node *)n;
+ }
+ | CREATE CROSS COLUMN STATISTICS ON INDEX qualified_name opt_stattarget
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+
+ n->relkind = 'i';
+ n->create = true;
+ n->relation = $7;
+ n->columns = NIL;
+ n->statistics_target = $8;
+ $$ = (Node *)n;
+ }
+ | DROP CROSS COLUMN STATISTICS ON INDEX qualified_name
+ {
+ ExtraStatStmt *n = makeNode(ExtraStatStmt);
+
+ n->relkind = 'i';
+ n->create = false;
+ n->relation = $7;
+ n->columns = NIL;
+ $$ = (Node *)n;
+ }
+ ;
+
+ cc_column_list:
+ columnref
+ {
+ $$ = list_make1($1);
+ }
+ | cc_column_list ',' columnref
+ {
+ $$ = lappend($1, $3);
+ }
+ ;
+
+ opt_stattarget:
+ WITH '(' Iconst ')' { $$ = $3; }
+ | /* EMPTY */ { $$ = -1; }
+ ;
+
+
+ /*****************************************************************************
+ *
* Set PG internal variable
* SET name TO 'var_value'
* Include SQL92 syntax (thomas 1997-10-22):
diff -dcrpN postgresql.4/src/backend/parser/parse_utilcmd.c postgresql.5/src/backend/parser/parse_utilcmd.c
*** postgresql.4/src/backend/parser/parse_utilcmd.c 2011-07-18 15:42:00.045377085 +0200
--- postgresql.5/src/backend/parser/parse_utilcmd.c 2011-08-02 15:00:29.005542805 +0200
*************** setSchemaName(char *context_schema, char
*** 2710,2712 ****
--- 2710,2804 ----
"different from the one being created (%s)",
*stmt_schema_name, context_schema)));
}
+
+ /*
+ * transformExtraStatistics
+ * Transform the column list or the expression into a form
+ * usable by the executor.
+ */
+ ExtraStatStmt *
+ transformExtraStatistics(ExtraStatStmt *stmt, const char *queryString)
+ {
+ ParseState *pstate;
+ RangeTblEntry *rte;
+ ExtraStatStmt *newstmt;
+ List *columns = NIL;
+ ListCell *cell;
+ Oid relId;
+ HeapTuple tuple;
+ HeapTuple attuple;
+ Form_pg_class classptr;
+ Form_pg_index indexptr;
+ Form_pg_attribute attptr;
+ AttrNumber i;
+
+ switch (stmt->relkind)
+ {
+ case 'r':
+ pstate = make_parsestate(NULL);
+ pstate->p_sourcetext = queryString;
+
+ rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true);
+ addRTEtoQuery(pstate, rte, true, true, true);
+
+ foreach(cell, stmt->columns)
+ {
+ Node *col = lfirst(cell);
+
+ columns = lappend(columns, transformExpr(pstate, col));
+ }
+
+ break;
+
+ case 'i':
+ relId = RangeVarGetRelid(stmt->relation, ShareLock, false, false);
+
+ tuple = SearchSysCache1(RELOID, relId);
+ classptr = (Form_pg_class) GETSTRUCT(tuple);
+
+ if (classptr->relkind != 'i')
+ elog(ERROR, "not an index");
+
+ ReleaseSysCache(tuple);
+
+ tuple = SearchSysCache1(INDEXRELID, relId);
+ indexptr = (Form_pg_index) GETSTRUCT(tuple);
+
+ if (indexptr->indnatts < 2)
+ {
+ ReleaseSysCache(tuple);
+
+ elog(ERROR, "cross column statistics are only usable on multi-column indexes");
+ }
+
+ for (i = 1; i <= indexptr->indnatts; i++)
+ {
+ attuple = SearchSysCache2(ATTNUM, relId, i);
+ if (!HeapTupleIsValid(attuple))
+ elog(ERROR, "pg_attribute row not found for index");
+
+ attptr = (Form_pg_attribute) GETSTRUCT(attuple);
+
+ columns = lappend(columns, makeVar(0, i,
+ attptr->atttypid,
+ attptr->atttypmod,
+ InvalidOid, 0));
+
+ ReleaseSysCache(attuple);
+ }
+
+ ReleaseSysCache(tuple);
+ break;
+
+ default:
+ elog(ERROR, "invalid relkind");
+ }
+
+ newstmt = makeNode(ExtraStatStmt);
+ newstmt->relkind = stmt->relkind;
+ newstmt->create = stmt->create;
+ newstmt->relation = copyObject(stmt->relation);
+ newstmt->columns = columns;
+
+ return newstmt;
+ }
diff -dcrpN postgresql.4/src/backend/tcop/utility.c postgresql.5/src/backend/tcop/utility.c
*** postgresql.4/src/backend/tcop/utility.c 2011-07-24 18:16:45.276678481 +0200
--- postgresql.5/src/backend/tcop/utility.c 2011-08-02 14:07:24.319036796 +0200
*************** check_xact_readonly(Node *parsetree)
*** 237,242 ****
--- 237,243 ----
case T_AlterTableSpaceOptionsStmt:
case T_CreateForeignTableStmt:
case T_SecLabelStmt:
+ case T_ExtraStatStmt:
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
break;
default:
*************** standard_ProcessUtility(Node *parsetree,
*** 581,586 ****
--- 582,595 ----
}
break;
+ case T_ExtraStatStmt:
+ {
+ ExtraStatStmt *newstmt = transformExtraStatistics((ExtraStatStmt *)parsetree, queryString);
+
+ ExtraStatistics(newstmt);
+ }
+ break;
+
case T_CreateTableSpaceStmt:
PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
CreateTableSpace((CreateTableSpaceStmt *) parsetree);
*************** CreateCommandTag(Node *parsetree)
*** 1744,1749 ****
--- 1753,1769 ----
tag = "CREATE FOREIGN TABLE";
break;
+ case T_ExtraStatStmt:
+ {
+ ExtraStatStmt *stmt = (ExtraStatStmt *)parsetree;
+
+ if (stmt->create)
+ tag = "CREATE CROSS COLUMN STATISTICS";
+ else
+ tag = "DROP CROSS COLUMN STATISTICS";
+ }
+ break;
+
case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType)
{
diff -dcrpN postgresql.4/src/include/commands/defrem.h postgresql.5/src/include/commands/defrem.h
*** postgresql.4/src/include/commands/defrem.h 2011-07-24 18:16:45.287677928 +0200
--- postgresql.5/src/include/commands/defrem.h 2011-08-02 14:07:24.332035848 +0200
*************** extern void RemoveAggregate(RemoveFuncSt
*** 93,98 ****
--- 93,101 ----
extern void RenameAggregate(List *name, List *args, const char *newname);
extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId);
+ /* commands/analyze.c */
+ extern void ExtraStatistics(ExtraStatStmt *stmt);
+
/* commands/opclasscmds.c */
extern void DefineOpClass(CreateOpClassStmt *stmt);
extern void DefineOpFamily(CreateOpFamilyStmt *stmt);
diff -dcrpN postgresql.4/src/include/nodes/nodes.h postgresql.5/src/include/nodes/nodes.h
*** postgresql.4/src/include/nodes/nodes.h 2011-03-22 17:53:48.045903422 +0100
--- postgresql.5/src/include/nodes/nodes.h 2011-08-02 14:07:24.340035264 +0200
*************** typedef enum NodeTag
*** 362,367 ****
--- 362,368 ----
T_CreateExtensionStmt,
T_AlterExtensionStmt,
T_AlterExtensionContentsStmt,
+ T_ExtraStatStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
diff -dcrpN postgresql.4/src/include/nodes/parsenodes.h postgresql.5/src/include/nodes/parsenodes.h
*** postgresql.4/src/include/nodes/parsenodes.h 2011-07-24 18:16:45.287677928 +0200
--- postgresql.5/src/include/nodes/parsenodes.h 2011-08-02 14:07:24.351034462 +0200
*************** typedef enum DropBehavior
*** 1160,1165 ****
--- 1160,1179 ----
} DropBehavior;
/* ----------------------
+ * Create Cross Column Statistics
+ * ----------------------
+ */
+ typedef struct ExtraStatStmt
+ {
+ NodeTag type;
+ char relkind;
+ bool create;
+ RangeVar *relation;
+ List *columns;
+ int statistics_target;
+ } ExtraStatStmt;
+
+ /* ----------------------
* Alter Table
* ----------------------
*/
diff -dcrpN postgresql.4/src/include/parser/parse_utilcmd.h postgresql.5/src/include/parser/parse_utilcmd.h
*** postgresql.4/src/include/parser/parse_utilcmd.h 2011-01-04 15:13:16.163549374 +0100
--- postgresql.5/src/include/parser/parse_utilcmd.h 2011-08-02 14:07:24.365033441 +0200
*************** extern void transformRuleStmt(RuleStmt *
*** 25,28 ****
--- 25,31 ----
List **actions, Node **whereClause);
extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
+ extern ExtraStatStmt *transformExtraStatistics(ExtraStatStmt *stmt,
+ const char *queryString);
+
#endif /* PARSE_UTILCMD_H */