alter-column-order.patch
application/octet-stream
Filename: alter-column-order.patch
Type: application/octet-stream
Part: 0
Message:
sorting table columns
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/access/common/tupdesc.c | 85 | 0 |
| src/backend/bootstrap/bootstrap.c | 3 | 0 |
| src/backend/catalog/genbki.pl | 4 | 0 |
| src/backend/catalog/heap.c | 23 | 0 |
| src/backend/executor/execQual.c | 1 | 0 |
| src/backend/executor/execTuples.c | 3 | 0 |
| src/backend/executor/functions.c | 4 | 0 |
| src/backend/nodes/copyfuncs.c | 3 | 0 |
| src/backend/nodes/equalfuncs.c | 2 | 0 |
| src/backend/nodes/makefuncs.c | 5 | 0 |
| src/backend/nodes/outfuncs.c | 25 | 0 |
| src/backend/nodes/readfuncs.c | 3 | 0 |
| src/backend/optimizer/prep/prepjointree.c | 1 | 0 |
| src/backend/optimizer/util/plancat.c | 6 | 0 |
| src/backend/parser/analyze.c | 2 | 0 |
| src/backend/parser/parse_clause.c | 2 | 0 |
| src/backend/parser/parse_coerce.c | 1 | 0 |
| src/backend/parser/parse_relation.c | 46 | 0 |
| src/backend/parser/parse_target.c | 6 | 0 |
| src/backend/rewrite/rewriteManip.c | 1 | 0 |
| src/include/access/tupdesc.h | 12 | 0 |
| src/include/catalog/pg_attribute.h | 37 | 0 |
| src/include/catalog/pg_class.h | 1 | 0 |
| src/include/nodes/parsenodes.h | 1 | 0 |
| src/include/nodes/primnodes.h | 2 | 0 |
| src/include/parser/parse_relation.h | 2 | 0 |
*** a/src/backend/access/common/tupdesc.c
--- b/src/backend/access/common/tupdesc.c
***************
*** 22,27 ****
--- 22,28 ----
#include "catalog/pg_type.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+ #include "utils/memutils.h"
#include "utils/resowner.h"
#include "utils/syscache.h"
***************
*** 84,89 **** CreateTemplateTupleDesc(int natts, bool hasoid)
--- 85,91 ----
* Initialize other fields of the tupdesc.
*/
desc->natts = natts;
+ desc->logattrs = NULL;
desc->constr = NULL;
desc->tdtypeid = RECORDOID;
desc->tdtypmod = -1;
***************
*** 117,122 **** CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
--- 119,125 ----
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
desc->attrs = attrs;
desc->natts = natts;
+ desc->logattrs = NULL;
desc->constr = NULL;
desc->tdtypeid = RECORDOID;
desc->tdtypmod = -1;
***************
*** 151,156 **** CreateTupleDescCopy(TupleDesc tupdesc)
--- 154,161 ----
desc->tdtypeid = tupdesc->tdtypeid;
desc->tdtypmod = tupdesc->tdtypmod;
+ Assert(desc->logattrs == NULL);
+
return desc;
}
***************
*** 256,261 **** FreeTupleDesc(TupleDesc tupdesc)
--- 261,269 ----
pfree(tupdesc->constr);
}
+ if (tupdesc->logattrs)
+ pfree(tupdesc->logattrs);
+
pfree(tupdesc);
}
***************
*** 300,306 **** DecrTupleDescRefCount(TupleDesc tupdesc)
* Note: we deliberately do not check the attrelid and tdtypmod fields.
* This allows typcache.c to use this routine to see if a cached record type
* matches a requested type, and is harmless for relcache.c's uses.
! * We don't compare tdrefcount, either.
*/
bool
equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
--- 308,314 ----
* Note: we deliberately do not check the attrelid and tdtypmod fields.
* This allows typcache.c to use this routine to see if a cached record type
* matches a requested type, and is harmless for relcache.c's uses.
! * We don't compare tdrefcount nor logattrs, either.
*/
bool
equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
***************
*** 341,346 **** equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
--- 349,361 ----
return false;
if (attr1->attlen != attr2->attlen)
return false;
+ if (attr1->attphysnum != attr2->attphysnum)
+ return false;
+ /* intentionally do not compare attlognum */
+ #if 0
+ if (attr1->attlognum != attr2->attlognum)
+ return false;
+ #endif
if (attr1->attndims != attr2->attndims)
return false;
if (attr1->atttypmod != attr2->atttypmod)
***************
*** 476,481 **** TupleDescInitEntry(TupleDesc desc,
--- 491,498 ----
att->atttypmod = typmod;
att->attnum = attributeNumber;
+ att->attphysnum = attributeNumber;
+ att->attlognum = attributeNumber;
att->attndims = attdim;
att->attnotnull = false;
***************
*** 521,526 **** TupleDescInitEntryCollation(TupleDesc desc,
--- 538,564 ----
desc->attrs[attributeNumber - 1]->attcollation = collationid;
}
+ /*
+ * TupleDescInitEntryLognum
+ *
+ * Assign a nondefault lognum to a previously initialized tuple descriptor
+ * entry.
+ */
+ void
+ TupleDescInitEntryLognum(TupleDesc desc,
+ AttrNumber attributeNumber,
+ int attlognum)
+ {
+ /*
+ * sanity checks
+ */
+ AssertArg(PointerIsValid(desc));
+ AssertArg(attributeNumber >= 1);
+ AssertArg(attributeNumber <= desc->natts);
+
+ desc->attrs[attributeNumber - 1]->attlognum = attlognum;
+ }
+
/*
* BuildDescForRelation
***************
*** 607,612 **** BuildDescForRelation(List *schema)
--- 645,652 ----
desc->constr = NULL;
}
+ Assert(desc->logattrs == NULL);
+
return desc;
}
***************
*** 667,671 **** BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
--- 707,755 ----
TupleDescInitEntryCollation(desc, attnum, attcollation);
}
+ Assert(desc->logattrs == NULL);
return desc;
}
+
+ /*
+ * qsort callback for TupleDescGetSortedAttrs
+ */
+ static int
+ cmplognum(const void *attr1, const void *attr2)
+ {
+ Form_pg_attribute att1 = *(Form_pg_attribute *) attr1;
+ Form_pg_attribute att2 = *(Form_pg_attribute *) attr2;
+
+ if (att1->attlognum < att2->attlognum)
+ return -1;
+ if (att1->attlognum > att2->attlognum)
+ return 1;
+ return 0;
+ }
+
+ /*
+ * Return the array of attrs sorted by logical position
+ */
+ Form_pg_attribute *
+ TupleDescGetSortedAttrs(TupleDesc desc)
+ {
+ if (desc->logattrs == NULL)
+ {
+ Form_pg_attribute *attrs;
+
+ /*
+ * logattrs must be allocated in the same memcxt as the tupdesc it
+ * belongs to, so that it isn't reset ahead of time.
+ */
+ attrs = MemoryContextAlloc(GetMemoryChunkContext(desc),
+ sizeof(Form_pg_attribute) * desc->natts);
+ memcpy(attrs, desc->attrs,
+ sizeof(Form_pg_attribute) * desc->natts);
+
+ qsort(attrs, desc->natts, sizeof(Form_pg_attribute), cmplognum);
+
+ desc->logattrs = attrs;
+ }
+
+ return desc->logattrs;
+ }
*** a/src/backend/bootstrap/bootstrap.c
--- b/src/backend/bootstrap/bootstrap.c
***************
*** 703,709 **** DefineAttr(char *name, char *type, int attnum)
namestrcpy(&attrtypes[attnum]->attname, name);
elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
! attrtypes[attnum]->attnum = attnum + 1; /* fillatt */
typeoid = gettype(type);
--- 703,711 ----
namestrcpy(&attrtypes[attnum]->attname, name);
elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
! attrtypes[attnum]->attnum = attnum + 1;
! attrtypes[attnum]->attphysnum = attnum + 1;
! attrtypes[attnum]->attlognum = attnum + 1;
typeoid = gettype(type);
*** a/src/backend/catalog/genbki.pl
--- b/src/backend/catalog/genbki.pl
***************
*** 190,195 **** foreach my $catname ( @{ $catalogs->{names} } )
--- 190,197 ----
$attnum++;
my $row = emit_pgattr_row($table_name, $attr, $priornotnull);
$row->{attnum} = $attnum;
+ $row->{attphysnum} = $attnum;
+ $row->{attlognum} = $attnum;
$row->{attstattarget} = '-1';
$priornotnull &= ($row->{attnotnull} eq 't');
***************
*** 225,230 **** foreach my $catname ( @{ $catalogs->{names} } )
--- 227,234 ----
$attnum--;
my $row = emit_pgattr_row($table_name, $attr, 1);
$row->{attnum} = $attnum;
+ $row->{attphysnum} = $attnum;
+ $row->{attlognum} = $attnum;
$row->{attstattarget} = '0';
# some catalogs don't have oids
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 127,163 **** static List *insert_ordered_unique_oid(List *list, Oid datum);
static FormData_pg_attribute a1 = {
0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
! SelfItemPointerAttributeNumber, 0, -1, -1,
false, 'p', 's', true, false, false, true, 0
};
static FormData_pg_attribute a2 = {
0, {"oid"}, OIDOID, 0, sizeof(Oid),
! ObjectIdAttributeNumber, 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a3 = {
0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
! MinTransactionIdAttributeNumber, 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a4 = {
0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
! MinCommandIdAttributeNumber, 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a5 = {
0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
! MaxTransactionIdAttributeNumber, 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a6 = {
0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
! MaxCommandIdAttributeNumber, 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
--- 127,175 ----
static FormData_pg_attribute a1 = {
0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
! SelfItemPointerAttributeNumber, SelfItemPointerAttributeNumber,
! SelfItemPointerAttributeNumber,
! 0, -1, -1,
false, 'p', 's', true, false, false, true, 0
};
static FormData_pg_attribute a2 = {
0, {"oid"}, OIDOID, 0, sizeof(Oid),
! ObjectIdAttributeNumber, ObjectIdAttributeNumber,
! ObjectIdAttributeNumber,
! 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a3 = {
0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
! MinTransactionIdAttributeNumber, MinTransactionIdAttributeNumber,
! MinTransactionIdAttributeNumber,
! 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a4 = {
0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
! MinCommandIdAttributeNumber, MinCommandIdAttributeNumber,
! MinCommandIdAttributeNumber,
! 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a5 = {
0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
! MaxTransactionIdAttributeNumber, MaxTransactionIdAttributeNumber,
! MaxTransactionIdAttributeNumber,
! 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
static FormData_pg_attribute a6 = {
0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
! MaxCommandIdAttributeNumber, MaxCommandIdAttributeNumber,
! MaxCommandIdAttributeNumber,
! 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
***************
*** 169,175 **** static FormData_pg_attribute a6 = {
*/
static FormData_pg_attribute a7 = {
0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
! TableOidAttributeNumber, 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
--- 181,189 ----
*/
static FormData_pg_attribute a7 = {
0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
! TableOidAttributeNumber, TableOidAttributeNumber,
! TableOidAttributeNumber,
! 0, -1, -1,
true, 'p', 'i', true, false, false, true, 0
};
***************
*** 598,603 **** InsertPgAttributeTuple(Relation pg_attribute_rel,
--- 612,619 ----
values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(new_attribute->attstattarget);
values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(new_attribute->attlen);
values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(new_attribute->attnum);
+ values[Anum_pg_attribute_attphysnum - 1] = Int16GetDatum(new_attribute->attphysnum);
+ values[Anum_pg_attribute_attlognum - 1] = Int16GetDatum(new_attribute->attlognum);
values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(new_attribute->attndims);
values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(new_attribute->attcacheoff);
values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(new_attribute->atttypmod);
*** a/src/backend/executor/execQual.c
--- b/src/backend/executor/execQual.c
***************
*** 4638,4644 **** ExecInitExpr(Expr *node, PlanState *parent)
}
/* Set up evaluation, skipping any deleted columns */
Assert(list_length(rowexpr->args) <= rstate->tupdesc->natts);
! attrs = rstate->tupdesc->attrs;
i = 0;
foreach(l, rowexpr->args)
{
--- 4638,4644 ----
}
/* Set up evaluation, skipping any deleted columns */
Assert(list_length(rowexpr->args) <= rstate->tupdesc->natts);
! attrs = TupleDescGetSortedAttrs(rstate->tupdesc);
i = 0;
foreach(l, rowexpr->args)
{
*** a/src/backend/executor/execTuples.c
--- b/src/backend/executor/execTuples.c
***************
*** 945,950 **** ExecTypeFromTLInternal(List *targetList, bool hasoid, bool skipjunk)
--- 945,953 ----
TupleDescInitEntryCollation(typeInfo,
cur_resno,
exprCollation((Node *) tle->expr));
+ TupleDescInitEntryLognum(typeInfo,
+ cur_resno,
+ tle->resoriglogcol);
cur_resno++;
}
*** a/src/backend/executor/functions.c
--- b/src/backend/executor/functions.c
***************
*** 1401,1406 **** check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
--- 1401,1407 ----
{
/* Returns a rowtype */
TupleDesc tupdesc;
+ Form_pg_attribute *attrs;
int tupnatts; /* physical number of columns in tuple */
int tuplogcols; /* # of nondeleted columns in tuple */
int colindex; /* physical column index */
***************
*** 1465,1470 **** check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
--- 1466,1472 ----
* result columns if the caller asked for that.
*/
tupnatts = tupdesc->natts;
+ attrs = TupleDescGetSortedAttrs(tupdesc);
tuplogcols = 0; /* we'll count nondeleted cols as we go */
colindex = 0;
newtlist = NIL; /* these are only used if modifyTargetList */
***************
*** 1493,1499 **** check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
errmsg("return type mismatch in function declared to return %s",
format_type_be(rettype)),
errdetail("Final statement returns too many columns.")));
! attr = tupdesc->attrs[colindex - 1];
if (attr->attisdropped && modifyTargetList)
{
Expr *null_expr;
--- 1495,1501 ----
errmsg("return type mismatch in function declared to return %s",
format_type_be(rettype)),
errdetail("Final statement returns too many columns.")));
! attr = attrs[colindex - 1];
if (attr->attisdropped && modifyTargetList)
{
Expr *null_expr;
***************
*** 1550,1556 **** check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
/* remaining columns in tupdesc had better all be dropped */
for (colindex++; colindex <= tupnatts; colindex++)
{
! if (!tupdesc->attrs[colindex - 1]->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("return type mismatch in function declared to return %s",
--- 1552,1558 ----
/* remaining columns in tupdesc had better all be dropped */
for (colindex++; colindex <= tupnatts; colindex++)
{
! if (!attrs[colindex - 1]->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("return type mismatch in function declared to return %s",
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
***************
*** 1063,1068 **** _copyVar(Var *from)
--- 1063,1069 ----
COPY_SCALAR_FIELD(varno);
COPY_SCALAR_FIELD(varattno);
+ COPY_SCALAR_FIELD(varlogno);
COPY_SCALAR_FIELD(vartype);
COPY_SCALAR_FIELD(vartypmod);
COPY_SCALAR_FIELD(varcollid);
***************
*** 1762,1767 **** _copyTargetEntry(TargetEntry *from)
--- 1763,1769 ----
COPY_SCALAR_FIELD(ressortgroupref);
COPY_SCALAR_FIELD(resorigtbl);
COPY_SCALAR_FIELD(resorigcol);
+ COPY_SCALAR_FIELD(resoriglogcol);
COPY_SCALAR_FIELD(resjunk);
return newnode;
***************
*** 1964,1969 **** _copyRangeTblEntry(RangeTblEntry *from)
--- 1966,1972 ----
COPY_SCALAR_FIELD(rtekind);
COPY_SCALAR_FIELD(relid);
COPY_SCALAR_FIELD(relkind);
+ COPY_NODE_FIELD(lognums);
COPY_NODE_FIELD(subquery);
COPY_SCALAR_FIELD(jointype);
COPY_NODE_FIELD(joinaliasvars);
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
***************
*** 136,141 **** _equalVar(Var *a, Var *b)
--- 136,142 ----
{
COMPARE_SCALAR_FIELD(varno);
COMPARE_SCALAR_FIELD(varattno);
+ /* intentially do not compare varlogno */
COMPARE_SCALAR_FIELD(vartype);
COMPARE_SCALAR_FIELD(vartypmod);
COMPARE_SCALAR_FIELD(varcollid);
***************
*** 740,745 **** _equalTargetEntry(TargetEntry *a, TargetEntry *b)
--- 741,747 ----
COMPARE_SCALAR_FIELD(ressortgroupref);
COMPARE_SCALAR_FIELD(resorigtbl);
COMPARE_SCALAR_FIELD(resorigcol);
+ /* intentionally do not compare resoriglogcol */
COMPARE_SCALAR_FIELD(resjunk);
return true;
*** a/src/backend/nodes/makefuncs.c
--- b/src/backend/nodes/makefuncs.c
***************
*** 88,94 **** makeVar(Index varno,
var->varnoold = varno;
var->varoattno = varattno;
! /* Likewise, we just set location to "unknown" here */
var->location = -1;
return var;
--- 88,97 ----
var->varnoold = varno;
var->varoattno = varattno;
! /*
! * Likewise, we just set varlogno to Invalid and location to "unknown" here
! */
! var->varlogno = InvalidAttrNumber;
var->location = -1;
return var;
***************
*** 228,233 **** makeTargetEntry(Expr *expr,
--- 231,237 ----
tle->ressortgroupref = 0;
tle->resorigtbl = InvalidOid;
tle->resorigcol = 0;
+ tle->resoriglogcol = 0;
tle->resjunk = resjunk;
*** a/src/backend/nodes/outfuncs.c
--- b/src/backend/nodes/outfuncs.c
***************
*** 909,914 **** _outVar(StringInfo str, Var *node)
--- 909,915 ----
WRITE_UINT_FIELD(varno);
WRITE_INT_FIELD(varattno);
+ WRITE_INT_FIELD(varlogno);
WRITE_OID_FIELD(vartype);
WRITE_INT_FIELD(vartypmod);
WRITE_OID_FIELD(varcollid);
***************
*** 1422,1431 **** _outTargetEntry(StringInfo str, TargetEntry *node)
--- 1423,1449 ----
WRITE_UINT_FIELD(ressortgroupref);
WRITE_OID_FIELD(resorigtbl);
WRITE_INT_FIELD(resorigcol);
+ WRITE_INT_FIELD(resoriglogcol);
WRITE_BOOL_FIELD(resjunk);
}
static void
+ _outGenericExprState(StringInfo str, GenericExprState *node)
+ {
+ WRITE_NODE_TYPE("GENERICEXPRSTATE");
+
+ WRITE_NODE_FIELD(arg);
+ }
+
+ static void
+ _outExprState(StringInfo str, ExprState *node)
+ {
+ WRITE_NODE_TYPE("EXPRSTATE");
+
+ WRITE_NODE_FIELD(expr);
+ }
+
+ static void
_outRangeTblRef(StringInfo str, RangeTblRef *node)
{
WRITE_NODE_TYPE("RANGETBLREF");
***************
*** 2318,2323 **** _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
--- 2336,2342 ----
case RTE_RELATION:
WRITE_OID_FIELD(relid);
WRITE_CHAR_FIELD(relkind);
+ WRITE_NODE_FIELD(lognums);
break;
case RTE_SUBQUERY:
WRITE_NODE_FIELD(subquery);
***************
*** 2942,2947 **** _outNode(StringInfo str, void *obj)
--- 2961,2972 ----
case T_FromExpr:
_outFromExpr(str, obj);
break;
+ case T_GenericExprState:
+ _outGenericExprState(str, obj);
+ break;
+ case T_ExprState:
+ _outExprState(str, obj);
+ break;
case T_Path:
_outPath(str, obj);
*** a/src/backend/nodes/readfuncs.c
--- b/src/backend/nodes/readfuncs.c
***************
*** 409,414 **** _readVar(void)
--- 409,415 ----
READ_UINT_FIELD(varno);
READ_INT_FIELD(varattno);
+ READ_INT_FIELD(varlogno);
READ_OID_FIELD(vartype);
READ_INT_FIELD(vartypmod);
READ_OID_FIELD(varcollid);
***************
*** 1114,1119 **** _readTargetEntry(void)
--- 1115,1121 ----
READ_UINT_FIELD(ressortgroupref);
READ_OID_FIELD(resorigtbl);
READ_INT_FIELD(resorigcol);
+ READ_INT_FIELD(resoriglogcol);
READ_BOOL_FIELD(resjunk);
READ_DONE();
***************
*** 1189,1194 **** _readRangeTblEntry(void)
--- 1191,1197 ----
case RTE_RELATION:
READ_OID_FIELD(relid);
READ_CHAR_FIELD(relkind);
+ READ_NODE_FIELD(lognums);
break;
case RTE_SUBQUERY:
READ_NODE_FIELD(subquery);
*** a/src/backend/optimizer/prep/prepjointree.c
--- b/src/backend/optimizer/prep/prepjointree.c
***************
*** 1343,1349 **** pullup_replace_vars_callback(Var *var,
* expansion with varlevelsup = 0, and then adjust if needed.
*/
expandRTE(rcon->target_rte,
! var->varno, 0 /* not varlevelsup */ , var->location,
(var->vartype != RECORDOID),
&colnames, &fields);
/* Adjust the generated per-field Vars, but don't insert PHVs */
--- 1343,1349 ----
* expansion with varlevelsup = 0, and then adjust if needed.
*/
expandRTE(rcon->target_rte,
! var->varno, 0 /* not varlevelsup */ , var->location, false,
(var->vartype != RECORDOID),
&colnames, &fields);
/* Adjust the generated per-field Vars, but don't insert PHVs */
*** a/src/backend/optimizer/util/plancat.c
--- b/src/backend/optimizer/util/plancat.c
***************
*** 850,855 **** build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
--- 850,856 ----
for (attrno = 1; attrno <= numattrs; attrno++)
{
Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1];
+ TargetEntry *te;
if (att_tup->attisdropped)
{
***************
*** 864,875 **** build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
att_tup->atttypmod,
att_tup->attcollation,
0);
! tlist = lappend(tlist,
! makeTargetEntry((Expr *) var,
! attrno,
! NULL,
! false));
}
heap_close(relation, NoLock);
--- 865,875 ----
att_tup->atttypmod,
att_tup->attcollation,
0);
+ var->varlogno = att_tup->attlognum;
+ te = makeTargetEntry((Expr *) var, attrno, NULL, false);
+ te->resoriglogcol = var->varlogno;
! tlist = lappend(tlist, te);
}
heap_close(relation, NoLock);
***************
*** 899,905 **** build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
case RTE_VALUES:
case RTE_CTE:
/* Not all of these can have dropped cols, but share code anyway */
! expandRTE(rte, varno, 0, -1, true /* include dropped */ ,
NULL, &colvars);
foreach(l, colvars)
{
--- 899,905 ----
case RTE_VALUES:
case RTE_CTE:
/* Not all of these can have dropped cols, but share code anyway */
! expandRTE(rte, varno, 0, -1, true /* include dropped */ , false,
NULL, &colvars);
foreach(l, colvars)
{
*** a/src/backend/parser/analyze.c
--- b/src/backend/parser/analyze.c
***************
*** 635,641 **** transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
/*
* Generate list of Vars referencing the RTE
*/
! expandRTE(rte, rtr->rtindex, 0, -1, false, NULL, &exprList);
}
else
{
--- 635,641 ----
/*
* Generate list of Vars referencing the RTE
*/
! expandRTE(rte, rtr->rtindex, 0, -1, false, false, NULL, &exprList);
}
else
{
***************
*** 1163,1169 **** transformValuesClause(ParseState *pstate, SelectStmt *stmt)
* Generate a targetlist as though expanding "*"
*/
Assert(pstate->p_next_resno == 1);
! qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0, -1);
/*
* The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
--- 1163,1169 ----
* Generate a targetlist as though expanding "*"
*/
Assert(pstate->p_next_resno == 1);
! qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0, false, -1);
/*
* The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
*** a/src/backend/parser/parse_clause.c
--- b/src/backend/parser/parse_clause.c
***************
*** 789,797 **** transformFromClauseItem(ParseState *pstate, Node *n,
*
* Note: expandRTE returns new lists, safe for me to modify
*/
! expandRTE(l_rte, l_rtindex, 0, -1, false,
&l_colnames, &l_colvars);
! expandRTE(r_rte, r_rtindex, 0, -1, false,
&r_colnames, &r_colvars);
/*
--- 789,797 ----
*
* Note: expandRTE returns new lists, safe for me to modify
*/
! expandRTE(l_rte, l_rtindex, 0, -1, false, true,
&l_colnames, &l_colvars);
! expandRTE(r_rte, r_rtindex, 0, -1, false, true,
&r_colnames, &r_colvars);
/*
*** a/src/backend/parser/parse_coerce.c
--- b/src/backend/parser/parse_coerce.c
***************
*** 897,903 **** coerce_record_to_complex(ParseState *pstate, Node *node,
RangeTblEntry *rte;
rte = GetRTEByRangeTablePosn(pstate, rtindex, sublevels_up);
! expandRTE(rte, rtindex, sublevels_up, vlocation, false,
NULL, &args);
}
else
--- 897,903 ----
RangeTblEntry *rte;
rte = GetRTEByRangeTablePosn(pstate, rtindex, sublevels_up);
! expandRTE(rte, rtindex, sublevels_up, vlocation, false, false,
NULL, &args);
}
else
*** a/src/backend/parser/parse_relation.c
--- b/src/backend/parser/parse_relation.c
***************
*** 40,50 **** static void markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
int rtindex, AttrNumber col);
static void expandRelation(Oid relid, Alias *eref,
int rtindex, int sublevels_up,
! int location, bool include_dropped,
List **colnames, List **colvars);
static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
int rtindex, int sublevels_up,
! int location, bool include_dropped,
List **colnames, List **colvars);
static int specialAttNum(const char *attname);
--- 40,50 ----
int rtindex, AttrNumber col);
static void expandRelation(Oid relid, Alias *eref,
int rtindex, int sublevels_up,
! int location, bool include_dropped, bool logical_sort,
List **colnames, List **colvars);
static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
int rtindex, int sublevels_up,
! int location, bool include_dropped, bool logical_sort,
List **colnames, List **colvars);
static int specialAttNum(const char *attname);
***************
*** 442,447 **** GetCTEForRTE(ParseState *pstate, RangeTblEntry *rte, int rtelevelsup)
--- 442,453 ----
return NULL; /* keep compiler quiet */
}
+ static int16
+ get_attnum_by_lognum(RangeTblEntry *rte, int16 attlognum)
+ {
+ return list_nth_int(rte->lognums, attlognum - 1);
+ }
+
/*
* scanRTEForColumn
* Search the column names of a single RTE for the given name.
***************
*** 484,489 **** scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
--- 490,497 ----
errmsg("column reference \"%s\" is ambiguous",
colname),
parser_errposition(pstate, location)));
+ if (rte->lognums)
+ attnum = get_attnum_by_lognum(rte, attnum);
var = make_var(pstate, rte, attnum, location);
/* Require read access to the column */
markVarForSelectPriv(pstate, var, rte);
***************
*** 699,711 **** markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte)
* eref->colnames is filled in. Also, alias->colnames is rebuilt to insert
* empty strings for any dropped columns, so that it will be one-to-one with
* physical column numbers.
*/
static void
! buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref)
{
int maxattrs = tupdesc->natts;
ListCell *aliaslc;
int numaliases;
int varattno;
int numdropped = 0;
--- 707,724 ----
* eref->colnames is filled in. Also, alias->colnames is rebuilt to insert
* empty strings for any dropped columns, so that it will be one-to-one with
* physical column numbers.
+ *
+ * If lognums is not NULL, it will be filled with a map from logical column
+ * numbers to attnum; that way, the nth element of eref->colnames corresponds
+ * to the attnum found in the nth element of lognums.
*/
static void
! buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref, List **lognums)
{
int maxattrs = tupdesc->natts;
ListCell *aliaslc;
int numaliases;
+ Form_pg_attribute *attrs;
int varattno;
int numdropped = 0;
***************
*** 724,732 **** buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref)
numaliases = 0;
}
for (varattno = 0; varattno < maxattrs; varattno++)
{
! Form_pg_attribute attr = tupdesc->attrs[varattno];
Value *attrname;
if (attr->attisdropped)
--- 737,747 ----
numaliases = 0;
}
+ attrs = TupleDescGetSortedAttrs(tupdesc);
+
for (varattno = 0; varattno < maxattrs; varattno++)
{
! Form_pg_attribute attr = attrs[varattno];
Value *attrname;
if (attr->attisdropped)
***************
*** 751,756 **** buildRelationAliases(TupleDesc tupdesc, Alias *alias, Alias *eref)
--- 766,774 ----
}
eref->colnames = lappend(eref->colnames, attrname);
+
+ if (lognums)
+ *lognums = lappend_int(*lognums, attr->attnum);
}
/* Too many user-supplied aliases? */
***************
*** 907,913 **** addRangeTableEntry(ParseState *pstate,
* and/or actual column names.
*/
rte->eref = makeAlias(refname, NIL);
! buildRelationAliases(rel->rd_att, alias, rte->eref);
/*
* Drop the rel refcount, but keep the access lock till end of transaction
--- 925,931 ----
* and/or actual column names.
*/
rte->eref = makeAlias(refname, NIL);
! buildRelationAliases(rel->rd_att, alias, rte->eref, &rte->lognums);
/*
* Drop the rel refcount, but keep the access lock till end of transaction
***************
*** 970,976 **** addRangeTableEntryForRelation(ParseState *pstate,
* and/or actual column names.
*/
rte->eref = makeAlias(refname, NIL);
! buildRelationAliases(rel->rd_att, alias, rte->eref);
/*----------
* Flags:
--- 988,994 ----
* and/or actual column names.
*/
rte->eref = makeAlias(refname, NIL);
! buildRelationAliases(rel->rd_att, alias, rte->eref, &rte->lognums);
/*----------
* Flags:
***************
*** 1145,1151 **** addRangeTableEntryForFunction(ParseState *pstate,
/* Composite data type, e.g. a table's row type */
Assert(tupdesc);
/* Build the column alias list */
! buildRelationAliases(tupdesc, alias, eref);
}
else if (functypclass == TYPEFUNC_SCALAR)
{
--- 1163,1169 ----
/* Composite data type, e.g. a table's row type */
Assert(tupdesc);
/* Build the column alias list */
! buildRelationAliases(tupdesc, alias, eref, NULL);
}
else if (functypclass == TYPEFUNC_SCALAR)
{
***************
*** 1552,1564 **** addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
* values to use in the created Vars. Ordinarily rtindex should match the
* actual position of the RTE in its rangetable.
*
* The output lists go into *colnames and *colvars.
* If only one of the two kinds of output list is needed, pass NULL for the
* output pointer for the unwanted one.
*/
void
expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
! int location, bool include_dropped,
List **colnames, List **colvars)
{
int varattno;
--- 1570,1585 ----
* values to use in the created Vars. Ordinarily rtindex should match the
* actual position of the RTE in its rangetable.
*
+ * If logical_sort is true, then the resulting lists are sorted by logical
+ * column number (attlognum); otherwise use regular attnum.
+ *
* The output lists go into *colnames and *colvars.
* If only one of the two kinds of output list is needed, pass NULL for the
* output pointer for the unwanted one.
*/
void
expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
! int location, bool include_dropped, bool logical_sort,
List **colnames, List **colvars)
{
int varattno;
***************
*** 1573,1580 **** expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
case RTE_RELATION:
/* Ordinary relation RTE */
expandRelation(rte->relid, rte->eref,
! rtindex, sublevels_up, location,
! include_dropped, colnames, colvars);
break;
case RTE_SUBQUERY:
{
--- 1594,1601 ----
case RTE_RELATION:
/* Ordinary relation RTE */
expandRelation(rte->relid, rte->eref,
! rtindex, sublevels_up, location, include_dropped,
! logical_sort, colnames, colvars);
break;
case RTE_SUBQUERY:
{
***************
*** 1632,1638 **** expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
/* Composite data type, e.g. a table's row type */
Assert(tupdesc);
expandTupleDesc(tupdesc, rte->eref,
! rtindex, sublevels_up, location,
include_dropped, colnames, colvars);
}
else if (functypclass == TYPEFUNC_SCALAR)
--- 1653,1659 ----
/* Composite data type, e.g. a table's row type */
Assert(tupdesc);
expandTupleDesc(tupdesc, rte->eref,
! rtindex, sublevels_up, location, false,
include_dropped, colnames, colvars);
}
else if (functypclass == TYPEFUNC_SCALAR)
***************
*** 1844,1850 **** expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
*/
static void
expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
! int location, bool include_dropped,
List **colnames, List **colvars)
{
Relation rel;
--- 1865,1871 ----
*/
static void
expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
! int location, bool include_dropped, bool logical_sort,
List **colnames, List **colvars)
{
Relation rel;
***************
*** 1852,1858 **** expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
/* Get the tupledesc and turn it over to expandTupleDesc */
rel = relation_open(relid, AccessShareLock);
expandTupleDesc(rel->rd_att, eref, rtindex, sublevels_up,
! location, include_dropped,
colnames, colvars);
relation_close(rel, AccessShareLock);
}
--- 1873,1879 ----
/* Get the tupledesc and turn it over to expandTupleDesc */
rel = relation_open(relid, AccessShareLock);
expandTupleDesc(rel->rd_att, eref, rtindex, sublevels_up,
! location, include_dropped, logical_sort,
colnames, colvars);
relation_close(rel, AccessShareLock);
}
***************
*** 1863,1878 **** expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
static void
expandTupleDesc(TupleDesc tupdesc, Alias *eref,
int rtindex, int sublevels_up,
! int location, bool include_dropped,
List **colnames, List **colvars)
{
int maxattrs = tupdesc->natts;
int numaliases = list_length(eref->colnames);
int varattno;
for (varattno = 0; varattno < maxattrs; varattno++)
{
! Form_pg_attribute attr = tupdesc->attrs[varattno];
if (attr->attisdropped)
{
--- 1884,1905 ----
static void
expandTupleDesc(TupleDesc tupdesc, Alias *eref,
int rtindex, int sublevels_up,
! int location, bool include_dropped, bool logical_sort,
List **colnames, List **colvars)
{
int maxattrs = tupdesc->natts;
int numaliases = list_length(eref->colnames);
int varattno;
+ Form_pg_attribute *attrs;
+
+ if (logical_sort)
+ attrs = TupleDescGetSortedAttrs(tupdesc);
+ else
+ attrs = tupdesc->attrs;
for (varattno = 0; varattno < maxattrs; varattno++)
{
! Form_pg_attribute attr = attrs[varattno];
if (attr->attisdropped)
{
***************
*** 1912,1917 **** expandTupleDesc(TupleDesc tupdesc, Alias *eref,
--- 1939,1945 ----
attr->atttypid, attr->atttypmod,
attr->attcollation,
sublevels_up);
+ varnode->varlogno = attr->attlognum;
varnode->location = location;
*colvars = lappend(*colvars, varnode);
***************
*** 1931,1937 **** expandTupleDesc(TupleDesc tupdesc, Alias *eref,
*/
List *
expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
! int rtindex, int sublevels_up, int location)
{
List *names,
*vars;
--- 1959,1965 ----
*/
List *
expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
! int rtindex, int sublevels_up, bool logical_sort, int location)
{
List *names,
*vars;
***************
*** 1939,1945 **** expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
*var;
List *te_list = NIL;
! expandRTE(rte, rtindex, sublevels_up, location, false,
&names, &vars);
/*
--- 1967,1973 ----
*var;
List *te_list = NIL;
! expandRTE(rte, rtindex, sublevels_up, location, false, logical_sort,
&names, &vars);
/*
***************
*** 1959,1964 **** expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
--- 1987,1993 ----
(AttrNumber) pstate->p_next_resno++,
label,
false);
+ te->resoriglogcol = varnode->varlogno;
te_list = lappend(te_list, te);
/* Require read access to each column */
*** a/src/backend/parser/parse_target.c
--- b/src/backend/parser/parse_target.c
***************
*** 282,287 **** markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
--- 282,288 ----
/* It's a table or view, report it */
tle->resorigtbl = rte->relid;
tle->resorigcol = attnum;
+ tle->resoriglogcol = var->varlogno;
break;
case RTE_SUBQUERY:
/* Subselect-in-FROM: copy up from the subselect */
***************
*** 1134,1140 **** ExpandAllTables(ParseState *pstate, int location)
target = list_concat(target,
expandRelAttrs(pstate, rte, rtindex, 0,
! location));
}
return target;
--- 1135,1141 ----
target = list_concat(target,
expandRelAttrs(pstate, rte, rtindex, 0,
! true, location));
}
return target;
***************
*** 1189,1202 **** ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
{
/* expandRelAttrs handles permissions marking */
return expandRelAttrs(pstate, rte, rtindex, sublevels_up,
! location);
}
else
{
List *vars;
ListCell *l;
! expandRTE(rte, rtindex, sublevels_up, location, false,
NULL, &vars);
/*
--- 1190,1203 ----
{
/* expandRelAttrs handles permissions marking */
return expandRelAttrs(pstate, rte, rtindex, sublevels_up,
! true, location);
}
else
{
List *vars;
ListCell *l;
! expandRTE(rte, rtindex, sublevels_up, location, false, true,
NULL, &vars);
/*
***************
*** 1304,1309 **** ExpandRowReference(ParseState *pstate, Node *expr,
--- 1305,1311 ----
(AttrNumber) pstate->p_next_resno++,
pstrdup(NameStr(att->attname)),
false);
+ te->resoriglogcol = att->attlognum;
result = lappend(result, te);
}
else
***************
*** 1350,1356 **** expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
*lvar;
int i;
! expandRTE(rte, var->varno, 0, var->location, false,
&names, &vars);
tupleDesc = CreateTemplateTupleDesc(list_length(vars), false);
--- 1352,1358 ----
*lvar;
int i;
! expandRTE(rte, var->varno, 0, var->location, false, false,
&names, &vars);
tupleDesc = CreateTemplateTupleDesc(list_length(vars), false);
*** a/src/backend/rewrite/rewriteManip.c
--- b/src/backend/rewrite/rewriteManip.c
***************
*** 1263,1269 **** ResolveNew_callback(Var *var,
*/
expandRTE(rcon->target_rte,
var->varno, var->varlevelsup, var->location,
! (var->vartype != RECORDOID),
&colnames, &fields);
/* Adjust the generated per-field Vars... */
fields = (List *) replace_rte_variables_mutator((Node *) fields,
--- 1263,1269 ----
*/
expandRTE(rcon->target_rte,
var->varno, var->varlevelsup, var->location,
! (var->vartype != RECORDOID), false,
&colnames, &fields);
/* Adjust the generated per-field Vars... */
fields = (List *) replace_rte_variables_mutator((Node *) fields,
*** a/src/include/access/tupdesc.h
--- b/src/include/access/tupdesc.h
***************
*** 59,64 **** typedef struct tupleConstr
--- 59,69 ----
* row type, or a value >= 0 to allow the rowtype to be looked up in the
* typcache.c type cache.
*
+ * We keep an array of attribute sorted by attlognum. This helps *-expansion.
+ * The array is initially set to NULL, and is only populated on first access;
+ * those wanting to access it should always do it through
+ * TupleDescGetSortedAttrs.
+ *
* Tuple descriptors that live in caches (relcache or typcache, at present)
* are reference-counted: they can be deleted when their reference count goes
* to zero. Tuple descriptors created by the executor need no reference
***************
*** 72,77 **** typedef struct tupleDesc
--- 77,83 ----
int natts; /* number of attributes in the tuple */
Form_pg_attribute *attrs;
/* attrs[N] is a pointer to the description of Attribute Number N+1 */
+ Form_pg_attribute *logattrs; /* array of attributes sorted by attlognum */
TupleConstr *constr; /* constraints, or NULL if none */
Oid tdtypeid; /* composite type ID for tuple type */
int32 tdtypmod; /* typmod for tuple type */
***************
*** 119,126 **** extern void TupleDescInitEntryCollation(TupleDesc desc,
--- 125,138 ----
AttrNumber attributeNumber,
Oid collationid);
+ extern void TupleDescInitEntryLognum(TupleDesc desc,
+ AttrNumber attributeNumber,
+ int attlognum);
+
extern TupleDesc BuildDescForRelation(List *schema);
extern TupleDesc BuildDescFromLists(List *names, List *types, List *typmods, List *collations);
+ extern Form_pg_attribute *TupleDescGetSortedAttrs(TupleDesc desc);
+
#endif /* TUPDESC_H */
*** a/src/include/catalog/pg_attribute.h
--- b/src/include/catalog/pg_attribute.h
***************
*** 63,81 **** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP BKI_WITHOUT_OIDS BKI_ROWTYPE_OID(75) BK
int2 attlen;
/*
! * attnum is the "attribute number" for the attribute: A value that
! * uniquely identifies this attribute within its class. For user
! * attributes, Attribute numbers are greater than 0 and not greater than
! * the number of attributes in the class. I.e. if the Class pg_class says
! * that Class XYZ has 10 attributes, then the user attribute numbers in
! * Class pg_attribute must be 1-10.
*
! * System attributes have attribute numbers less than 0 that are unique
! * within the class, but not constrained to any particular range.
*
* Note that (attnum - 1) is often used as the index to an array.
*/
int2 attnum;
/*
* attndims is the declared number of dimensions, if an array type,
--- 63,92 ----
int2 attlen;
/*
! * We previously had a single "attnum" attribute here, which has been
! * broken up in three parts:
*
! * attnum uniquely identifies the column within its class, throughout its
! * lifetime. For user attributes, Attribute numbers are greater than 0 and
! * not greater than the number of attributes in the class. I.e. if the
! * Class pg_class says that Class XYZ has 10 attributes, then the user
! * attribute numbers in Class pg_attribute must be 1-10. System attributes
! * have attribute numbers less than 0 that are unique within the class, but
! * not constrained to any particular range.
! *
! * attphysnum (physical position) specifies the position in which the
! * column is stored in physical tuples. This might differ from attnum if
! * there are useful optimizations in storage space, for example alignment
! * considerations.
! *
! * attlognum (logical position) specifies the position in which the column
! * is expanded in "SELECT * FROM rel" type queries.
*
* Note that (attnum - 1) is often used as the index to an array.
*/
int2 attnum;
+ int2 attphysnum;
+ int2 attlognum;
/*
* attndims is the declared number of dimensions, if an array type,
***************
*** 182,209 **** typedef FormData_pg_attribute *Form_pg_attribute;
* ----------------
*/
! #define Natts_pg_attribute 21
#define Anum_pg_attribute_attrelid 1
#define Anum_pg_attribute_attname 2
#define Anum_pg_attribute_atttypid 3
#define Anum_pg_attribute_attstattarget 4
#define Anum_pg_attribute_attlen 5
#define Anum_pg_attribute_attnum 6
! #define Anum_pg_attribute_attndims 7
! #define Anum_pg_attribute_attcacheoff 8
! #define Anum_pg_attribute_atttypmod 9
! #define Anum_pg_attribute_attbyval 10
! #define Anum_pg_attribute_attstorage 11
! #define Anum_pg_attribute_attalign 12
! #define Anum_pg_attribute_attnotnull 13
! #define Anum_pg_attribute_atthasdef 14
! #define Anum_pg_attribute_attisdropped 15
! #define Anum_pg_attribute_attislocal 16
! #define Anum_pg_attribute_attinhcount 17
! #define Anum_pg_attribute_attcollation 18
! #define Anum_pg_attribute_attacl 19
! #define Anum_pg_attribute_attoptions 20
! #define Anum_pg_attribute_attfdwoptions 21
/* ----------------
--- 193,222 ----
* ----------------
*/
! #define Natts_pg_attribute 23
#define Anum_pg_attribute_attrelid 1
#define Anum_pg_attribute_attname 2
#define Anum_pg_attribute_atttypid 3
#define Anum_pg_attribute_attstattarget 4
#define Anum_pg_attribute_attlen 5
#define Anum_pg_attribute_attnum 6
! #define Anum_pg_attribute_attphysnum 7
! #define Anum_pg_attribute_attlognum 8
! #define Anum_pg_attribute_attndims 9
! #define Anum_pg_attribute_attcacheoff 10
! #define Anum_pg_attribute_atttypmod 11
! #define Anum_pg_attribute_attbyval 12
! #define Anum_pg_attribute_attstorage 13
! #define Anum_pg_attribute_attalign 14
! #define Anum_pg_attribute_attnotnull 15
! #define Anum_pg_attribute_atthasdef 16
! #define Anum_pg_attribute_attisdropped 17
! #define Anum_pg_attribute_attislocal 18
! #define Anum_pg_attribute_attinhcount 19
! #define Anum_pg_attribute_attcollation 20
! #define Anum_pg_attribute_attacl 21
! #define Anum_pg_attribute_attoptions 22
! #define Anum_pg_attribute_attfdwoptions 23
/* ----------------
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
***************
*** 135,141 **** typedef FormData_pg_class *Form_pg_class;
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ ));
DESCR("");
! DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 21 0 f f f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
DESCR("");
--- 135,141 ----
/* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 0 f f p r 29 0 t f f f f 3 _null_ _null_ ));
DESCR("");
! DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 0 f f p r 23 0 f f f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
DESCR("");
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 701,706 **** typedef struct RangeTblEntry
--- 701,707 ----
*/
Oid relid; /* OID of the relation */
char relkind; /* relation kind (see pg_class.relkind) */
+ List *lognums; /* int list of logical column numbers */
/*
* Fields valid for a subquery RTE (else NULL):
*** a/src/include/nodes/primnodes.h
--- b/src/include/nodes/primnodes.h
***************
*** 142,147 **** typedef struct Var
--- 142,148 ----
* table, or INNER_VAR/OUTER_VAR/INDEX_VAR */
AttrNumber varattno; /* attribute number of this var, or zero for
* all */
+ AttrNumber varlogno; /* logical position of column in table XXX invalid value? */
Oid vartype; /* pg_type OID for the type of this var */
int32 vartypmod; /* pg_attribute typmod value */
Oid varcollid; /* OID of collation, or InvalidOid if none */
***************
*** 1166,1171 **** typedef struct TargetEntry
--- 1167,1173 ----
* clause */
Oid resorigtbl; /* OID of column's source table */
AttrNumber resorigcol; /* column's number in source table */
+ AttrNumber resoriglogcol; /* column's logical number in source table */
bool resjunk; /* set to true to eliminate the attribute from
* final target list */
} TargetEntry;
*** a/src/include/parser/parse_relation.h
--- b/src/include/parser/parse_relation.h
***************
*** 83,92 **** extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
bool addToRelNameSpace, bool addToVarNameSpace);
extern void errorMissingRTE(ParseState *pstate, RangeVar *relation);
extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
! int location, bool include_dropped,
List **colnames, List **colvars);
extern List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
! int rtindex, int sublevels_up, int location);
extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK);
extern Name attnumAttName(Relation rd, int attid);
extern Oid attnumTypeId(Relation rd, int attid);
--- 83,92 ----
bool addToRelNameSpace, bool addToVarNameSpace);
extern void errorMissingRTE(ParseState *pstate, RangeVar *relation);
extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
! int location, bool include_dropped, bool logical_sort,
List **colnames, List **colvars);
extern List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
! int rtindex, int sublevels_up, bool logical_sort, int location);
extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK);
extern Name attnumAttName(Relation rd, int attid);
extern Oid attnumTypeId(Relation rd, int attid);