Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
62c3e61e
Commit
62c3e61e
authored
Jun 06, 2004
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add binary I/O support for composite types.
parent
f24c5098
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
291 additions
and
28 deletions
+291
-28
src/backend/utils/adt/rowtypes.c
src/backend/utils/adt/rowtypes.c
+291
-28
No files found.
src/backend/utils/adt/rowtypes.c
View file @
62c3e61e
...
...
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.
2 2004/06/06 04:50:28
tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.
3 2004/06/06 18:06:25
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
]
->
atttypid
)
if
(
column_info
->
column_type
!=
column_type
)
{
getTypeInputInfo
(
tupdesc
->
attrs
[
i
]
->
atttypid
,
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
=
tupdesc
->
attrs
[
i
]
->
atttypid
;
column_info
->
column_type
=
column_type
;
}
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
]
->
atttypid
)
if
(
column_info
->
column_type
!=
column_type
)
{
bool
typIsVarlena
;
getTypeOutputInfo
(
tupdesc
->
attrs
[
i
]
->
atttypid
,
getTypeOutputInfo
(
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
=
tupdesc
->
attrs
[
i
]
->
atttypid
;
column_info
->
column_type
=
column_type
;
}
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
));
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment