Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita3704d3

Browse files
committed
Preliminary support for composite type I/O; just text for now,
no binary yet.
1 parentc541bb8 commita3704d3

File tree

1 file changed

+357
-11
lines changed

1 file changed

+357
-11
lines changed

‎src/backend/utils/adt/rowtypes.c

Lines changed: 357 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,42 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.1 2004/04/01 21:28:45 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.2 2004/06/06 04:50:28 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515
#include"postgres.h"
1616

17+
#include<ctype.h>
18+
19+
#include"access/heapam.h"
20+
#include"access/htup.h"
21+
#include"catalog/pg_type.h"
22+
#include"lib/stringinfo.h"
1723
#include"libpq/pqformat.h"
1824
#include"utils/builtins.h"
25+
#include"utils/lsyscache.h"
26+
#include"utils/typcache.h"
27+
28+
29+
/*
30+
* structure to cache metadata needed for record I/O
31+
*/
32+
typedefstructColumnIOData
33+
{
34+
Oidcolumn_type;
35+
Oidtypiofunc;
36+
Oidtypioparam;
37+
FmgrInfoproc;
38+
}ColumnIOData;
39+
40+
typedefstructRecordIOData
41+
{
42+
Oidrecord_type;
43+
int32record_typmod;
44+
intncolumns;
45+
ColumnIODatacolumns[1];/* VARIABLE LENGTH ARRAY */
46+
}RecordIOData;
1947

2048

2149
/*
@@ -24,12 +52,194 @@
2452
Datum
2553
record_in(PG_FUNCTION_ARGS)
2654
{
27-
/* Need to decide on external format before we can write this */
28-
ereport(ERROR,
29-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
30-
errmsg("input of composite types not implemented yet")));
55+
char*string=PG_GETARG_CSTRING(0);
56+
OidtupType=PG_GETARG_OID(1);
57+
HeapTupletuple;
58+
TupleDesctupdesc;
59+
RecordIOData*my_extra;
60+
intncolumns;
61+
inti;
62+
char*ptr;
63+
Datum*values;
64+
char*nulls;
65+
StringInfoDatabuf;
3166

32-
PG_RETURN_VOID();/* keep compiler quiet */
67+
/*
68+
* Use the passed type unless it's RECORD; we can't support input
69+
* of anonymous types, mainly because there's no good way to figure
70+
* out which anonymous type is wanted. Note that for RECORD,
71+
* what we'll probably actually get is RECORD's typelem, ie, zero.
72+
*/
73+
if (tupType==InvalidOid||tupType==RECORDOID)
74+
ereport(ERROR,
75+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
76+
errmsg("input of anonymous composite types is not implemented")));
77+
tupdesc=lookup_rowtype_tupdesc(tupType,-1);
78+
ncolumns=tupdesc->natts;
79+
80+
/*
81+
* We arrange to look up the needed I/O info just once per series of
82+
* calls, assuming the record type doesn't change underneath us.
83+
*/
84+
my_extra= (RecordIOData*)fcinfo->flinfo->fn_extra;
85+
if (my_extra==NULL||
86+
my_extra->ncolumns!=ncolumns)
87+
{
88+
fcinfo->flinfo->fn_extra=
89+
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
90+
sizeof(RecordIOData)-sizeof(ColumnIOData)
91+
+ncolumns*sizeof(ColumnIOData));
92+
my_extra= (RecordIOData*)fcinfo->flinfo->fn_extra;
93+
my_extra->record_type=InvalidOid;
94+
my_extra->record_typmod=-1;
95+
}
96+
97+
if (my_extra->record_type!=tupType||
98+
my_extra->record_typmod!=-1)
99+
{
100+
MemSet(my_extra,0,
101+
sizeof(RecordIOData)-sizeof(ColumnIOData)
102+
+ncolumns*sizeof(ColumnIOData));
103+
my_extra->record_type=tupType;
104+
my_extra->record_typmod=-1;
105+
my_extra->ncolumns=ncolumns;
106+
}
107+
108+
values= (Datum*)palloc(ncolumns*sizeof(Datum));
109+
nulls= (char*)palloc(ncolumns*sizeof(char));
110+
111+
/*
112+
* Scan the string.
113+
*/
114+
ptr=string;
115+
/* Allow leading whitespace */
116+
while (*ptr&&isspace((unsignedchar)*ptr))
117+
ptr++;
118+
if (*ptr++!='(')
119+
ereport(ERROR,
120+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
121+
errmsg("malformed record literal: \"%s\"",string),
122+
errdetail("Missing left parenthesis.")));
123+
124+
initStringInfo(&buf);
125+
126+
for (i=0;i<ncolumns;i++)
127+
{
128+
ColumnIOData*column_info=&my_extra->columns[i];
129+
130+
/* Check for null */
131+
if (*ptr==','||*ptr==')')
132+
{
133+
values[i]= (Datum)0;
134+
nulls[i]='n';
135+
}
136+
else
137+
{
138+
/* Extract string for this column */
139+
boolinquote= false;
140+
141+
buf.len=0;
142+
buf.data[0]='\0';
143+
while (inquote|| !(*ptr==','||*ptr==')'))
144+
{
145+
charch=*ptr++;
146+
147+
if (ch=='\0')
148+
ereport(ERROR,
149+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
150+
errmsg("malformed record literal: \"%s\"",
151+
string),
152+
errdetail("Unexpected end of input.")));
153+
if (ch=='\\')
154+
{
155+
if (*ptr=='\0')
156+
ereport(ERROR,
157+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
158+
errmsg("malformed record literal: \"%s\"",
159+
string),
160+
errdetail("Unexpected end of input.")));
161+
appendStringInfoChar(&buf,*ptr++);
162+
}
163+
elseif (ch=='\"')
164+
{
165+
if (!inquote)
166+
inquote= true;
167+
elseif (*ptr=='\"')
168+
{
169+
/* doubled quote within quote sequence */
170+
appendStringInfoChar(&buf,*ptr++);
171+
}
172+
else
173+
inquote= false;
174+
}
175+
else
176+
appendStringInfoChar(&buf,ch);
177+
}
178+
179+
/*
180+
* Convert the column value
181+
*/
182+
if (column_info->column_type!=tupdesc->attrs[i]->atttypid)
183+
{
184+
getTypeInputInfo(tupdesc->attrs[i]->atttypid,
185+
&column_info->typiofunc,
186+
&column_info->typioparam);
187+
fmgr_info_cxt(column_info->typiofunc,&column_info->proc,
188+
fcinfo->flinfo->fn_mcxt);
189+
column_info->column_type=tupdesc->attrs[i]->atttypid;
190+
}
191+
192+
values[i]=FunctionCall3(&column_info->proc,
193+
CStringGetDatum(buf.data),
194+
ObjectIdGetDatum(column_info->typioparam),
195+
Int32GetDatum(tupdesc->attrs[i]->atttypmod));
196+
nulls[i]=' ';
197+
}
198+
199+
/*
200+
* Prep for next column
201+
*/
202+
if (*ptr==',')
203+
{
204+
if (i==ncolumns-1)
205+
ereport(ERROR,
206+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
207+
errmsg("malformed record literal: \"%s\"",string),
208+
errdetail("Too many columns.")));
209+
ptr++;
210+
}
211+
else
212+
{
213+
/* *ptr must be ')' */
214+
if (i<ncolumns-1)
215+
ereport(ERROR,
216+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
217+
errmsg("malformed record literal: \"%s\"",string),
218+
errdetail("Too few columns.")));
219+
}
220+
}
221+
222+
if (*ptr++!=')')
223+
ereport(ERROR,
224+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
225+
errmsg("malformed record literal: \"%s\"",string),
226+
errdetail("Too many columns.")));
227+
/* Allow trailing whitespace */
228+
while (*ptr&&isspace((unsignedchar)*ptr))
229+
ptr++;
230+
if (*ptr)
231+
ereport(ERROR,
232+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
233+
errmsg("malformed record literal: \"%s\"",string),
234+
errdetail("Junk after right parenthesis.")));
235+
236+
tuple=heap_formtuple(tupdesc,values,nulls);
237+
238+
pfree(buf.data);
239+
pfree(values);
240+
pfree(nulls);
241+
242+
PG_RETURN_HEAPTUPLEHEADER(tuple->t_data);
33243
}
34244

35245
/*
@@ -38,12 +248,148 @@ record_in(PG_FUNCTION_ARGS)
38248
Datum
39249
record_out(PG_FUNCTION_ARGS)
40250
{
41-
/* Need to decide on external format before we can write this */
42-
ereport(ERROR,
43-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
44-
errmsg("output of composite types not implemented yet")));
251+
HeapTupleHeaderrec=PG_GETARG_HEAPTUPLEHEADER(0);
252+
OidtupType=PG_GETARG_OID(1);
253+
int32tupTypmod;
254+
TupleDesctupdesc;
255+
HeapTupleDatatuple;
256+
RecordIOData*my_extra;
257+
intncolumns;
258+
inti;
259+
Datum*values;
260+
char*nulls;
261+
StringInfoDatabuf;
45262

46-
PG_RETURN_VOID();/* keep compiler quiet */
263+
/*
264+
* Use the passed type unless it's RECORD; in that case, we'd better
265+
* get the type info out of the datum itself. Note that for RECORD,
266+
* what we'll probably actually get is RECORD's typelem, ie, zero.
267+
*/
268+
if (tupType==InvalidOid||tupType==RECORDOID)
269+
{
270+
tupType=HeapTupleHeaderGetTypeId(rec);
271+
tupTypmod=HeapTupleHeaderGetTypMod(rec);
272+
}
273+
else
274+
tupTypmod=-1;
275+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
276+
ncolumns=tupdesc->natts;
277+
/* Build a temporary HeapTuple control structure */
278+
tuple.t_len=HeapTupleHeaderGetDatumLength(rec);
279+
ItemPointerSetInvalid(&(tuple.t_self));
280+
tuple.t_tableOid=InvalidOid;
281+
tuple.t_data=rec;
282+
283+
/*
284+
* We arrange to look up the needed I/O info just once per series of
285+
* calls, assuming the record type doesn't change underneath us.
286+
*/
287+
my_extra= (RecordIOData*)fcinfo->flinfo->fn_extra;
288+
if (my_extra==NULL||
289+
my_extra->ncolumns!=ncolumns)
290+
{
291+
fcinfo->flinfo->fn_extra=
292+
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
293+
sizeof(RecordIOData)-sizeof(ColumnIOData)
294+
+ncolumns*sizeof(ColumnIOData));
295+
my_extra= (RecordIOData*)fcinfo->flinfo->fn_extra;
296+
my_extra->record_type=InvalidOid;
297+
my_extra->record_typmod=-1;
298+
}
299+
300+
if (my_extra->record_type!=tupType||
301+
my_extra->record_typmod!=tupTypmod)
302+
{
303+
MemSet(my_extra,0,
304+
sizeof(RecordIOData)-sizeof(ColumnIOData)
305+
+ncolumns*sizeof(ColumnIOData));
306+
my_extra->record_type=tupType;
307+
my_extra->record_typmod=tupTypmod;
308+
my_extra->ncolumns=ncolumns;
309+
}
310+
311+
/* Break down the tuple into fields */
312+
values= (Datum*)palloc(ncolumns*sizeof(Datum));
313+
nulls= (char*)palloc(ncolumns*sizeof(char));
314+
heap_deformtuple(&tuple,tupdesc,values,nulls);
315+
316+
/* And build the result string */
317+
initStringInfo(&buf);
318+
319+
appendStringInfoChar(&buf,'(');
320+
321+
for (i=0;i<ncolumns;i++)
322+
{
323+
ColumnIOData*column_info=&my_extra->columns[i];
324+
char*value;
325+
char*tmp;
326+
boolnq;
327+
328+
if (i>0)
329+
appendStringInfoChar(&buf,',');
330+
331+
if (nulls[i]=='n')
332+
{
333+
/* emit nothing... */
334+
continue;
335+
}
336+
337+
/*
338+
* Convert the column value
339+
*/
340+
if (column_info->column_type!=tupdesc->attrs[i]->atttypid)
341+
{
342+
booltypIsVarlena;
343+
344+
getTypeOutputInfo(tupdesc->attrs[i]->atttypid,
345+
&column_info->typiofunc,
346+
&column_info->typioparam,
347+
&typIsVarlena);
348+
fmgr_info_cxt(column_info->typiofunc,&column_info->proc,
349+
fcinfo->flinfo->fn_mcxt);
350+
column_info->column_type=tupdesc->attrs[i]->atttypid;
351+
}
352+
353+
value=DatumGetCString(FunctionCall3(&column_info->proc,
354+
values[i],
355+
ObjectIdGetDatum(column_info->typioparam),
356+
Int32GetDatum(tupdesc->attrs[i]->atttypmod)));
357+
358+
/* Detect whether we need double quotes for this value */
359+
nq= (value[0]=='\0');/* force quotes for empty string */
360+
for (tmp=value;*tmp;tmp++)
361+
{
362+
charch=*tmp;
363+
364+
if (ch=='"'||ch=='\\'||
365+
ch=='('||ch==')'||ch==','||
366+
isspace((unsignedchar)ch))
367+
{
368+
nq= true;
369+
break;
370+
}
371+
}
372+
373+
if (nq)
374+
appendStringInfoChar(&buf,'"');
375+
for (tmp=value;*tmp;tmp++)
376+
{
377+
charch=*tmp;
378+
379+
if (ch=='"'||ch=='\\')
380+
appendStringInfoChar(&buf,'\\');
381+
appendStringInfoChar(&buf,ch);
382+
}
383+
if (nq)
384+
appendStringInfoChar(&buf,'"');
385+
}
386+
387+
appendStringInfoChar(&buf,')');
388+
389+
pfree(values);
390+
pfree(nulls);
391+
392+
PG_RETURN_CSTRING(buf.data);
47393
}
48394

49395
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp