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
a3704d3d
Commit
a3704d3d
authored
Jun 06, 2004
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Preliminary support for composite type I/O; just text for now,
no binary yet.
parent
c541bb86
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
357 additions
and
11 deletions
+357
-11
src/backend/utils/adt/rowtypes.c
src/backend/utils/adt/rowtypes.c
+357
-11
No files found.
src/backend/utils/adt/rowtypes.c
View file @
a3704d3d
...
...
@@ -8,14 +8,42 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.
1 2004/04/01 21:28:45
tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/rowtypes.c,v 1.
2 2004/06/06 04:50:28
tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <ctype.h>
#include "access/heapam.h"
#include "access/htup.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.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
;
/*
...
...
@@ -24,12 +52,194 @@
Datum
record_in
(
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"
)));
char
*
string
=
PG_GETARG_CSTRING
(
0
);
Oid
tupType
=
PG_GETARG_OID
(
1
);
HeapTuple
tuple
;
TupleDesc
tupdesc
;
RecordIOData
*
my_extra
;
int
ncolumns
;
int
i
;
char
*
ptr
;
Datum
*
values
;
char
*
nulls
;
StringInfoData
buf
;
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"
)));
tupdesc
=
lookup_rowtype_tupdesc
(
tupType
,
-
1
);
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
=
-
1
;
}
if
(
my_extra
->
record_type
!=
tupType
||
my_extra
->
record_typmod
!=
-
1
)
{
MemSet
(
my_extra
,
0
,
sizeof
(
RecordIOData
)
-
sizeof
(
ColumnIOData
)
+
ncolumns
*
sizeof
(
ColumnIOData
));
my_extra
->
record_type
=
tupType
;
my_extra
->
record_typmod
=
-
1
;
my_extra
->
ncolumns
=
ncolumns
;
}
values
=
(
Datum
*
)
palloc
(
ncolumns
*
sizeof
(
Datum
));
nulls
=
(
char
*
)
palloc
(
ncolumns
*
sizeof
(
char
));
/*
* Scan the string.
*/
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
];
/* Check for null */
if
(
*
ptr
==
','
||
*
ptr
==
')'
)
{
values
[
i
]
=
(
Datum
)
0
;
nulls
[
i
]
=
'n'
;
}
else
{
/* Extract string for this column */
bool
inquote
=
false
;
buf
.
len
=
0
;
buf
.
data
[
0
]
=
'\0'
;
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
);
}
/*
* Convert the column value
*/
if
(
column_info
->
column_type
!=
tupdesc
->
attrs
[
i
]
->
atttypid
)
{
getTypeInputInfo
(
tupdesc
->
attrs
[
i
]
->
atttypid
,
&
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
;
}
values
[
i
]
=
FunctionCall3
(
&
column_info
->
proc
,
CStringGetDatum
(
buf
.
data
),
ObjectIdGetDatum
(
column_info
->
typioparam
),
Int32GetDatum
(
tupdesc
->
attrs
[
i
]
->
atttypmod
));
nulls
[
i
]
=
' '
;
}
/*
* Prep for next column
*/
if
(
*
ptr
==
','
)
{
if
(
i
==
ncolumns
-
1
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_INVALID_TEXT_REPRESENTATION
),
errmsg
(
"malformed record literal:
\"
%s
\"
"
,
string
),
errdetail
(
"Too many columns."
)));
ptr
++
;
}
else
{
/* *ptr must be ')' */
if
(
i
<
ncolumns
-
1
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_INVALID_TEXT_REPRESENTATION
),
errmsg
(
"malformed record literal:
\"
%s
\"
"
,
string
),
errdetail
(
"Too few columns."
)));
}
}
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
);
pfree
(
buf
.
data
);
pfree
(
values
);
pfree
(
nulls
);
PG_RETURN_HEAPTUPLEHEADER
(
tuple
->
t_data
);
}
/*
...
...
@@ -38,12 +248,148 @@ record_in(PG_FUNCTION_ARGS)
Datum
record_out
(
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
;
PG_RETURN_VOID
();
/* keep compiler quiet */
/*
* 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
=
-
1
;
}
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
;
}
/* Break down the tuple into fields */
values
=
(
Datum
*
)
palloc
(
ncolumns
*
sizeof
(
Datum
));
nulls
=
(
char
*
)
palloc
(
ncolumns
*
sizeof
(
char
));
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
];
char
*
value
;
char
*
tmp
;
bool
nq
;
if
(
i
>
0
)
appendStringInfoChar
(
&
buf
,
','
);
if
(
nulls
[
i
]
==
'n'
)
{
/* emit nothing... */
continue
;
}
/*
* Convert the column value
*/
if
(
column_info
->
column_type
!=
tupdesc
->
attrs
[
i
]
->
atttypid
)
{
bool
typIsVarlena
;
getTypeOutputInfo
(
tupdesc
->
attrs
[
i
]
->
atttypid
,
&
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
;
}
value
=
DatumGetCString
(
FunctionCall3
(
&
column_info
->
proc
,
values
[
i
],
ObjectIdGetDatum
(
column_info
->
typioparam
),
Int32GetDatum
(
tupdesc
->
attrs
[
i
]
->
atttypmod
)));
/* 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
;
}
}
if
(
nq
)
appendStringInfoChar
(
&
buf
,
'"'
);
for
(
tmp
=
value
;
*
tmp
;
tmp
++
)
{
char
ch
=
*
tmp
;
if
(
ch
==
'"'
||
ch
==
'\\'
)
appendStringInfoChar
(
&
buf
,
'\\'
);
appendStringInfoChar
(
&
buf
,
ch
);
}
if
(
nq
)
appendStringInfoChar
(
&
buf
,
'"'
);
}
appendStringInfoChar
(
&
buf
,
')'
);
pfree
(
values
);
pfree
(
nulls
);
PG_RETURN_CSTRING
(
buf
.
data
);
}
/*
...
...
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