copy.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,233 行 · 第 1/4 页

C
2,233
字号
		if (!skip_tuple)		{			/* Place tuple in tuple slot */			ExecStoreTuple(tuple, slot, InvalidBuffer, false);			/*			 * Check the constraints of the tuple			 */			if (rel->rd_att->constr)				ExecConstraints(resultRelInfo, slot, estate);			/*			 * OK, store the tuple and create index entries for it			 */			simple_heap_insert(rel, tuple);			if (resultRelInfo->ri_NumIndices > 0)				ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);			/* AFTER ROW INSERT Triggers */			ExecARInsertTriggers(estate, resultRelInfo, tuple);		}	}	/*	 * Done, clean up	 */	error_context_stack = errcontext.previous;	MemoryContextSwitchTo(oldcontext);	/*	 * Execute AFTER STATEMENT insertion triggers	 */	ExecASInsertTriggers(estate, resultRelInfo);	pfree(values);	pfree(nulls);	if (!binary)	{		pfree(in_functions);		pfree(elements);	}	ExecDropTupleTable(tupleTable, true);	ExecCloseIndices(resultRelInfo);	FreeExecutorState(estate);}/* * Read the next input line and stash it in line_buf, with conversion to * server encoding. * * Result is true if read was terminated by EOF, false if terminated * by newline. */static boolCopyReadLine(void){	bool		result;	bool		change_encoding = (client_encoding != server_encoding);	int			c;	int			mblen;	int			j;	unsigned char s[2];	char	   *cvt;	s[1] = 0;	/* reset line_buf to empty */	line_buf.len = 0;	line_buf.data[0] = '\0';	line_buf.cursor = 0;	/* mark that encoding conversion hasn't occurred yet */	line_buf_converted = false;	/* set default status */	result = false;	/*	 * In this loop we only care for detecting newlines (\r and/or \n)	 * and the end-of-copy marker (\.).  For backwards compatibility	 * we allow backslashes to escape newline characters.  Backslashes	 * other than the end marker get put into the line_buf, since	 * CopyReadAttribute does its own escape processing.  These four	 * characters, and only these four, are assumed the same in frontend	 * and backend encodings.  We do not assume that second and later bytes	 * of a frontend multibyte character couldn't look like ASCII characters.	 */	for (;;)	{		c = CopyGetChar();		if (c == EOF)		{			result = true;			break;		}		if (c == '\r')		{			if (eol_type == EOL_NL)				ereport(ERROR,						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),						 errmsg("literal carriage return found in data"),				  errhint("Use \"\\r\" to represent carriage return.")));			/* Check for \r\n on first line, _and_ handle \r\n. */			if (eol_type == EOL_UNKNOWN || eol_type == EOL_CRNL)			{				int			c2 = CopyPeekChar();				if (c2 == '\n')				{					CopyDonePeek(c2, true);		/* eat newline */					eol_type = EOL_CRNL;				}				else				{					/* found \r, but no \n */					if (eol_type == EOL_CRNL)						ereport(ERROR,								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),						 errmsg("literal carriage return found in data"),								 errhint("Use \"\\r\" to represent carriage return.")));					/*					 * if we got here, it is the first line and we didn't					 * get \n, so put it back					 */					CopyDonePeek(c2, false);					eol_type = EOL_CR;				}			}			break;		}		if (c == '\n')		{			if (eol_type == EOL_CR || eol_type == EOL_CRNL)				ereport(ERROR,						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),						 errmsg("literal newline found in data"),						 errhint("Use \"\\n\" to represent newline.")));			eol_type = EOL_NL;			break;		}		if (c == '\\')		{			c = CopyGetChar();			if (c == EOF)			{				result = true;				break;			}			if (c == '.')			{				if (eol_type == EOL_CRNL)				{					c = CopyGetChar();					if (c == '\n')						ereport(ERROR,								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),								 errmsg("end-of-copy marker does not match previous newline style")));					if (c != '\r')						ereport(ERROR,								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),								 errmsg("end-of-copy marker corrupt")));				}				c = CopyGetChar();				if (c != '\r' && c != '\n')					ereport(ERROR,							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),							 errmsg("end-of-copy marker corrupt")));				if ((eol_type == EOL_NL && c != '\n') ||					(eol_type == EOL_CRNL && c != '\n') ||					(eol_type == EOL_CR && c != '\r'))					ereport(ERROR,							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),							 errmsg("end-of-copy marker does not match previous newline style")));				/*				 * In protocol version 3, we should ignore anything				 * after \. up to the protocol end of copy data.  (XXX				 * maybe better not to treat \. as special?)				 */				if (copy_dest == COPY_NEW_FE)				{					while (c != EOF)						c = CopyGetChar();				}				result = true;	/* report EOF */				break;			}			/* not EOF mark, so emit \ and following char literally */			appendStringInfoCharMacro(&line_buf, '\\');		}		appendStringInfoCharMacro(&line_buf, c);		/*		 * When client encoding != server, must be careful to read the		 * extra bytes of a multibyte character exactly, since the encoding		 * might not ensure they don't look like ASCII.  When the encodings		 * are the same, we need not do this, since no server encoding we		 * use has ASCII-like following bytes.		 */		if (change_encoding)		{			s[0] = c;			mblen = pg_encoding_mblen(client_encoding, s);			for (j = 1; j < mblen; j++)			{				c = CopyGetChar();				if (c == EOF)				{					result = true;					break;				}				appendStringInfoCharMacro(&line_buf, c);			}			if (result)				break;			/* out of outer loop */		}	} /* end of outer loop */	/*	 * Done reading the line.  Convert it to server encoding.	 *	 * Note: set line_buf_converted to true *before* attempting conversion;	 * this prevents infinite recursion during error reporting should	 * pg_client_to_server() issue an error, due to copy_in_error_callback	 * again attempting the same conversion.  We'll end up issuing the message	 * without conversion, which is bad but better than nothing ...	 */	line_buf_converted = true;	if (change_encoding)	{		cvt = (char *) pg_client_to_server((unsigned char *) line_buf.data,										   line_buf.len);		if (cvt != line_buf.data)		{			/* transfer converted data back to line_buf */			line_buf.len = 0;			line_buf.data[0] = '\0';			appendBinaryStringInfo(&line_buf, cvt, strlen(cvt));		}	}	return result;}/*---------- * Read the value of a single attribute, performing de-escaping as needed. * * delim is the column delimiter string (must be just one byte for now). * null_print is the null marker string.  Note that this is compared to * the pre-de-escaped input string. * * *result is set to indicate what terminated the read: *		NORMAL_ATTR:	column delimiter *		END_OF_LINE:	end of line * In either case, the string read up to the terminator is returned. * * *isnull is set true or false depending on whether the input matched * the null marker.  Note that the caller cannot check this since the * returned string will be the post-de-escaping equivalent, which may * look the same as some valid data string. *---------- */static char *CopyReadAttribute(const char *delim, const char *null_print,				  CopyReadResult *result, bool *isnull){	char		c;	char		delimc = delim[0];	int			start_cursor = line_buf.cursor;	int			end_cursor;	int			input_len;	/* reset attribute_buf to empty */	attribute_buf.len = 0;	attribute_buf.data[0] = '\0';	/* set default status */	*result = END_OF_LINE;	for (;;)	{		end_cursor = line_buf.cursor;		if (line_buf.cursor >= line_buf.len)			break;		c = line_buf.data[line_buf.cursor++];		if (c == delimc)		{			*result = NORMAL_ATTR;			break;		}		if (c == '\\')		{			if (line_buf.cursor >= line_buf.len)				break;			c = line_buf.data[line_buf.cursor++];			switch (c)			{				case '0':				case '1':				case '2':				case '3':				case '4':				case '5':				case '6':				case '7':					{						int			val;						val = OCTVALUE(c);						if (line_buf.cursor < line_buf.len)						{							c = line_buf.data[line_buf.cursor];							if (ISOCTAL(c))							{								line_buf.cursor++;								val = (val << 3) + OCTVALUE(c);								if (line_buf.cursor < line_buf.len)								{									c = line_buf.data[line_buf.cursor];									if (ISOCTAL(c))									{										line_buf.cursor++;										val = (val << 3) + OCTVALUE(c);									}								}							}						}						c = val & 0377;					}					break;				case 'b':					c = '\b';					break;				case 'f':					c = '\f';					break;				case 'n':					c = '\n';					break;				case 'r':					c = '\r';					break;				case 't':					c = '\t';					break;				case 'v':					c = '\v';					break;				/*				 * in all other cases, take the char after '\' literally				 */			}		}		appendStringInfoCharMacro(&attribute_buf, c);	}	/* check whether raw input matched null marker */	input_len = end_cursor - start_cursor;	if (input_len == strlen(null_print) &&		strncmp(&line_buf.data[start_cursor], null_print, input_len) == 0)		*isnull = true;	else		*isnull = false;	return attribute_buf.data;}/* * Read a binary attribute */static DatumCopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,						bool *isnull){	int32		fld_size;	Datum		result;	fld_size = CopyGetInt32();	if (CopyGetEof())		ereport(ERROR,				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),				 errmsg("unexpected EOF in COPY data")));	if (fld_size == -1)	{		*isnull = true;		return (Datum) 0;	}	if (fld_size < 0)		ereport(ERROR,				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),				 errmsg("invalid field size")));	/* reset attribute_buf to empty, and load raw data in it */	attribute_buf.len = 0;	attribute_buf.data[0] = '\0';	attribute_buf.cursor = 0;	enlargeStringInfo(&attribute_buf, fld_size);	CopyGetData(attribute_buf.data, fld_size);	if (CopyGetEof())		ereport(ERROR,				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),				 errmsg("unexpected EOF in COPY data")));	attribute_buf.len = fld_size;	attribute_buf.data[fld_size] = '\0';	/* Call the column type's binary input converter */	result = FunctionCall2(flinfo,						   PointerGetDatum(&attribute_buf),						   ObjectIdGetDatum(typelem));	/* Trouble if it didn't eat the whole buffer */	if (attribute_buf.cursor != attribute_buf.len)		ereport(ERROR,				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),				 errmsg("incorrect binary data format")));	*isnull = false;	return result;}/* * Send text representation of one attribute, with conversion and escaping */static voidCopyAttributeOut(char *server_string, char *delim){	char	   *string;	char		c;	char		delimc = delim[0];	bool		same_encoding;	int			mblen;	int			i;	same_encoding = (server_encoding == client_encoding);	if (!same_encoding)		string = (char *) pg_server_to_client((unsigned char *) server_string,											  strlen(server_string));	else		string = server_string;	for (; (c = *string) != '\0'; string += mblen)	{		mblen = 1;		switch (c)		{			case '\b':				CopySendString("\\b");				break;			case '\f':				CopySendString("\\f");				break;			case '\n':				CopySendString("\\n");				break;			case '\r':				CopySendString("\\r");				break;			case '\t':				CopySendString("\\t");				break;			case '\v':				CopySendString("\\v");				break;			case '\\':				CopySendString("\\\\");				break;			default:				if (c == delimc)					CopySendChar('\\');				CopySendChar(c);				/*				 * We can skip pg_encoding_mblen() overhead when encoding				 * is same, because in valid backend encodings, extra				 * bytes of a multibyte character never look like ASCII.				 */				if (!same_encoding)				{					/* send additional bytes of the char, if any */					mblen = pg_encoding_mblen(client_encoding, string);					for (i = 1; i < mblen; i++)						CopySendChar(string[i]);				}				break;		}	}}/* * 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 List *CopyGetAttnums(Relation rel, List *attnamelist){	List	   *attnums = NIL;	if (attnamelist == NIL)	{		/* 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 (attr[i]->attisdropped)				continue;			attnums = lappendi(attnums, i + 1);		}	}	else	{		/* Validate the user-supplied list and extract attnums */		List	   *l;		foreach(l, attnamelist)		{			char	   *name = strVal(lfirst(l));			int			attnum;			/* Lookup column name, ereport on failure */			/* Note we disallow system columns here */			attnum = attnameAttNum(rel, name, false);			/* Check for duplicates */			if (intMember(attnum, attnums))				ereport(ERROR,						(errcode(ERRCODE_DUPLICATE_COLUMN),					  errmsg("column \"%s\" specified more than once",							 name)));			attnums = lappendi(attnums, attnum);		}	}	return attnums;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?