mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-04 00:02:52 -05:00 
			
		
		
		
	Fixed this problem and added regression tests in domain.sql.
Also: - Changed header file order (alphabetical) - Changed to m = attnum - 1 in binary copy code for consistency Rod Taylor
This commit is contained in:
		
							parent
							
								
									24bebf0b72
								
							
						
					
					
						commit
						07a6fa9df1
					
				@ -7,7 +7,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.171 2002/09/04 20:31:14 momjian Exp $
 | 
			
		||||
 *	  $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.172 2002/09/20 03:52:50 momjian Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@ -28,10 +28,13 @@
 | 
			
		||||
#include "commands/copy.h"
 | 
			
		||||
#include "commands/trigger.h"
 | 
			
		||||
#include "executor/executor.h"
 | 
			
		||||
#include "rewrite/rewriteHandler.h"
 | 
			
		||||
#include "libpq/libpq.h"
 | 
			
		||||
#include "mb/pg_wchar.h"
 | 
			
		||||
#include "miscadmin.h"
 | 
			
		||||
#include "nodes/makefuncs.h"
 | 
			
		||||
#include "parser/parse_coerce.h"
 | 
			
		||||
#include "parser/parse_relation.h"
 | 
			
		||||
#include "rewrite/rewriteHandler.h"
 | 
			
		||||
#include "tcop/pquery.h"
 | 
			
		||||
#include "tcop/tcopprot.h"
 | 
			
		||||
#include "utils/acl.h"
 | 
			
		||||
@ -39,7 +42,6 @@
 | 
			
		||||
#include "utils/relcache.h"
 | 
			
		||||
#include "utils/lsyscache.h"
 | 
			
		||||
#include "utils/syscache.h"
 | 
			
		||||
#include "mb/pg_wchar.h"
 | 
			
		||||
 | 
			
		||||
#define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 | 
			
		||||
#define OCTVALUE(c) ((c) - '0')
 | 
			
		||||
@ -744,6 +746,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
				num_defaults;
 | 
			
		||||
	FmgrInfo   *in_functions;
 | 
			
		||||
	Oid		   *elements;
 | 
			
		||||
	bool	   *isDomain;
 | 
			
		||||
	bool		hasDomain = false;
 | 
			
		||||
	int			i;
 | 
			
		||||
	List	   *cur;
 | 
			
		||||
	Oid			in_func_oid;
 | 
			
		||||
@ -796,6 +800,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
	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));
 | 
			
		||||
	isDomain = (bool *) palloc(num_phys_attrs * sizeof(bool));
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_phys_attrs; i++)
 | 
			
		||||
	{
 | 
			
		||||
@ -803,6 +808,16 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
		if (attr[i]->attisdropped)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* Test for the base type */
 | 
			
		||||
		if (getBaseType(attr[i]->atttypid) != attr[i]->atttypid)
 | 
			
		||||
		{
 | 
			
		||||
			hasDomain = true;
 | 
			
		||||
			isDomain[i] = true;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			isDomain[i] = false;
 | 
			
		||||
 | 
			
		||||
		/* Fetch the input function */
 | 
			
		||||
		in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
 | 
			
		||||
		fmgr_info(in_func_oid, &in_functions[i]);
 | 
			
		||||
		elements[i] = GetTypeElement(attr[i]->atttypid);
 | 
			
		||||
@ -1011,6 +1026,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
			foreach(cur, attnumlist)
 | 
			
		||||
			{
 | 
			
		||||
				int			attnum = lfirsti(cur);
 | 
			
		||||
				int			m = attnum - 1;
 | 
			
		||||
 | 
			
		||||
				i++;
 | 
			
		||||
 | 
			
		||||
@ -1019,9 +1035,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
					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)
 | 
			
		||||
				if (fld_size != attr[m]->attlen)
 | 
			
		||||
					elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d",
 | 
			
		||||
					  i, (int) fld_size, (int) attr[attnum - 1]->attlen);
 | 
			
		||||
					  i, (int) fld_size, (int) attr[m]->attlen);
 | 
			
		||||
				if (fld_size == -1)
 | 
			
		||||
				{
 | 
			
		||||
					/* varlena field */
 | 
			
		||||
@ -1040,9 +1056,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
								fp);
 | 
			
		||||
					if (CopyGetEof(fp))
 | 
			
		||||
						elog(ERROR, "COPY BINARY: unexpected EOF");
 | 
			
		||||
					values[attnum - 1] = PointerGetDatum(varlena_ptr);
 | 
			
		||||
					values[m] = PointerGetDatum(varlena_ptr);
 | 
			
		||||
				}
 | 
			
		||||
				else if (!attr[attnum - 1]->attbyval)
 | 
			
		||||
				else if (!attr[m]->attbyval)
 | 
			
		||||
				{
 | 
			
		||||
					/* fixed-length pass-by-reference */
 | 
			
		||||
					Pointer		refval_ptr;
 | 
			
		||||
@ -1052,7 +1068,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
					CopyGetData(refval_ptr, fld_size, fp);
 | 
			
		||||
					if (CopyGetEof(fp))
 | 
			
		||||
						elog(ERROR, "COPY BINARY: unexpected EOF");
 | 
			
		||||
					values[attnum - 1] = PointerGetDatum(refval_ptr);
 | 
			
		||||
					values[m] = PointerGetDatum(refval_ptr);
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
@ -1067,10 +1083,56 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 | 
			
		||||
					CopyGetData(&datumBuf, fld_size, fp);
 | 
			
		||||
					if (CopyGetEof(fp))
 | 
			
		||||
						elog(ERROR, "COPY BINARY: unexpected EOF");
 | 
			
		||||
					values[attnum - 1] = fetch_att(&datumBuf, true, fld_size);
 | 
			
		||||
					values[m] = fetch_att(&datumBuf, true, fld_size);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				nulls[attnum - 1] = ' ';
 | 
			
		||||
				nulls[m] = ' ';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Deal with domains */
 | 
			
		||||
		if (hasDomain)
 | 
			
		||||
		{
 | 
			
		||||
			ParseState *pstate;
 | 
			
		||||
			pstate = make_parsestate(NULL);
 | 
			
		||||
 | 
			
		||||
			foreach(cur, attnumlist)
 | 
			
		||||
			{
 | 
			
		||||
				int			attnum = lfirsti(cur);
 | 
			
		||||
				int			m = attnum - 1;
 | 
			
		||||
 | 
			
		||||
				Const	   *con;
 | 
			
		||||
				Node	   *node;
 | 
			
		||||
				bool	   isNull = (nulls[m] == 'n');
 | 
			
		||||
 | 
			
		||||
				/* This is not a domain, so lets skip it */
 | 
			
		||||
				if (!isDomain[m])
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				/*
 | 
			
		||||
				 * This is a domain.  As such, we must process it's input
 | 
			
		||||
				 * function and coerce_type_constraints.  The simplest way
 | 
			
		||||
				 * of doing that is to allow coerce_type to accomplish its
 | 
			
		||||
				 * job from an unknown constant
 | 
			
		||||
				 */
 | 
			
		||||
 | 
			
		||||
				/* Create a constant */
 | 
			
		||||
				con = makeConst(attr[m]->atttypid,
 | 
			
		||||
								attr[m]->attlen,
 | 
			
		||||
								values[m],
 | 
			
		||||
								isNull,
 | 
			
		||||
								attr[m]->attbyval,
 | 
			
		||||
								false,		/* not a set */
 | 
			
		||||
								false);		/* not coerced */
 | 
			
		||||
 | 
			
		||||
				/* Process constraints */
 | 
			
		||||
				node = coerce_type_constraints(pstate, (Node *) con,
 | 
			
		||||
											   attr[m]->atttypid, true);
 | 
			
		||||
 | 
			
		||||
				values[m] = ExecEvalExpr(node, econtext,
 | 
			
		||||
										 &isNull, NULL);
 | 
			
		||||
 | 
			
		||||
				nulls[m] = isNull ? 'n' : ' ';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -37,12 +37,18 @@ INSERT INTO basictest values ('88', 'haha', 'short', '123.12');      -- Good
 | 
			
		||||
INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
 | 
			
		||||
ERROR:  value too long for type character varying(5)
 | 
			
		||||
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212');    -- Truncate numeric
 | 
			
		||||
-- Test copy
 | 
			
		||||
COPY basictest (testvarchar) FROM stdin; -- fail
 | 
			
		||||
ERROR:  copy: line 1, value too long for type character varying(5)
 | 
			
		||||
lost synchronization with server, resetting connection
 | 
			
		||||
COPY basictest (testvarchar) FROM stdin;
 | 
			
		||||
select * from basictest;
 | 
			
		||||
 testint4 | testtext | testvarchar | testnumeric 
 | 
			
		||||
----------+----------+-------------+-------------
 | 
			
		||||
 88       | haha     | short       | 123.12
 | 
			
		||||
 88       | haha     | short       | 123.12
 | 
			
		||||
(2 rows)
 | 
			
		||||
          |          | short       | 
 | 
			
		||||
(3 rows)
 | 
			
		||||
 | 
			
		||||
-- check that domains inherit operations from base types
 | 
			
		||||
select testtext || testvarchar as concat, testnumeric + 42 as sum
 | 
			
		||||
@ -51,7 +57,8 @@ from basictest;
 | 
			
		||||
-----------+--------
 | 
			
		||||
 hahashort | 165.12
 | 
			
		||||
 hahashort | 165.12
 | 
			
		||||
(2 rows)
 | 
			
		||||
           |       
 | 
			
		||||
(3 rows)
 | 
			
		||||
 | 
			
		||||
drop table basictest;
 | 
			
		||||
drop domain domainvarchar restrict;
 | 
			
		||||
@ -111,12 +118,18 @@ ERROR:  Domain dnotnull does not allow NULL values
 | 
			
		||||
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
 | 
			
		||||
ERROR:  ExecInsert: Fail to add null value in not null attribute col3
 | 
			
		||||
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
 | 
			
		||||
-- Test copy
 | 
			
		||||
COPY nulltest FROM stdin; --fail
 | 
			
		||||
ERROR:  copy: line 1, CopyFrom: Fail to add null value in not null attribute col3
 | 
			
		||||
lost synchronization with server, resetting connection
 | 
			
		||||
COPY nulltest FROM stdin;
 | 
			
		||||
select * from nulltest;
 | 
			
		||||
 col1 | col2 | col3 | col4 
 | 
			
		||||
------+------+------+------
 | 
			
		||||
 a    | b    | c    | d
 | 
			
		||||
 a    | b    | c    | 
 | 
			
		||||
(2 rows)
 | 
			
		||||
 a    | b    | c    | 
 | 
			
		||||
(3 rows)
 | 
			
		||||
 | 
			
		||||
-- Test out coerced (casted) constraints
 | 
			
		||||
SELECT cast('1' as dnotnull);
 | 
			
		||||
@ -156,13 +169,16 @@ NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 'defaulttest_pkey
 | 
			
		||||
insert into defaulttest default values;
 | 
			
		||||
insert into defaulttest default values;
 | 
			
		||||
insert into defaulttest default values;
 | 
			
		||||
-- Test defaults with copy
 | 
			
		||||
COPY defaulttest(col5) FROM stdin;
 | 
			
		||||
select * from defaulttest;
 | 
			
		||||
 col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8  
 | 
			
		||||
------+------+------+------+------+------+------+-------
 | 
			
		||||
 3    | 12   | 5    | 1    | 3    | 88   | 8000 | 12.12
 | 
			
		||||
 3    | 12   | 5    | 2    | 3    | 88   | 8000 | 12.12
 | 
			
		||||
 3    | 12   | 5    | 3    | 3    | 88   | 8000 | 12.12
 | 
			
		||||
(3 rows)
 | 
			
		||||
 3    | 12   | 5    | 4    | 42   | 88   | 8000 | 12.12
 | 
			
		||||
(4 rows)
 | 
			
		||||
 | 
			
		||||
drop sequence ddef4_seq;
 | 
			
		||||
drop table defaulttest;
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,16 @@ create table basictest
 | 
			
		||||
INSERT INTO basictest values ('88', 'haha', 'short', '123.12');      -- Good
 | 
			
		||||
INSERT INTO basictest values ('88', 'haha', 'short text', '123.12'); -- Bad varchar
 | 
			
		||||
INSERT INTO basictest values ('88', 'haha', 'short', '123.1212');    -- Truncate numeric
 | 
			
		||||
 | 
			
		||||
-- Test copy
 | 
			
		||||
COPY basictest (testvarchar) FROM stdin; -- fail
 | 
			
		||||
notsoshorttext
 | 
			
		||||
\.
 | 
			
		||||
 | 
			
		||||
COPY basictest (testvarchar) FROM stdin;
 | 
			
		||||
short
 | 
			
		||||
\.
 | 
			
		||||
 | 
			
		||||
select * from basictest;
 | 
			
		||||
 | 
			
		||||
-- check that domains inherit operations from base types
 | 
			
		||||
@ -84,6 +94,16 @@ INSERT INTO nulltest values (NULL, 'b', 'c', 'd');
 | 
			
		||||
INSERT INTO nulltest values ('a', NULL, 'c', 'd');
 | 
			
		||||
INSERT INTO nulltest values ('a', 'b', NULL, 'd');
 | 
			
		||||
INSERT INTO nulltest values ('a', 'b', 'c', NULL); -- Good
 | 
			
		||||
 | 
			
		||||
-- Test copy
 | 
			
		||||
COPY nulltest FROM stdin; --fail
 | 
			
		||||
a	b	\N	d
 | 
			
		||||
\.
 | 
			
		||||
 | 
			
		||||
COPY nulltest FROM stdin;
 | 
			
		||||
a	b	c	\N
 | 
			
		||||
\.
 | 
			
		||||
 | 
			
		||||
select * from nulltest;
 | 
			
		||||
 | 
			
		||||
-- Test out coerced (casted) constraints
 | 
			
		||||
@ -119,6 +139,12 @@ create table defaulttest
 | 
			
		||||
insert into defaulttest default values;
 | 
			
		||||
insert into defaulttest default values;
 | 
			
		||||
insert into defaulttest default values;
 | 
			
		||||
 | 
			
		||||
-- Test defaults with copy
 | 
			
		||||
COPY defaulttest(col5) FROM stdin;
 | 
			
		||||
42
 | 
			
		||||
\.
 | 
			
		||||
 | 
			
		||||
select * from defaulttest;
 | 
			
		||||
 | 
			
		||||
drop sequence ddef4_seq;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user