Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
P
postgres-lambda-diff
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Jakob Huber
postgres-lambda-diff
Commits
62c3e61e
Commit
62c3e61e
authored
20 years ago
by
Tom Lane
Browse files
Options
Downloads
Patches
Plain Diff
Add binary I/O support for composite types.
parent
f24c5098
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/backend/utils/adt/rowtypes.c
+291
-28
291 additions, 28 deletions
src/backend/utils/adt/rowtypes.c
with
291 additions
and
28 deletions
src/backend/utils/adt/rowtypes.c
+
291
−
28
View file @
62c3e61e
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.
2
2004/06/06
04:50
:2
8
tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.
3
2004/06/06
18:06
:2
5
tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -54,8 +54,9 @@ record_in(PG_FUNCTION_ARGS)
{
char
*
string
=
PG_GETARG_CSTRING
(
0
);
Oid
tupType
=
PG_GETARG_OID
(
1
);
HeapTuple
tuple
;
int32
tupTypmod
;
TupleDesc
tupdesc
;
HeapTuple
tuple
;
RecordIOData
*
my_extra
;
int
ncolumns
;
int
i
;
...
...
@@ -74,7 +75,8 @@ record_in(PG_FUNCTION_ARGS)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_FEATURE_NOT_SUPPORTED
),
errmsg
(
"input of anonymous composite types is not implemented"
)));
tupdesc
=
lookup_rowtype_tupdesc
(
tupType
,
-
1
);
tupTypmod
=
-
1
;
/* for all non-anonymous types */
tupdesc
=
lookup_rowtype_tupdesc
(
tupType
,
tupTypmod
);
ncolumns
=
tupdesc
->
natts
;
/*
...
...
@@ -91,17 +93,17 @@ record_in(PG_FUNCTION_ARGS)
+
ncolumns
*
sizeof
(
ColumnIOData
));
my_extra
=
(
RecordIOData
*
)
fcinfo
->
flinfo
->
fn_extra
;
my_extra
->
record_type
=
InvalidOid
;
my_extra
->
record_typmod
=
-
1
;
my_extra
->
record_typmod
=
0
;
}
if
(
my_extra
->
record_type
!=
tupType
||
my_extra
->
record_typmod
!=
-
1
)
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
=
-
1
;
my_extra
->
record_typmod
=
tupTypmod
;
my_extra
->
ncolumns
=
ncolumns
;
}
...
...
@@ -109,7 +111,8 @@ record_in(PG_FUNCTION_ARGS)
nulls
=
(
char
*
)
palloc
(
ncolumns
*
sizeof
(
char
));
/*
* Scan the string.
* 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 */
...
...
@@ -126,8 +129,9 @@ record_in(PG_FUNCTION_ARGS)
for
(
i
=
0
;
i
<
ncolumns
;
i
++
)
{
ColumnIOData
*
column_info
=
&
my_extra
->
columns
[
i
];
Oid
column_type
=
tupdesc
->
attrs
[
i
]
->
atttypid
;
/* Check for null */
/* Check for
null: completely empty input means
null */
if
(
*
ptr
==
','
||
*
ptr
==
')'
)
{
values
[
i
]
=
(
Datum
)
0
;
...
...
@@ -179,14 +183,14 @@ record_in(PG_FUNCTION_ARGS)
/*
* Convert the column value
*/
if
(
column_info
->
column_type
!=
tupdesc
->
attrs
[
i
]
->
att
typ
id
)
if
(
column_info
->
column_type
!=
column_
typ
e
)
{
getTypeInputInfo
(
tupdesc
->
attrs
[
i
]
->
att
typ
id
,
getTypeInputInfo
(
column_
typ
e
,
&
column_info
->
typiofunc
,
&
column_info
->
typioparam
);
fmgr_info_cxt
(
column_info
->
typiofunc
,
&
column_info
->
proc
,
fcinfo
->
flinfo
->
fn_mcxt
);
column_info
->
column_type
=
tupdesc
->
attrs
[
i
]
->
att
typ
id
;
column_info
->
column_type
=
column_
typ
e
;
}
values
[
i
]
=
FunctionCall3
(
&
column_info
->
proc
,
...
...
@@ -219,6 +223,7 @@ record_in(PG_FUNCTION_ARGS)
}
}
/* The check for ')' here is redundant except when ncolumns == 0 */
if
(
*
ptr
++
!=
')'
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_INVALID_TEXT_REPRESENTATION
),
...
...
@@ -274,6 +279,7 @@ record_out(PG_FUNCTION_ARGS)
tupTypmod
=
-
1
;
tupdesc
=
lookup_rowtype_tupdesc
(
tupType
,
tupTypmod
);
ncolumns
=
tupdesc
->
natts
;
/* Build a temporary HeapTuple control structure */
tuple
.
t_len
=
HeapTupleHeaderGetDatumLength
(
rec
);
ItemPointerSetInvalid
(
&
(
tuple
.
t_self
));
...
...
@@ -294,7 +300,7 @@ record_out(PG_FUNCTION_ARGS)
+
ncolumns
*
sizeof
(
ColumnIOData
));
my_extra
=
(
RecordIOData
*
)
fcinfo
->
flinfo
->
fn_extra
;
my_extra
->
record_type
=
InvalidOid
;
my_extra
->
record_typmod
=
-
1
;
my_extra
->
record_typmod
=
0
;
}
if
(
my_extra
->
record_type
!=
tupType
||
...
...
@@ -308,9 +314,10 @@ record_out(PG_FUNCTION_ARGS)
my_extra
->
ncolumns
=
ncolumns
;
}
/* Break down the tuple into fields */
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 */
...
...
@@ -321,6 +328,7 @@ record_out(PG_FUNCTION_ARGS)
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
;
...
...
@@ -335,19 +343,19 @@ record_out(PG_FUNCTION_ARGS)
}
/*
* Convert the column value
* Convert the column value
to text
*/
if
(
column_info
->
column_type
!=
tupdesc
->
attrs
[
i
]
->
att
typ
id
)
if
(
column_info
->
column_type
!=
column_
typ
e
)
{
bool
typIsVarlena
;
getTypeOutputInfo
(
tupdesc
->
attrs
[
i
]
->
att
typ
id
,
getTypeOutputInfo
(
column_
typ
e
,
&
column_info
->
typiofunc
,
&
column_info
->
typioparam
,
&
typIsVarlena
);
fmgr_info_cxt
(
column_info
->
typiofunc
,
&
column_info
->
proc
,
fcinfo
->
flinfo
->
fn_mcxt
);
column_info
->
column_type
=
tupdesc
->
attrs
[
i
]
->
att
typ
id
;
column_info
->
column_type
=
column_
typ
e
;
}
value
=
DatumGetCString
(
FunctionCall3
(
&
column_info
->
proc
,
...
...
@@ -370,6 +378,7 @@ record_out(PG_FUNCTION_ARGS)
}
}
/* And emit the string */
if
(
nq
)
appendStringInfoChar
(
&
buf
,
'"'
);
for
(
tmp
=
value
;
*
tmp
;
tmp
++
)
...
...
@@ -377,7 +386,7 @@ record_out(PG_FUNCTION_ARGS)
char
ch
=
*
tmp
;
if
(
ch
==
'"'
||
ch
==
'\\'
)
appendStringInfoChar
(
&
buf
,
'\\'
);
appendStringInfoChar
(
&
buf
,
ch
);
appendStringInfoChar
(
&
buf
,
ch
);
}
if
(
nq
)
...
...
@@ -398,12 +407,154 @@ record_out(PG_FUNCTION_ARGS)
Datum
record_recv
(
PG_FUNCTION_ARGS
)
{
/* Need to decide on external format before we can write this */
ereport
(
ERROR
,
(
errcode
(
ERRCODE_FEATURE_NOT_SUPPORTED
),
errmsg
(
"input of composite types not implemented yet"
)));
StringInfo
buf
=
(
StringInfo
)
PG_GETARG_POINTER
(
0
);
Oid
tupType
=
PG_GETARG_OID
(
1
);
int32
tupTypmod
;
TupleDesc
tupdesc
;
HeapTuple
tuple
;
RecordIOData
*
my_extra
;
int
ncolumns
;
int
i
;
Datum
*
values
;
char
*
nulls
;
PG_RETURN_VOID
();
/* keep compiler quiet */
/*
* 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
));
/* Verify number of columns */
i
=
pq_getmsgint
(
buf
,
4
);
if
(
i
!=
ncolumns
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_DATATYPE_MISMATCH
),
errmsg
(
"wrong number of columns: %d, expected %d"
,
i
,
ncolumns
)));
/* 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
;
/* 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 */
values
[
i
]
=
(
Datum
)
0
;
nulls
[
i
]
=
'n'
;
}
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.
*/
StringInfoData
item_buf
;
char
csave
;
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'
;
/* 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
]
=
FunctionCall2
(
&
column_info
->
proc
,
PointerGetDatum
(
&
item_buf
),
ObjectIdGetDatum
(
column_info
->
typioparam
));
nulls
[
i
]
=
' '
;
/* 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
);
pfree
(
values
);
pfree
(
nulls
);
PG_RETURN_HEAPTUPLEHEADER
(
tuple
->
t_data
);
}
/*
...
...
@@ -412,10 +563,122 @@ record_recv(PG_FUNCTION_ARGS)
Datum
record_send
(
PG_FUNCTION_ARGS
)
{
/* Need to decide on external format before we can write this */
ereport
(
ERROR
,
(
errcode
(
ERRCODE_FEATURE_NOT_SUPPORTED
),
errmsg
(
"output of composite types not implemented yet"
)));
HeapTupleHeader
rec
=
PG_GETARG_HEAPTUPLEHEADER
(
0
);
Oid
tupType
=
PG_GETARG_OID
(
1
);
int32
tupTypmod
;
TupleDesc
tupdesc
;
HeapTupleData
tuple
;
RecordIOData
*
my_extra
;
int
ncolumns
;
int
i
;
Datum
*
values
;
char
*
nulls
;
StringInfoData
buf
;
/*
* Use the passed type unless it's RECORD; in that case, we'd better
* get the type info out of the datum itself. Note that for RECORD,
* what we'll probably actually get is RECORD's typelem, ie, zero.
*/
if
(
tupType
==
InvalidOid
||
tupType
==
RECORDOID
)
{
tupType
=
HeapTupleHeaderGetTypeId
(
rec
);
tupTypmod
=
HeapTupleHeaderGetTypMod
(
rec
);
}
else
tupTypmod
=
-
1
;
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
);
pq_sendint
(
&
buf
,
ncolumns
,
4
);
for
(
i
=
0
;
i
<
ncolumns
;
i
++
)
{
ColumnIOData
*
column_info
=
&
my_extra
->
columns
[
i
];
Oid
column_type
=
tupdesc
->
attrs
[
i
]
->
atttypid
;
bytea
*
outputbytes
;
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
,
&
column_info
->
typioparam
,
&
typIsVarlena
);
fmgr_info_cxt
(
column_info
->
typiofunc
,
&
column_info
->
proc
,
fcinfo
->
flinfo
->
fn_mcxt
);
column_info
->
column_type
=
column_type
;
}
outputbytes
=
DatumGetByteaP
(
FunctionCall2
(
&
column_info
->
proc
,
values
[
i
],
ObjectIdGetDatum
(
column_info
->
typioparam
)));
/* 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
);
PG_RETURN_
VOID
();
/* keep compiler quiet */
PG_RETURN_
BYTEA_P
(
pq_endtypsend
(
&
buf
));
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment