1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-17 06:41:09 +03:00

ALTER TABLE DROP COLUMN works. Patch by Christopher Kings-Lynne,

code review by Tom Lane.  Remaining issues: functions that take or
return tuple types are likely to break if one drops (or adds!)
a column in the table defining the type.  Need to think about what
to do here.

Along the way: some code review for recent COPY changes; mark system
columns attnotnull = true where appropriate, per discussion a month ago.
This commit is contained in:
Tom Lane
2002-08-02 18:15:10 +00:00
parent 5e6528adf7
commit 38bb77a5d1
44 changed files with 1823 additions and 891 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.39 2002/07/31 17:19:51 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.40 2002/08/02 18:15:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -27,6 +27,7 @@
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/datum.h"
@ -147,7 +148,6 @@ void
analyze_rel(Oid relid, VacuumStmt *vacstmt)
{
Relation onerel;
Form_pg_attribute *attr;
int attr_cnt,
tcnt,
i;
@ -234,9 +234,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
*
* Note that system attributes are never analyzed.
*/
attr = onerel->rd_att->attrs;
attr_cnt = onerel->rd_att->natts;
if (vacstmt->va_cols != NIL)
{
List *le;
@ -248,15 +245,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
{
char *col = strVal(lfirst(le));
for (i = 0; i < attr_cnt; i++)
{
if (namestrcmp(&(attr[i]->attname), col) == 0)
break;
}
if (i >= attr_cnt)
elog(ERROR, "ANALYZE: there is no attribute %s in %s",
col, RelationGetRelationName(onerel));
vacattrstats[tcnt] = examine_attribute(onerel, i + 1);
i = attnameAttNum(onerel, col, false);
vacattrstats[tcnt] = examine_attribute(onerel, i);
if (vacattrstats[tcnt] != NULL)
tcnt++;
}
@ -264,12 +254,13 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
}
else
{
attr_cnt = onerel->rd_att->natts;
vacattrstats = (VacAttrStats **) palloc(attr_cnt *
sizeof(VacAttrStats *));
tcnt = 0;
for (i = 0; i < attr_cnt; i++)
for (i = 1; i <= attr_cnt; i++)
{
vacattrstats[tcnt] = examine_attribute(onerel, i + 1);
vacattrstats[tcnt] = examine_attribute(onerel, i);
if (vacattrstats[tcnt] != NULL)
tcnt++;
}
@ -388,6 +379,10 @@ examine_attribute(Relation onerel, int attnum)
Oid ltopr = InvalidOid;
VacAttrStats *stats;
/* Don't analyze dropped columns */
if (attr->attisdropped)
return NULL;
/* Don't analyze column if user has specified not to */
if (attr->attstattarget == 0)
return NULL;

View File

@ -7,7 +7,7 @@
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.53 2002/07/29 23:46:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.54 2002/08/02 18:15:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -382,8 +382,8 @@ CommentAttribute(List *qualname, char *comment)
attnum = get_attnum(RelationGetRelid(relation), attrname);
if (attnum == InvalidAttrNumber)
elog(ERROR, "\"%s\" is not an attribute of class \"%s\"",
attrname, RelationGetRelationName(relation));
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
RelationGetRelationName(relation), attrname);
/* Create the comment using the relation's oid */

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.161 2002/07/30 16:55:06 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.162 2002/08/02 18:15:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -31,6 +31,7 @@
#include "rewrite/rewriteHandler.h"
#include "libpq/libpq.h"
#include "miscadmin.h"
#include "parser/parse_relation.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
@ -53,13 +54,15 @@ typedef enum CopyReadResult
} CopyReadResult;
/* non-export function prototypes */
static void CopyTo(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
static void CopyFrom(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print);
static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print);
static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print);
static Oid GetInputFunction(Oid type);
static Oid GetTypeElement(Oid type);
static char *CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result);
static void CopyAttributeOut(FILE *fp, char *string, char *delim);
static void CopyCheckAttlist(Relation rel, List *attlist);
static List *CopyGetAttnums(Relation rel, List *attnamelist);
static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0";
@ -275,7 +278,8 @@ DoCopy(const CopyStmt *stmt)
bool is_from = stmt->is_from;
bool pipe = (stmt->filename == NULL);
List *option;
List *attlist = stmt->attlist;
List *attnamelist = stmt->attlist;
List *attnumlist;
bool binary = false;
bool oids = false;
char *delim = NULL;
@ -373,6 +377,11 @@ DoCopy(const CopyStmt *stmt)
elog(ERROR, "COPY: table \"%s\" does not have OIDs",
RelationGetRelationName(rel));
/*
* Generate or convert list of attributes to process
*/
attnumlist = CopyGetAttnums(rel, attnamelist);
/*
* Set up variables to avoid per-attribute overhead.
*/
@ -382,26 +391,6 @@ DoCopy(const CopyStmt *stmt)
server_encoding = GetDatabaseEncoding();
#endif
if (attlist == NIL)
{
/* get list of attributes in the relation */
TupleDesc desc = RelationGetDescr(rel);
int i;
for (i = 0; i < desc->natts; ++i)
{
Ident *id = makeNode(Ident);
id->name = NameStr(desc->attrs[i]->attname);
attlist = lappend(attlist,id);
}
}
else
{
if (binary)
elog(ERROR,"COPY: BINARY format cannot be used with specific column list");
CopyCheckAttlist(rel, attlist);
}
if (is_from)
{ /* copy from file to database */
if (rel->rd_rel->relkind != RELKIND_RELATION)
@ -442,10 +431,10 @@ DoCopy(const CopyStmt *stmt)
if (S_ISDIR(st.st_mode))
{
FreeFile(fp);
elog(ERROR, "COPY: %s is a directory.", filename);
elog(ERROR, "COPY: %s is a directory", filename);
}
}
CopyFrom(rel, attlist, binary, oids, fp, delim, null_print);
CopyFrom(rel, attnumlist, binary, oids, fp, delim, null_print);
}
else
{ /* copy from database to file */
@ -483,7 +472,7 @@ DoCopy(const CopyStmt *stmt)
*/
if (filename[0] != '/')
elog(ERROR, "Relative path not allowed for server side"
" COPY command.");
" COPY command");
oumask = umask((mode_t) 022);
fp = AllocateFile(filename, PG_BINARY_W);
@ -498,10 +487,10 @@ DoCopy(const CopyStmt *stmt)
if (S_ISDIR(st.st_mode))
{
FreeFile(fp);
elog(ERROR, "COPY: %s is a directory.", filename);
elog(ERROR, "COPY: %s is a directory", filename);
}
}
CopyTo(rel, attlist, binary, oids, fp, delim, null_print);
CopyTo(rel, attnumlist, binary, oids, fp, delim, null_print);
}
if (!pipe)
@ -529,14 +518,14 @@ DoCopy(const CopyStmt *stmt)
* Copy from relation TO file.
*/
static void
CopyTo(Relation rel, List *attlist, bool binary, bool oids,
CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
HeapScanDesc scandesc;
int attr_count,
i;
int num_phys_attrs;
int attr_count;
Form_pg_attribute *attr;
FmgrInfo *out_functions;
Oid *elements;
@ -544,48 +533,33 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
int16 fld_size;
char *string;
Snapshot mySnapshot;
int copy_attr_count;
int *attmap;
int p = 0;
List *cur;
tupDesc = rel->rd_att;
attr_count = rel->rd_att->natts;
attr = rel->rd_att->attrs;
copy_attr_count = length(attlist);
attmap = (int *) palloc(copy_attr_count * sizeof(int));
foreach(cur, attlist)
{
const char *currAtt = strVal(lfirst(cur));
for (i = 0; i < attr_count; i++)
{
if (namestrcmp(&attr[i]->attname, currAtt) == 0)
{
attmap[p++] = i;
continue;
}
}
}
attr = tupDesc->attrs;
num_phys_attrs = tupDesc->natts;
attr_count = length(attnumlist);
/*
* Get info about the columns we need to process.
*
* For binary copy we really only need isvarlena, but compute it
* all...
*/
out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
elements = (Oid *) palloc(attr_count * sizeof(Oid));
isvarlena = (bool *) palloc(attr_count * sizeof(bool));
for (i = 0; i < attr_count; i++)
out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
isvarlena = (bool *) palloc(num_phys_attrs * sizeof(bool));
foreach(cur, attnumlist)
{
int attnum = lfirsti(cur);
Oid out_func_oid;
if (!getTypeOutputInfo(attr[i]->atttypid,
&out_func_oid, &elements[i], &isvarlena[i]))
if (!getTypeOutputInfo(attr[attnum-1]->atttypid,
&out_func_oid, &elements[attnum-1],
&isvarlena[attnum-1]))
elog(ERROR, "COPY: couldn't lookup info for type %u",
attr[i]->atttypid);
fmgr_info(out_func_oid, &out_functions[i]);
attr[attnum-1]->atttypid);
fmgr_info(out_func_oid, &out_functions[attnum-1]);
}
if (binary)
@ -650,14 +624,14 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
}
}
for (i = 0; i < copy_attr_count; i++)
foreach(cur, attnumlist)
{
int attnum = lfirsti(cur);
Datum origvalue,
value;
bool isnull;
int mi = attmap[i];
origvalue = heap_getattr(tuple, mi + 1, tupDesc, &isnull);
origvalue = heap_getattr(tuple, attnum, tupDesc, &isnull);
if (!binary)
{
@ -686,25 +660,25 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
* (or for binary case, becase we must output untoasted
* value).
*/
if (isvarlena[mi])
if (isvarlena[attnum-1])
value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
else
value = origvalue;
if (!binary)
{
string = DatumGetCString(FunctionCall3(&out_functions[mi],
string = DatumGetCString(FunctionCall3(&out_functions[attnum-1],
value,
ObjectIdGetDatum(elements[mi]),
Int32GetDatum(attr[mi]->atttypmod)));
ObjectIdGetDatum(elements[attnum-1]),
Int32GetDatum(attr[attnum-1]->atttypmod)));
CopyAttributeOut(fp, string, delim);
pfree(string);
}
else
{
fld_size = attr[mi]->attlen;
fld_size = attr[attnum-1]->attlen;
CopySendData(&fld_size, sizeof(int16), fp);
if (isvarlena[mi])
if (isvarlena[attnum-1])
{
/* varlena */
Assert(fld_size == -1);
@ -712,7 +686,7 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
VARSIZE(value),
fp);
}
else if (!attr[mi]->attbyval)
else if (!attr[attnum-1]->attbyval)
{
/* fixed-length pass-by-reference */
Assert(fld_size > 0);
@ -767,36 +741,36 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids,
* Copy FROM file to relation.
*/
static void
CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
FILE *fp, char *delim, char *null_print)
{
HeapTuple tuple;
TupleDesc tupDesc;
Form_pg_attribute *attr;
AttrNumber attr_count, copy_attr_count, def_attr_count;
AttrNumber num_phys_attrs, attr_count, num_defaults;
FmgrInfo *in_functions;
Oid *elements;
int i;
List *cur;
Oid in_func_oid;
Datum *values;
char *nulls;
int done = 0;
bool done = false;
ResultRelInfo *resultRelInfo;
EState *estate = CreateExecutorState(); /* for ExecConstraints() */
TupleTable tupleTable;
TupleTableSlot *slot;
bool file_has_oids;
int *attmap = NULL;
int *defmap = NULL;
Node **defexprs = NULL; /* array of default att expressions */
int *defmap;
Node **defexprs; /* array of default att expressions */
ExprContext *econtext; /* used for ExecEvalExpr for default atts */
ExprDoneCond isdone;
MemoryContext oldcontext = CurrentMemoryContext;
tupDesc = RelationGetDescr(rel);
attr = tupDesc->attrs;
attr_count = tupDesc->natts;
copy_attr_count = length(attlist);
def_attr_count = 0;
num_phys_attrs = tupDesc->natts;
attr_count = length(attnumlist);
num_defaults = 0;
/*
* We need a ResultRelInfo so we can use the regular executor's
@ -819,50 +793,40 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, tupDesc, false);
if (!binary)
/*
* pick up the input function and default expression (if any) for
* each attribute in the relation. (We don't actually use the
* input function if it's a binary copy.)
*/
defmap = (int *) palloc(sizeof(int) * num_phys_attrs);
defexprs = (Node **) palloc(sizeof(Node *) * num_phys_attrs);
in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
for (i = 0; i < num_phys_attrs; i++)
{
/*
* pick up the input function and default expression (if any) for
* each attribute in the relation.
*/
attmap = (int *) palloc(sizeof(int) * attr_count);
defmap = (int *) palloc(sizeof(int) * attr_count);
defexprs = (Node **) palloc(sizeof(Node *) * attr_count);
in_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
elements = (Oid *) palloc(attr_count * sizeof(Oid));
for (i = 0; i < attr_count; i++)
/* We don't need info for dropped attributes */
if (attr[i]->attisdropped)
continue;
in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
fmgr_info(in_func_oid, &in_functions[i]);
elements[i] = GetTypeElement(attr[i]->atttypid);
/* if column not specified, use default value if one exists */
if (!intMember(i + 1, attnumlist))
{
List *l;
int p = 0;
bool specified = false;
in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
fmgr_info(in_func_oid, &in_functions[i]);
elements[i] = GetTypeElement(attr[i]->atttypid);
foreach(l, attlist)
defexprs[num_defaults] = build_column_default(rel, i + 1);
if (defexprs[num_defaults] != NULL)
{
if (namestrcmp(&attr[i]->attname, strVal(lfirst(l))) == 0)
{
attmap[p] = i;
specified = true;
continue;
}
p++;
}
/* if column not specified, use default value if one exists */
if (! specified)
{
defexprs[def_attr_count] = build_column_default(rel, i + 1);
if (defexprs[def_attr_count] != NULL)
{
defmap[def_attr_count] = i;
def_attr_count++;
}
defmap[num_defaults] = i;
num_defaults++;
}
}
}
if (!binary)
{
file_has_oids = oids; /* must rely on user to tell us this... */
}
else
@ -898,13 +862,10 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: bogus file header (wrong length)");
}
in_functions = NULL;
elements = NULL;
}
values = (Datum *) palloc(attr_count * sizeof(Datum));
nulls = (char *) palloc(attr_count * sizeof(char));
values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
nulls = (char *) palloc(num_phys_attrs * sizeof(char));
copy_lineno = 0;
fe_eof = false;
@ -914,58 +875,77 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
while (!done)
{
bool skip_tuple;
Oid loaded_oid;
Oid loaded_oid = InvalidOid;
CHECK_FOR_INTERRUPTS();
copy_lineno++;
/* Reset the per-output-tuple exprcontext */
/* Reset the per-tuple exprcontext */
ResetPerTupleExprContext(estate);
/* Switch to and reset per-tuple memory context, too */
MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
MemoryContextReset(CurrentMemoryContext);
/* Initialize all values for row to NULL */
MemSet(values, 0, attr_count * sizeof(Datum));
MemSet(nulls, 'n', attr_count * sizeof(char));
MemSet(values, 0, num_phys_attrs * sizeof(Datum));
MemSet(nulls, 'n', num_phys_attrs * sizeof(char));
if (!binary)
{
CopyReadResult result;
CopyReadResult result = NORMAL_ATTR;
char *string;
if (file_has_oids)
{
string = CopyReadAttribute(fp, delim, &result);
if (result == END_OF_FILE)
done = 1;
else if (string == NULL || strcmp(string, null_print) == 0)
elog(ERROR, "COPY TEXT: NULL Oid");
if (result == END_OF_FILE && *string == '\0')
{
/* EOF at start of line: all is well */
done = true;
break;
}
if (strcmp(string, null_print) == 0)
elog(ERROR, "NULL Oid");
else
{
loaded_oid = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(string)));
if (loaded_oid == InvalidOid)
elog(ERROR, "COPY TEXT: Invalid Oid");
elog(ERROR, "Invalid Oid");
}
}
/*
* here, we only try to read as many attributes as
* were specified.
/*
* Loop to read the user attributes on the line.
*/
for (i = 0; i < copy_attr_count && !done; i++)
foreach(cur, attnumlist)
{
int m = attmap[i];
int attnum = lfirsti(cur);
int m = attnum - 1;
/*
* If prior attr on this line was ended by newline or EOF,
* complain.
*/
if (result != NORMAL_ATTR)
elog(ERROR, "Missing data for column \"%s\"",
NameStr(attr[m]->attname));
string = CopyReadAttribute(fp, delim, &result);
/* If we got an end-of-line before we expected, bail out */
if (result == END_OF_LINE && i < (copy_attr_count - 1))
elog(ERROR, "COPY TEXT: Missing data for attribute %d", i + 1);
if (result == END_OF_FILE && *string == '\0' &&
cur == attnumlist && !file_has_oids)
{
/* EOF at start of line: all is well */
done = true;
break; /* out of per-attr loop */
}
if (result == END_OF_FILE)
done = 1;
else if (strcmp(string, null_print) == 0)
if (strcmp(string, null_print) == 0)
{
/* we read an SQL NULL, no need to do anything */
}
@ -979,124 +959,149 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
}
}
if (result == NORMAL_ATTR && !done)
elog(ERROR, "COPY TEXT: Extra data encountered");
if (done)
break; /* out of per-row loop */
/* Complain if there are more fields on the input line */
if (result == NORMAL_ATTR)
elog(ERROR, "Extra data after last expected column");
/*
* as above, we only try a default lookup if one is
* known to be available
* If we got some data on the line, but it was ended by EOF,
* process the line normally but set flag to exit the loop
* when we return to the top.
*/
for (i = 0; i < def_attr_count && !done; i++)
{
bool isnull;
values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
&isnull, &isdone);
if (! isnull)
nulls[defmap[i]] = ' ';
}
if (result == END_OF_FILE)
done = true;
}
else
{ /* binary */
{
/* binary */
int16 fld_count,
fld_size;
CopyGetData(&fld_count, sizeof(int16), fp);
if (CopyGetEof(fp) || fld_count == -1)
done = 1;
else
{
if (fld_count <= 0 || fld_count > attr_count)
elog(ERROR, "COPY BINARY: tuple field count is %d, expected %d",
(int) fld_count, attr_count);
done = true;
break;
}
if (file_has_oids)
if (fld_count != attr_count)
elog(ERROR, "COPY BINARY: tuple field count is %d, expected %d",
(int) fld_count, attr_count);
if (file_has_oids)
{
CopyGetData(&fld_size, sizeof(int16), fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
if (fld_size != (int16) sizeof(Oid))
elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d",
(int) fld_size, (int) sizeof(Oid));
CopyGetData(&loaded_oid, sizeof(Oid), fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
if (loaded_oid == InvalidOid)
elog(ERROR, "COPY BINARY: Invalid Oid");
}
i = 0;
foreach(cur, attnumlist)
{
int attnum = lfirsti(cur);
i++;
CopyGetData(&fld_size, sizeof(int16), fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
if (fld_size == 0)
continue; /* it's NULL; nulls[attnum-1] already set */
if (fld_size != attr[attnum-1]->attlen)
elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d",
i, (int) fld_size, (int) attr[attnum-1]->attlen);
if (fld_size == -1)
{
CopyGetData(&fld_size, sizeof(int16), fp);
/* varlena field */
int32 varlena_size;
Pointer varlena_ptr;
CopyGetData(&varlena_size, sizeof(int32), fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
if (fld_size != (int16) sizeof(Oid))
elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d",
(int) fld_size, (int) sizeof(Oid));
CopyGetData(&loaded_oid, sizeof(Oid), fp);
if (varlena_size < (int32) sizeof(int32))
elog(ERROR, "COPY BINARY: bogus varlena length");
varlena_ptr = (Pointer) palloc(varlena_size);
VARATT_SIZEP(varlena_ptr) = varlena_size;
CopyGetData(VARDATA(varlena_ptr),
varlena_size - sizeof(int32),
fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
if (loaded_oid == InvalidOid)
elog(ERROR, "COPY BINARY: Invalid Oid");
values[attnum-1] = PointerGetDatum(varlena_ptr);
}
else if (!attr[attnum-1]->attbyval)
{
/* fixed-length pass-by-reference */
Pointer refval_ptr;
Assert(fld_size > 0);
refval_ptr = (Pointer) palloc(fld_size);
CopyGetData(refval_ptr, fld_size, fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
values[attnum-1] = PointerGetDatum(refval_ptr);
}
else
{
/* pass-by-value */
Datum datumBuf;
/*
* We need this horsing around because we don't
* know how shorter data values are aligned within
* a Datum.
*/
Assert(fld_size > 0 && fld_size <= sizeof(Datum));
CopyGetData(&datumBuf, fld_size, fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
values[attnum-1] = fetch_att(&datumBuf, true, fld_size);
}
for (i = 0; i < (int) fld_count; i++)
{
CopyGetData(&fld_size, sizeof(int16), fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
if (fld_size == 0)
continue; /* it's NULL; nulls[i] already set */
if (fld_size != attr[i]->attlen)
elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d",
i + 1, (int) fld_size, (int) attr[i]->attlen);
if (fld_size == -1)
{
/* varlena field */
int32 varlena_size;
Pointer varlena_ptr;
CopyGetData(&varlena_size, sizeof(int32), fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
if (varlena_size < (int32) sizeof(int32))
elog(ERROR, "COPY BINARY: bogus varlena length");
varlena_ptr = (Pointer) palloc(varlena_size);
VARATT_SIZEP(varlena_ptr) = varlena_size;
CopyGetData(VARDATA(varlena_ptr),
varlena_size - sizeof(int32),
fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
values[i] = PointerGetDatum(varlena_ptr);
}
else if (!attr[i]->attbyval)
{
/* fixed-length pass-by-reference */
Pointer refval_ptr;
Assert(fld_size > 0);
refval_ptr = (Pointer) palloc(fld_size);
CopyGetData(refval_ptr, fld_size, fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
values[i] = PointerGetDatum(refval_ptr);
}
else
{
/* pass-by-value */
Datum datumBuf;
/*
* We need this horsing around because we don't
* know how shorter data values are aligned within
* a Datum.
*/
Assert(fld_size > 0 && fld_size <= sizeof(Datum));
CopyGetData(&datumBuf, fld_size, fp);
if (CopyGetEof(fp))
elog(ERROR, "COPY BINARY: unexpected EOF");
values[i] = fetch_att(&datumBuf, true, fld_size);
}
nulls[i] = ' ';
}
nulls[attnum-1] = ' ';
}
}
if (done)
break;
/*
* Now compute and insert any defaults available for the
* columns not provided by the input data. Anything not
* processed here or above will remain NULL.
*/
for (i = 0; i < num_defaults; i++)
{
bool isnull;
values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext,
&isnull, NULL);
if (!isnull)
nulls[defmap[i]] = ' ';
}
/*
* And now we can form the input tuple.
*/
tuple = heap_formtuple(tupDesc, values, nulls);
if (oids && file_has_oids)
HeapTupleSetOid(tuple, loaded_oid);
/*
* Triggers and stuff need to be invoked in query context.
*/
MemoryContextSwitchTo(oldcontext);
skip_tuple = false;
/* BEFORE ROW INSERT Triggers */
@ -1118,6 +1123,7 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
if (!skip_tuple)
{
/* Place tuple in tuple slot */
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
/*
@ -1138,8 +1144,6 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
if (resultRelInfo->ri_TrigDesc)
ExecARInsertTriggers(estate, resultRelInfo, tuple);
}
heap_freetuple(tuple);
}
/*
@ -1147,6 +1151,8 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids,
*/
copy_lineno = 0;
MemoryContextSwitchTo(oldcontext);
pfree(values);
pfree(nulls);
@ -1197,12 +1203,11 @@ GetTypeElement(Oid type)
/*
* Read the value of a single attribute.
*
* Results are returned in the status indicator, as well as the
* return value. If a value was successfully read but there is
* more to read before EOL, NORMAL_ATTR is set and the value read
* is returned. If a value was read and we hit EOL, END_OF_LINE
* is set and the value read is returned. If we hit the EOF,
* END_OF_FILE is set and NULL is returned.
* *result is set to indicate what terminated the read:
* NORMAL_ATTR: column delimiter
* END_OF_LINE: newline
* END_OF_FILE: EOF indication
* In all cases, the string read up to the terminator is returned.
*
* Note: This function does not care about SQL NULL values -- it
* is the caller's responsibility to check if the returned string
@ -1215,8 +1220,7 @@ static char *
CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
{
int c;
int delimc = (unsigned char)delim[0];
int delimc = (unsigned char) delim[0];
#ifdef MULTIBYTE
int mblen;
unsigned char s[2];
@ -1230,7 +1234,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
attribute_buf.len = 0;
attribute_buf.data[0] = '\0';
/* set default */
/* set default status */
*result = NORMAL_ATTR;
for (;;)
@ -1239,7 +1243,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
if (c == EOF)
{
*result = END_OF_FILE;
return NULL;
goto copy_eof;
}
if (c == '\n')
{
@ -1254,7 +1258,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
if (c == EOF)
{
*result = END_OF_FILE;
return NULL;
goto copy_eof;
}
switch (c)
{
@ -1286,7 +1290,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
if (c == EOF)
{
*result = END_OF_FILE;
return NULL;
goto copy_eof;
}
CopyDonePeek(fp, c, false /* put back */ );
}
@ -1296,7 +1300,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
if (c == EOF)
{
*result = END_OF_FILE;
return NULL;
goto copy_eof;
}
CopyDonePeek(fp, c, false /* put back */ );
}
@ -1336,7 +1340,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
if (c != '\n')
elog(ERROR, "CopyReadAttribute: end of record marker corrupted");
*result = END_OF_FILE;
return NULL;
goto copy_eof;
}
}
appendStringInfoCharMacro(&attribute_buf, c);
@ -1353,7 +1357,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
if (c == EOF)
{
*result = END_OF_FILE;
return NULL;
goto copy_eof;
}
appendStringInfoCharMacro(&attribute_buf, c);
}
@ -1361,6 +1365,8 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result)
#endif
}
copy_eof:
#ifdef MULTIBYTE
if (client_encoding != server_encoding)
{
@ -1468,50 +1474,51 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
}
/*
* CopyCheckAttlist: elog(ERROR,...) if the specified attlist
* is not valid for the Relation
* CopyGetAttnums - build an integer list of attnums to be copied
*
* The input attnamelist is either the user-specified column list,
* or NIL if there was none (in which case we want all the non-dropped
* columns).
*/
static void
CopyCheckAttlist(Relation rel, List *attlist)
static List *
CopyGetAttnums(Relation rel, List *attnamelist)
{
TupleDesc tupDesc;
int attr_count;
List *l;
List *attnums = NIL;
if (attlist == NIL)
return;
tupDesc = RelationGetDescr(rel);
Assert(tupDesc != NULL);
/*
* make sure there aren't more columns specified than are in the table
*/
attr_count = tupDesc->natts;
if (attr_count < length(attlist))
elog(ERROR, "COPY: Too many columns specified");
/*
* make sure no columns are specified that don't exist in the table
*/
foreach(l, attlist)
if (attnamelist == NIL)
{
char *colName = strVal(lfirst(l));
bool found = false;
int i;
/* Generate default column list */
TupleDesc tupDesc = RelationGetDescr(rel);
Form_pg_attribute *attr = tupDesc->attrs;
int attr_count = tupDesc->natts;
int i;
for (i = 0; i < attr_count; i++)
{
if (namestrcmp(&tupDesc->attrs[i]->attname, colName) == 0)
{
found = true;
break;
}
if (attr[i]->attisdropped)
continue;
attnums = lappendi(attnums, i + 1);
}
if (!found)
elog(ERROR, "COPY: Specified column \"%s\" does not exist",
colName);
}
}
else
{
/* Validate the user-supplied list and extract attnums */
List *l;
foreach(l, attnamelist)
{
char *name = strVal(lfirst(l));
int attnum;
/* Lookup column name, elog on failure */
/* Note we disallow system columns here */
attnum = attnameAttNum(rel, name, false);
/* Check for duplicates */
if (intMember(attnum, attnums))
elog(ERROR, "Attribute \"%s\" specified more than once", name);
attnums = lappendi(attnums, attnum);
}
}
return attnums;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.79 2002/07/29 23:46:35 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.80 2002/08/02 18:15:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -294,10 +294,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
HeapTuple tuple;
Form_pg_attribute att;
tuple = SearchSysCache(ATTNAME,
ObjectIdGetDatum(relId),
PointerGetDatum(arg),
0, 0);
tuple = SearchSysCacheAttName(relId, arg);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg);
att = (Form_pg_attribute) GETSTRUCT(tuple);
@ -387,10 +384,7 @@ NormIndexAttrs(IndexInfo *indexInfo,
if (attribute->name == NULL)
elog(ERROR, "missing attribute for define index");
atttuple = SearchSysCache(ATTNAME,
ObjectIdGetDatum(relId),
PointerGetDatum(attribute->name),
0, 0);
atttuple = SearchSysCacheAttName(relId, attribute->name);
if (!HeapTupleIsValid(atttuple))
elog(ERROR, "DefineIndex: attribute \"%s\" not found",
attribute->name);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.25 2002/07/31 17:19:51 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.26 2002/08/02 18:15:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -503,7 +503,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
/*
* newattno[] will contain the child-table attribute numbers for
* the attributes of this parent table. (They are not the same
* for parents after the first one.)
* for parents after the first one, nor if we have dropped columns.)
*/
newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
@ -516,6 +516,19 @@ MergeAttributes(List *schema, List *supers, bool istemp,
ColumnDef *def;
TypeName *typename;
/*
* Ignore dropped columns in the parent.
*/
if (attribute->attisdropped)
{
/*
* change_varattnos_of_a_node asserts that this is greater than
* zero, so if anything tries to use it, we should find out.
*/
newattno[parent_attno - 1] = 0;
continue;
}
/*
* Does it conflict with some previously inherited column?
*/
@ -1062,17 +1075,17 @@ renameatt(Oid relid,
attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
atttup = SearchSysCacheCopy(ATTNAME,
ObjectIdGetDatum(relid),
PointerGetDatum(oldattname),
0, 0);
atttup = SearchSysCacheCopyAttName(relid, oldattname);
if (!HeapTupleIsValid(atttup))
elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname);
elog(ERROR, "renameatt: attribute \"%s\" does not exist",
oldattname);
if (((Form_pg_attribute) GETSTRUCT(atttup))->attnum < 0)
elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
elog(ERROR, "renameatt: system attribute \"%s\" may not be renamed",
oldattname);
/* should not already exist */
/* this test is deliberately not attisdropped-aware */
if (SearchSysCacheExists(ATTNAME,
ObjectIdGetDatum(relid),
PointerGetDatum(newattname),
@ -1126,10 +1139,7 @@ renameatt(Oid relid,
* Okay, look to see if any column name of the index matches the
* old attribute name.
*/
atttup = SearchSysCacheCopy(ATTNAME,
ObjectIdGetDatum(indexoid),
PointerGetDatum(oldattname),
0, 0);
atttup = SearchSysCacheCopyAttName(indexoid, oldattname);
if (!HeapTupleIsValid(atttup))
continue; /* Nope, so ignore it */
@ -1634,6 +1644,10 @@ AlterTableAddColumn(Oid myrelid,
elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
RelationGetRelationName(rel));
/*
* this test is deliberately not attisdropped-aware, since if one tries
* to add a column matching a dropped column name, it's gonna fail anyway.
*/
if (SearchSysCacheExists(ATTNAME,
ObjectIdGetDatum(myrelid),
PointerGetDatum(colDef->colname),
@ -1681,6 +1695,7 @@ AlterTableAddColumn(Oid myrelid,
attribute->attnotnull = colDef->is_not_null;
attribute->atthasdef = (colDef->raw_default != NULL ||
colDef->cooked_default != NULL);
attribute->attisdropped = false;
ReleaseSysCache(typeTuple);
@ -1821,17 +1836,11 @@ AlterTableAlterColumnDropNotNull(Oid myrelid,
/*
* get the number of the attribute
*/
tuple = SearchSysCache(ATTNAME,
ObjectIdGetDatum(myrelid),
PointerGetDatum(colName),
0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
attnum = get_attnum(myrelid, colName);
if (attnum == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), colName);
attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
ReleaseSysCache(tuple);
/* Prevent them from altering a system attribute */
if (attnum < 0)
elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
@ -1884,10 +1893,7 @@ AlterTableAlterColumnDropNotNull(Oid myrelid,
*/
attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
tuple = SearchSysCacheCopy(ATTNAME,
ObjectIdGetDatum(myrelid),
PointerGetDatum(colName),
0, 0);
tuple = SearchSysCacheCopyAttName(myrelid, colName);
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), colName);
@ -1971,17 +1977,11 @@ AlterTableAlterColumnSetNotNull(Oid myrelid,
/*
* get the number of the attribute
*/
tuple = SearchSysCache(ATTNAME,
ObjectIdGetDatum(myrelid),
PointerGetDatum(colName),
0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
attnum = get_attnum(myrelid, colName);
if (attnum == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), colName);
attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
ReleaseSysCache(tuple);
/* Prevent them from altering a system attribute */
if (attnum < 0)
elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
@ -2014,10 +2014,7 @@ AlterTableAlterColumnSetNotNull(Oid myrelid,
*/
attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
tuple = SearchSysCacheCopy(ATTNAME,
ObjectIdGetDatum(myrelid),
PointerGetDatum(colName),
0, 0);
tuple = SearchSysCacheCopyAttName(myrelid, colName);
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), colName);
@ -2051,7 +2048,6 @@ AlterTableAlterColumnDefault(Oid myrelid,
Node *newDefault)
{
Relation rel;
HeapTuple tuple;
AttrNumber attnum;
rel = heap_open(myrelid, AccessExclusiveLock);
@ -2106,16 +2102,15 @@ AlterTableAlterColumnDefault(Oid myrelid,
/*
* get the number of the attribute
*/
tuple = SearchSysCache(ATTNAME,
ObjectIdGetDatum(myrelid),
PointerGetDatum(colName),
0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
attnum = get_attnum(myrelid, colName);
if (attnum == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), colName);
attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
ReleaseSysCache(tuple);
/* Prevent them from altering a system attribute */
if (attnum < 0)
elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
colName);
/*
* Remove any old default for the column. We use RESTRICT here for
@ -2254,10 +2249,7 @@ AlterTableAlterColumnFlags(Oid myrelid,
attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
tuple = SearchSysCacheCopy(ATTNAME,
ObjectIdGetDatum(myrelid),
PointerGetDatum(colName),
0, 0);
tuple = SearchSysCacheCopyAttName(myrelid, colName);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), colName);
@ -2309,7 +2301,99 @@ AlterTableDropColumn(Oid myrelid,
bool inh, const char *colName,
DropBehavior behavior)
{
elog(ERROR, "ALTER TABLE / DROP COLUMN is not implemented");
Relation rel;
AttrNumber attnum;
AttrNumber n;
TupleDesc tupleDesc;
bool success;
ObjectAddress object;
rel = heap_open(myrelid, AccessExclusiveLock);
if (rel->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
RelationGetRelationName(rel));
if (!allowSystemTableMods
&& IsSystemRelation(rel))
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
RelationGetRelationName(rel));
if (!pg_class_ownercheck(myrelid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel));
/*
* get the number of the attribute
*/
attnum = get_attnum(myrelid, colName);
if (attnum == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), colName);
/* Can't drop a system attribute */
if (attnum < 0)
elog(ERROR, "ALTER TABLE: Cannot drop system attribute \"%s\"",
colName);
/*
* Make sure there will be at least one user column left in the relation
* after we drop this one. Zero-length tuples tend to confuse us.
*/
tupleDesc = RelationGetDescr(rel);
success = false;
for (n = 1; n <= tupleDesc->natts; n++)
{
Form_pg_attribute attribute = tupleDesc->attrs[n - 1];
if (!attribute->attisdropped && n != attnum)
{
success = true;
break;
}
}
if (!success)
elog(ERROR, "ALTER TABLE: Cannot drop last column from table \"%s\"",
RelationGetRelationName(rel));
/*
* Propagate to children if desired
*/
if (inh)
{
List *child,
*children;
/* this routine is actually in the planner */
children = find_all_inheritors(myrelid);
/*
* find_all_inheritors does the recursive search of the
* inheritance hierarchy, so all we have to do is process all of
* the relids in the list that it returns.
*/
foreach(child, children)
{
Oid childrelid = lfirsti(child);
if (childrelid == myrelid)
continue;
AlterTableDropColumn(childrelid,
false, colName, behavior);
}
}
/*
* Perform the actual deletion
*/
object.classId = RelOid_pg_class;
object.objectId = myrelid;
object.objectSubId = attnum;
performDeletion(&object, behavior);
heap_close(rel, NoLock); /* close rel, but keep lock! */
}
@ -2722,8 +2806,13 @@ createForeignKeyConstraint(Relation rel, Relation pkrel,
foreach(l, fkconstraint->fk_attrs)
{
Ident *id = (Ident *) lfirst(l);
AttrNumber attno;
fkattr[i++] = get_attnum(RelationGetRelid(rel), id->name);
attno = get_attnum(RelationGetRelid(rel), id->name);
if (attno == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
RelationGetRelationName(rel), id->name);
fkattr[i++] = attno;
}
/* The same for the referenced primary key attrs */
@ -2733,8 +2822,13 @@ createForeignKeyConstraint(Relation rel, Relation pkrel,
foreach(l, fkconstraint->pk_attrs)
{
Ident *id = (Ident *) lfirst(l);
AttrNumber attno;
pkattr[i++] = get_attnum(RelationGetRelid(pkrel), id->name);
attno = get_attnum(RelationGetRelid(pkrel), id->name);
if (attno == InvalidAttrNumber)
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
RelationGetRelationName(pkrel), id->name);
pkattr[i++] = attno;
}
/* Now we can make the pg_constraint entry */