rowtypes.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 738 行 · 第 1/2 页

C
738
字号
							  &typIsVarlena);			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,						  fcinfo->flinfo->fn_mcxt);			column_info->column_type = column_type;		}		value = OutputFunctionCall(&column_info->proc, values[i]);		/* Detect whether we need double quotes for this value */		nq = (value[0] == '\0');	/* force quotes for empty string */		for (tmp = value; *tmp; tmp++)		{			char		ch = *tmp;			if (ch == '"' || ch == '\\' ||				ch == '(' || ch == ')' || ch == ',' ||				isspace((unsigned char) ch))			{				nq = true;				break;			}		}		/* And emit the string */		if (nq)			appendStringInfoChar(&buf, '"');		for (tmp = value; *tmp; tmp++)		{			char		ch = *tmp;			if (ch == '"' || ch == '\\')				appendStringInfoChar(&buf, ch);			appendStringInfoChar(&buf, ch);		}		if (nq)			appendStringInfoChar(&buf, '"');	}	appendStringInfoChar(&buf, ')');	pfree(values);	pfree(nulls);	ReleaseTupleDesc(tupdesc);	PG_RETURN_CSTRING(buf.data);}/* * record_recv		- binary input routine for any composite type. */Datumrecord_recv(PG_FUNCTION_ARGS){	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);	Oid			tupType = PG_GETARG_OID(1);#ifdef NOT_USED	int32		typmod = PG_GETARG_INT32(2);#endif	HeapTupleHeader result;	int32		tupTypmod;	TupleDesc	tupdesc;	HeapTuple	tuple;	RecordIOData *my_extra;	int			ncolumns;	int			usercols;	int			validcols;	int			i;	Datum	   *values;	char	   *nulls;	/*	 * Use the passed type unless it's RECORD; we can't support input of	 * anonymous types, mainly because there's no good way to figure out which	 * anonymous type is wanted.  Note that for RECORD, what we'll probably	 * actually get is RECORD's typelem, ie, zero.	 */	if (tupType == InvalidOid || tupType == RECORDOID)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),		   errmsg("input of anonymous composite types is not implemented")));	tupTypmod = -1;				/* for all non-anonymous types */	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);	ncolumns = tupdesc->natts;	/*	 * We arrange to look up the needed I/O info just once per series of	 * calls, assuming the record type doesn't change underneath us.	 */	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;	if (my_extra == NULL ||		my_extra->ncolumns != ncolumns)	{		fcinfo->flinfo->fn_extra =			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,							   sizeof(RecordIOData) - sizeof(ColumnIOData)							   + ncolumns * sizeof(ColumnIOData));		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;		my_extra->record_type = InvalidOid;		my_extra->record_typmod = 0;	}	if (my_extra->record_type != tupType ||		my_extra->record_typmod != tupTypmod)	{		MemSet(my_extra, 0,			   sizeof(RecordIOData) - sizeof(ColumnIOData)			   + ncolumns * sizeof(ColumnIOData));		my_extra->record_type = tupType;		my_extra->record_typmod = tupTypmod;		my_extra->ncolumns = ncolumns;	}	values = (Datum *) palloc(ncolumns * sizeof(Datum));	nulls = (char *) palloc(ncolumns * sizeof(char));	/* Fetch number of columns user thinks it has */	usercols = pq_getmsgint(buf, 4);	/* Need to scan to count nondeleted columns */	validcols = 0;	for (i = 0; i < ncolumns; i++)	{		if (!tupdesc->attrs[i]->attisdropped)			validcols++;	}	if (usercols != validcols)		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("wrong number of columns: %d, expected %d",						usercols, validcols)));	/* Process each column */	for (i = 0; i < ncolumns; i++)	{		ColumnIOData *column_info = &my_extra->columns[i];		Oid			column_type = tupdesc->attrs[i]->atttypid;		Oid			coltypoid;		int			itemlen;		StringInfoData item_buf;		StringInfo	bufptr;		char		csave;		/* Ignore dropped columns in datatype, but fill with nulls */		if (tupdesc->attrs[i]->attisdropped)		{			values[i] = (Datum) 0;			nulls[i] = 'n';			continue;		}		/* Verify column datatype */		coltypoid = pq_getmsgint(buf, sizeof(Oid));		if (coltypoid != column_type)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),					 errmsg("wrong data type: %u, expected %u",							coltypoid, column_type)));		/* Get and check the item length */		itemlen = pq_getmsgint(buf, 4);		if (itemlen < -1 || itemlen > (buf->len - buf->cursor))			ereport(ERROR,					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),					 errmsg("insufficient data left in message")));		if (itemlen == -1)		{			/* -1 length means NULL */			bufptr = NULL;			nulls[i] = 'n';			csave = 0;			/* keep compiler quiet */		}		else		{			/*			 * Rather than copying data around, we just set up a phony			 * StringInfo pointing to the correct portion of the input buffer.			 * We assume we can scribble on the input buffer so as to maintain			 * the convention that StringInfos have a trailing null.			 */			item_buf.data = &buf->data[buf->cursor];			item_buf.maxlen = itemlen + 1;			item_buf.len = itemlen;			item_buf.cursor = 0;			buf->cursor += itemlen;			csave = buf->data[buf->cursor];			buf->data[buf->cursor] = '\0';			bufptr = &item_buf;			nulls[i] = ' ';		}		/* Now call the column's receiveproc */		if (column_info->column_type != column_type)		{			getTypeBinaryInputInfo(column_type,								   &column_info->typiofunc,								   &column_info->typioparam);			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,						  fcinfo->flinfo->fn_mcxt);			column_info->column_type = column_type;		}		values[i] = ReceiveFunctionCall(&column_info->proc,										bufptr,										column_info->typioparam,										tupdesc->attrs[i]->atttypmod);		if (bufptr)		{			/* Trouble if it didn't eat the whole buffer */			if (item_buf.cursor != itemlen)				ereport(ERROR,						(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),						 errmsg("improper binary format in record column %d",								i + 1)));			buf->data[buf->cursor] = csave;		}	}	tuple = heap_formtuple(tupdesc, values, nulls);	/*	 * We cannot return tuple->t_data because heap_formtuple allocates it as	 * part of a larger chunk, and our caller may expect to be able to pfree	 * our result.	So must copy the info into a new palloc chunk.	 */	result = (HeapTupleHeader) palloc(tuple->t_len);	memcpy(result, tuple->t_data, tuple->t_len);	heap_freetuple(tuple);	pfree(values);	pfree(nulls);	ReleaseTupleDesc(tupdesc);	PG_RETURN_HEAPTUPLEHEADER(result);}/* * record_send		- binary output routine for any composite type. */Datumrecord_send(PG_FUNCTION_ARGS){	HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);	Oid			tupType;	int32		tupTypmod;	TupleDesc	tupdesc;	HeapTupleData tuple;	RecordIOData *my_extra;	int			ncolumns;	int			validcols;	int			i;	Datum	   *values;	char	   *nulls;	StringInfoData buf;	/* Extract type info from the tuple itself */	tupType = HeapTupleHeaderGetTypeId(rec);	tupTypmod = HeapTupleHeaderGetTypMod(rec);	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);	ncolumns = tupdesc->natts;	/* Build a temporary HeapTuple control structure */	tuple.t_len = HeapTupleHeaderGetDatumLength(rec);	ItemPointerSetInvalid(&(tuple.t_self));	tuple.t_tableOid = InvalidOid;	tuple.t_data = rec;	/*	 * We arrange to look up the needed I/O info just once per series of	 * calls, assuming the record type doesn't change underneath us.	 */	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;	if (my_extra == NULL ||		my_extra->ncolumns != ncolumns)	{		fcinfo->flinfo->fn_extra =			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,							   sizeof(RecordIOData) - sizeof(ColumnIOData)							   + ncolumns * sizeof(ColumnIOData));		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;		my_extra->record_type = InvalidOid;		my_extra->record_typmod = 0;	}	if (my_extra->record_type != tupType ||		my_extra->record_typmod != tupTypmod)	{		MemSet(my_extra, 0,			   sizeof(RecordIOData) - sizeof(ColumnIOData)			   + ncolumns * sizeof(ColumnIOData));		my_extra->record_type = tupType;		my_extra->record_typmod = tupTypmod;		my_extra->ncolumns = ncolumns;	}	values = (Datum *) palloc(ncolumns * sizeof(Datum));	nulls = (char *) palloc(ncolumns * sizeof(char));	/* Break down the tuple into fields */	heap_deformtuple(&tuple, tupdesc, values, nulls);	/* And build the result string */	pq_begintypsend(&buf);	/* Need to scan to count nondeleted columns */	validcols = 0;	for (i = 0; i < ncolumns; i++)	{		if (!tupdesc->attrs[i]->attisdropped)			validcols++;	}	pq_sendint(&buf, validcols, 4);	for (i = 0; i < ncolumns; i++)	{		ColumnIOData *column_info = &my_extra->columns[i];		Oid			column_type = tupdesc->attrs[i]->atttypid;		bytea	   *outputbytes;		/* Ignore dropped columns in datatype */		if (tupdesc->attrs[i]->attisdropped)			continue;		pq_sendint(&buf, column_type, sizeof(Oid));		if (nulls[i] == 'n')		{			/* emit -1 data length to signify a NULL */			pq_sendint(&buf, -1, 4);			continue;		}		/*		 * Convert the column value to binary		 */		if (column_info->column_type != column_type)		{			bool		typIsVarlena;			getTypeBinaryOutputInfo(column_type,									&column_info->typiofunc,									&typIsVarlena);			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,						  fcinfo->flinfo->fn_mcxt);			column_info->column_type = column_type;		}		outputbytes = SendFunctionCall(&column_info->proc, values[i]);		/* We assume the result will not have been toasted */		pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);		pq_sendbytes(&buf, VARDATA(outputbytes),					 VARSIZE(outputbytes) - VARHDRSZ);		pfree(outputbytes);	}	pfree(values);	pfree(nulls);	ReleaseTupleDesc(tupdesc);	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));}

⌨️ 快捷键说明

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