rowtypes.c

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

C
738
字号
/*------------------------------------------------------------------------- * * rowtypes.c *	  I/O functions for generic composite types. * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.20 2008/01/01 19:45:52 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <ctype.h>#include "access/heapam.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/typcache.h"/* * structure to cache metadata needed for record I/O */typedef struct ColumnIOData{	Oid			column_type;	Oid			typiofunc;	Oid			typioparam;	FmgrInfo	proc;} ColumnIOData;typedef struct RecordIOData{	Oid			record_type;	int32		record_typmod;	int			ncolumns;	ColumnIOData columns[1];	/* VARIABLE LENGTH ARRAY */} RecordIOData;/* * record_in		- input routine for any composite type. */Datumrecord_in(PG_FUNCTION_ARGS){	char	   *string = PG_GETARG_CSTRING(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;	bool		needComma = false;	int			ncolumns;	int			i;	char	   *ptr;	Datum	   *values;	char	   *nulls;	StringInfoData buf;	/*	 * 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));	/*	 * Scan the string.  We use "buf" to accumulate the de-quoted data for	 * each column, which is then fed to the appropriate input converter.	 */	ptr = string;	/* Allow leading whitespace */	while (*ptr && isspace((unsigned char) *ptr))		ptr++;	if (*ptr++ != '(')		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				 errmsg("malformed record literal: \"%s\"", string),				 errdetail("Missing left parenthesis.")));	initStringInfo(&buf);	for (i = 0; i < ncolumns; i++)	{		ColumnIOData *column_info = &my_extra->columns[i];		Oid			column_type = tupdesc->attrs[i]->atttypid;		char	   *column_data;		/* Ignore dropped columns in datatype, but fill with nulls */		if (tupdesc->attrs[i]->attisdropped)		{			values[i] = (Datum) 0;			nulls[i] = 'n';			continue;		}		if (needComma)		{			/* Skip comma that separates prior field from this one */			if (*ptr == ',')				ptr++;			else				/* *ptr must be ')' */				ereport(ERROR,						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),						 errmsg("malformed record literal: \"%s\"", string),						 errdetail("Too few columns.")));		}		/* Check for null: completely empty input means null */		if (*ptr == ',' || *ptr == ')')		{			column_data = NULL;			nulls[i] = 'n';		}		else		{			/* Extract string for this column */			bool		inquote = false;			resetStringInfo(&buf);			while (inquote || !(*ptr == ',' || *ptr == ')'))			{				char		ch = *ptr++;				if (ch == '\0')					ereport(ERROR,							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),							 errmsg("malformed record literal: \"%s\"",									string),							 errdetail("Unexpected end of input.")));				if (ch == '\\')				{					if (*ptr == '\0')						ereport(ERROR,								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),								 errmsg("malformed record literal: \"%s\"",										string),								 errdetail("Unexpected end of input.")));					appendStringInfoChar(&buf, *ptr++);				}				else if (ch == '\"')				{					if (!inquote)						inquote = true;					else if (*ptr == '\"')					{						/* doubled quote within quote sequence */						appendStringInfoChar(&buf, *ptr++);					}					else						inquote = false;				}				else					appendStringInfoChar(&buf, ch);			}			column_data = buf.data;			nulls[i] = ' ';		}		/*		 * Convert the column value		 */		if (column_info->column_type != column_type)		{			getTypeInputInfo(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] = InputFunctionCall(&column_info->proc,									  column_data,									  column_info->typioparam,									  tupdesc->attrs[i]->atttypmod);		/*		 * Prep for next column		 */		needComma = true;	}	if (*ptr++ != ')')		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				 errmsg("malformed record literal: \"%s\"", string),				 errdetail("Too many columns.")));	/* Allow trailing whitespace */	while (*ptr && isspace((unsigned char) *ptr))		ptr++;	if (*ptr)		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),				 errmsg("malformed record literal: \"%s\"", string),				 errdetail("Junk after right parenthesis.")));	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(buf.data);	pfree(values);	pfree(nulls);	ReleaseTupleDesc(tupdesc);	PG_RETURN_HEAPTUPLEHEADER(result);}/* * record_out		- output routine for any composite type. */Datumrecord_out(PG_FUNCTION_ARGS){	HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);	Oid			tupType;	int32		tupTypmod;	TupleDesc	tupdesc;	HeapTupleData tuple;	RecordIOData *my_extra;	bool		needComma = false;	int			ncolumns;	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 */	initStringInfo(&buf);	appendStringInfoChar(&buf, '(');	for (i = 0; i < ncolumns; i++)	{		ColumnIOData *column_info = &my_extra->columns[i];		Oid			column_type = tupdesc->attrs[i]->atttypid;		char	   *value;		char	   *tmp;		bool		nq;		/* Ignore dropped columns in datatype */		if (tupdesc->attrs[i]->attisdropped)			continue;		if (needComma)			appendStringInfoChar(&buf, ',');		needComma = true;		if (nulls[i] == 'n')		{			/* emit nothing... */			continue;		}		/*		 * Convert the column value to text		 */		if (column_info->column_type != column_type)		{			bool		typIsVarlena;			getTypeOutputInfo(column_type,							  &column_info->typiofunc,

⌨️ 快捷键说明

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