mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
Implement array_send/array_recv (binary I/O for arrays). This exposed
the folly of not passing element type to typsend/typreceive, so fix that.
This commit is contained in:
parent
b1ee615a7f
commit
ba1e066e46
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.42 2003/05/08 22:19:56 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.43 2003/05/09 23:01:44 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
@ -117,15 +117,20 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> (
|
||||
representation is in the machine's native byte order.) The receive
|
||||
function should perform adequate checking to ensure that the value is
|
||||
valid.
|
||||
The receive function should be declared as taking one argument of type
|
||||
<type>internal</type> and returning a value of the data type itself.
|
||||
(The argument actually supplied is a pointer to a StringInfo buffer
|
||||
holding the received byte string.) Similarly, the optional
|
||||
The receive function may be declared as taking one argument of type
|
||||
<type>internal</type>, or two arguments of types <type>internal</type>
|
||||
and <type>oid</type>. It must return a value of the data type itself.
|
||||
(The first argument is a pointer to a StringInfo buffer
|
||||
holding the received byte string; the optional second argument is the
|
||||
element type in case this is an array type.) Similarly, the optional
|
||||
<replaceable class="parameter">send_function</replaceable> converts
|
||||
from the internal representation to the external binary representation.
|
||||
If this function is not supplied, the type cannot participate in binary
|
||||
output. The send function should be declared as taking one argument of the
|
||||
new data type and returning type <type>bytea</type>.
|
||||
output. The send function may be
|
||||
declared as taking one argument of the new data type, or as taking
|
||||
two arguments of which the second is type <type>oid</type>.
|
||||
The second argument is again the array element type for array types.
|
||||
The send function must return type <type>bytea</type>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.35 2003/05/08 22:19:56 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.36 2003/05/09 23:01:45 tgl Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@ -911,7 +911,8 @@ findTypeReceiveFunction(List *procname, Oid typeOid)
|
||||
Oid procOid;
|
||||
|
||||
/*
|
||||
* Receive functions take a single argument of type INTERNAL.
|
||||
* Receive functions can take a single argument of type INTERNAL, or
|
||||
* two arguments (internal, oid).
|
||||
*/
|
||||
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
|
||||
@ -921,6 +922,12 @@ findTypeReceiveFunction(List *procname, Oid typeOid)
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
argList[1] = OIDOID;
|
||||
|
||||
procOid = LookupFuncName(procname, 2, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
func_error("TypeCreate", procname, 1, argList, NULL);
|
||||
|
||||
return InvalidOid; /* keep compiler quiet */
|
||||
@ -933,7 +940,8 @@ findTypeSendFunction(List *procname, Oid typeOid)
|
||||
Oid procOid;
|
||||
|
||||
/*
|
||||
* Send functions take a single argument of the type.
|
||||
* Send functions can take a single argument of the type, or two
|
||||
* arguments (data value, element OID).
|
||||
*/
|
||||
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
|
||||
@ -943,6 +951,12 @@ findTypeSendFunction(List *procname, Oid typeOid)
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
argList[1] = OIDOID;
|
||||
|
||||
procOid = LookupFuncName(procname, 2, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
func_error("TypeCreate", procname, 1, argList, NULL);
|
||||
|
||||
return InvalidOid; /* keep compiler quiet */
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.88 2003/05/08 22:19:56 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.89 2003/05/09 23:01:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -19,6 +19,7 @@
|
||||
#include "access/tupmacs.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
@ -69,6 +70,15 @@
|
||||
|
||||
#define RETURN_NULL(type) do { *isNull = true; return (type) 0; } while (0)
|
||||
|
||||
/* I/O function selector for system_cache_lookup */
|
||||
typedef enum IOFuncSelector
|
||||
{
|
||||
IOFunc_input,
|
||||
IOFunc_output,
|
||||
IOFunc_receive,
|
||||
IOFunc_send
|
||||
} IOFuncSelector;
|
||||
|
||||
|
||||
static int ArrayCount(char *str, int *dim, char typdelim);
|
||||
static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
|
||||
@ -76,12 +86,17 @@ static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
|
||||
char typdelim,
|
||||
int typlen, bool typbyval, char typalign,
|
||||
int *nbytes);
|
||||
static Datum *ReadArrayBinary(StringInfo buf, int nitems,
|
||||
FmgrInfo *receiveproc, Oid typelem,
|
||||
int typlen, bool typbyval, char typalign,
|
||||
int *nbytes);
|
||||
static void CopyArrayEls(char *p, Datum *values, int nitems,
|
||||
int typlen, bool typbyval, char typalign,
|
||||
bool freedata);
|
||||
static void system_cache_lookup(Oid element_type, bool input, int *typlen,
|
||||
bool *typbyval, char *typdelim, Oid *typelem,
|
||||
Oid *proc, char *typalign);
|
||||
static void system_cache_lookup(Oid element_type, IOFuncSelector which_func,
|
||||
int *typlen, bool *typbyval,
|
||||
char *typdelim, Oid *typelem,
|
||||
Oid *proc, char *typalign);
|
||||
static Datum ArrayCast(char *value, bool byval, int len);
|
||||
static int ArrayCastAndSet(Datum src,
|
||||
int typlen, bool typbyval, char typalign,
|
||||
@ -141,7 +156,8 @@ array_in(PG_FUNCTION_ARGS)
|
||||
char typalign;
|
||||
|
||||
/* Get info about element type, including its input conversion proc */
|
||||
system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
|
||||
system_cache_lookup(element_type, IOFunc_input,
|
||||
&typlen, &typbyval, &typdelim,
|
||||
&typelem, &typinput, &typalign);
|
||||
fmgr_info(typinput, &inputproc);
|
||||
|
||||
@ -622,8 +638,9 @@ array_out(PG_FUNCTION_ARGS)
|
||||
*dim;
|
||||
|
||||
element_type = ARR_ELEMTYPE(v);
|
||||
system_cache_lookup(element_type, false, &typlen, &typbyval,
|
||||
&typdelim, &typelem, &typoutput, &typalign);
|
||||
system_cache_lookup(element_type, IOFunc_output,
|
||||
&typlen, &typbyval, &typdelim,
|
||||
&typelem, &typoutput, &typalign);
|
||||
fmgr_info(typoutput, &outputproc);
|
||||
|
||||
ndim = ARR_NDIM(v);
|
||||
@ -763,10 +780,178 @@ array_out(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
array_recv(PG_FUNCTION_ARGS)
|
||||
{
|
||||
elog(ERROR, "array_recv: not implemented yet");
|
||||
return 0;
|
||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
||||
Oid spec_element_type = PG_GETARG_OID(1); /* type of an array
|
||||
* element */
|
||||
Oid element_type;
|
||||
int typlen;
|
||||
bool typbyval;
|
||||
char typdelim;
|
||||
Oid typreceive;
|
||||
Oid typelem;
|
||||
FmgrInfo receiveproc;
|
||||
int i,
|
||||
nitems;
|
||||
int32 nbytes;
|
||||
Datum *dataPtr;
|
||||
ArrayType *retval;
|
||||
int ndim,
|
||||
flags,
|
||||
dim[MAXDIM],
|
||||
lBound[MAXDIM];
|
||||
char typalign;
|
||||
|
||||
/* Get the array header information */
|
||||
ndim = pq_getmsgint(buf, 4);
|
||||
if (ndim < 0 || ndim > MAXDIM)
|
||||
elog(ERROR, "array_recv: invalid number of dimensions");
|
||||
flags = pq_getmsgint(buf, 4);
|
||||
if (flags != 0)
|
||||
elog(ERROR, "array_recv: invalid array flags");
|
||||
element_type = pq_getmsgint(buf, sizeof(Oid));
|
||||
if (element_type != spec_element_type)
|
||||
{
|
||||
/* XXX Can we allow taking the input element type in any cases? */
|
||||
elog(ERROR, "array_recv: wrong element type");
|
||||
}
|
||||
|
||||
for (i = 0; i < ndim; i++)
|
||||
{
|
||||
dim[i] = pq_getmsgint(buf, 4);
|
||||
lBound[i] = pq_getmsgint(buf, 4);
|
||||
}
|
||||
nitems = ArrayGetNItems(ndim, dim);
|
||||
|
||||
if (nitems == 0)
|
||||
{
|
||||
/* Return empty array */
|
||||
retval = (ArrayType *) palloc0(sizeof(ArrayType));
|
||||
retval->size = sizeof(ArrayType);
|
||||
retval->elemtype = element_type;
|
||||
PG_RETURN_ARRAYTYPE_P(retval);
|
||||
}
|
||||
|
||||
/* Get info about element type, including its receive conversion proc */
|
||||
system_cache_lookup(element_type, IOFunc_receive,
|
||||
&typlen, &typbyval, &typdelim,
|
||||
&typelem, &typreceive, &typalign);
|
||||
if (!OidIsValid(typreceive))
|
||||
elog(ERROR, "No binary input function available for type %s",
|
||||
format_type_be(element_type));
|
||||
fmgr_info(typreceive, &receiveproc);
|
||||
|
||||
dataPtr = ReadArrayBinary(buf, nitems, &receiveproc, typelem,
|
||||
typlen, typbyval, typalign,
|
||||
&nbytes);
|
||||
nbytes += ARR_OVERHEAD(ndim);
|
||||
|
||||
retval = (ArrayType *) palloc0(nbytes);
|
||||
retval->size = nbytes;
|
||||
retval->ndim = ndim;
|
||||
retval->elemtype = element_type;
|
||||
memcpy((char *) ARR_DIMS(retval), (char *) dim,
|
||||
ndim * sizeof(int));
|
||||
memcpy((char *) ARR_LBOUND(retval), (char *) lBound,
|
||||
ndim * sizeof(int));
|
||||
|
||||
CopyArrayEls(ARR_DATA_PTR(retval), dataPtr, nitems,
|
||||
typlen, typbyval, typalign, true);
|
||||
pfree(dataPtr);
|
||||
|
||||
PG_RETURN_ARRAYTYPE_P(retval);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
* ReadArrayBinary:
|
||||
* collect the data elements of an array being read in binary style.
|
||||
* result :
|
||||
* returns a palloc'd array of Datum representations of the array elements.
|
||||
* If element type is pass-by-ref, the Datums point to palloc'd values.
|
||||
* *nbytes is set to the amount of data space needed for the array,
|
||||
* including alignment padding but not including array header overhead.
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
static Datum *
|
||||
ReadArrayBinary(StringInfo buf,
|
||||
int nitems,
|
||||
FmgrInfo *receiveproc,
|
||||
Oid typelem,
|
||||
int typlen,
|
||||
bool typbyval,
|
||||
char typalign,
|
||||
int *nbytes)
|
||||
{
|
||||
Datum *values;
|
||||
int i;
|
||||
|
||||
values = (Datum *) palloc(nitems * sizeof(Datum));
|
||||
|
||||
for (i = 0; i < nitems; i++)
|
||||
{
|
||||
int itemlen;
|
||||
StringInfoData elem_buf;
|
||||
char csave;
|
||||
|
||||
/* Get and check the item length */
|
||||
itemlen = pq_getmsgint(buf, 4);
|
||||
if (itemlen < 0 || itemlen > (buf->len - buf->cursor))
|
||||
elog(ERROR, "insufficient data left in message");
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
elem_buf.data = &buf->data[buf->cursor];
|
||||
elem_buf.maxlen = itemlen + 1;
|
||||
elem_buf.len = itemlen;
|
||||
elem_buf.cursor = 0;
|
||||
|
||||
buf->cursor += itemlen;
|
||||
|
||||
csave = buf->data[buf->cursor];
|
||||
buf->data[buf->cursor] = '\0';
|
||||
|
||||
/* Now call the element's receiveproc */
|
||||
values[i] = FunctionCall2(receiveproc,
|
||||
PointerGetDatum(&elem_buf),
|
||||
ObjectIdGetDatum(typelem));
|
||||
|
||||
/* Trouble if it didn't eat the whole buffer */
|
||||
if (elem_buf.cursor != itemlen)
|
||||
elog(ERROR, "Improper binary format in array element %d",
|
||||
i + 1);
|
||||
|
||||
buf->data[buf->cursor] = csave;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute total data space needed
|
||||
*/
|
||||
if (typlen > 0)
|
||||
{
|
||||
*nbytes = nitems * att_align(typlen, typalign);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(!typbyval);
|
||||
*nbytes = 0;
|
||||
for (i = 0; i < nitems; i++)
|
||||
{
|
||||
/* let's just make sure data is not toasted */
|
||||
if (typlen == -1)
|
||||
values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i]));
|
||||
*nbytes = att_addlength(*nbytes, typlen, values[i]);
|
||||
*nbytes = att_align(*nbytes, typalign);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* array_send :
|
||||
* takes the internal representation of an array and returns a bytea
|
||||
@ -776,8 +961,70 @@ array_recv(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
array_send(PG_FUNCTION_ARGS)
|
||||
{
|
||||
elog(ERROR, "array_send: not implemented yet");
|
||||
return 0;
|
||||
ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
|
||||
Oid element_type;
|
||||
int typlen;
|
||||
bool typbyval;
|
||||
char typdelim;
|
||||
Oid typsend,
|
||||
typelem;
|
||||
FmgrInfo sendproc;
|
||||
char typalign;
|
||||
char *p;
|
||||
int nitems,
|
||||
i;
|
||||
int ndim,
|
||||
*dim;
|
||||
StringInfoData buf;
|
||||
|
||||
/* Get information about the element type and the array dimensions */
|
||||
element_type = ARR_ELEMTYPE(v);
|
||||
system_cache_lookup(element_type, IOFunc_send, &typlen, &typbyval,
|
||||
&typdelim, &typelem, &typsend, &typalign);
|
||||
if (!OidIsValid(typsend))
|
||||
elog(ERROR, "No binary output function available for type %s",
|
||||
format_type_be(element_type));
|
||||
fmgr_info(typsend, &sendproc);
|
||||
|
||||
ndim = ARR_NDIM(v);
|
||||
dim = ARR_DIMS(v);
|
||||
nitems = ArrayGetNItems(ndim, dim);
|
||||
|
||||
pq_begintypsend(&buf);
|
||||
|
||||
/* Send the array header information */
|
||||
pq_sendint(&buf, ndim, 4);
|
||||
pq_sendint(&buf, v->flags, 4);
|
||||
pq_sendint(&buf, element_type, sizeof(Oid));
|
||||
for (i = 0; i < ndim; i++)
|
||||
{
|
||||
pq_sendint(&buf, ARR_DIMS(v)[i], 4);
|
||||
pq_sendint(&buf, ARR_LBOUND(v)[i], 4);
|
||||
}
|
||||
|
||||
/* Send the array elements using the element's own sendproc */
|
||||
p = ARR_DATA_PTR(v);
|
||||
for (i = 0; i < nitems; i++)
|
||||
{
|
||||
Datum itemvalue;
|
||||
bytea *outputbytes;
|
||||
|
||||
itemvalue = fetch_att(p, typbyval, typlen);
|
||||
|
||||
outputbytes = DatumGetByteaP(FunctionCall2(&sendproc,
|
||||
itemvalue,
|
||||
ObjectIdGetDatum(typelem)));
|
||||
/* 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);
|
||||
|
||||
p = att_addlength(p, typlen, PointerGetDatum(p));
|
||||
p = (char *) att_align(p, typalign);
|
||||
}
|
||||
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
@ -1583,9 +1830,9 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType)
|
||||
PG_RETURN_ARRAYTYPE_P(v);
|
||||
|
||||
/* Lookup source and result types. Unneeded variables are reused. */
|
||||
system_cache_lookup(inpType, false, &inp_typlen, &inp_typbyval,
|
||||
system_cache_lookup(inpType, IOFunc_input, &inp_typlen, &inp_typbyval,
|
||||
&typdelim, &typelem, &proc, &inp_typalign);
|
||||
system_cache_lookup(retType, false, &typlen, &typbyval,
|
||||
system_cache_lookup(retType, IOFunc_input, &typlen, &typbyval,
|
||||
&typdelim, &typelem, &proc, &typalign);
|
||||
|
||||
/* Allocate temporary array for new values */
|
||||
@ -1832,7 +2079,7 @@ array_eq(PG_FUNCTION_ARGS)
|
||||
|
||||
static void
|
||||
system_cache_lookup(Oid element_type,
|
||||
bool input,
|
||||
IOFuncSelector which_func,
|
||||
int *typlen,
|
||||
bool *typbyval,
|
||||
char *typdelim,
|
||||
@ -1855,10 +2102,21 @@ system_cache_lookup(Oid element_type,
|
||||
*typdelim = typeStruct->typdelim;
|
||||
*typelem = typeStruct->typelem;
|
||||
*typalign = typeStruct->typalign;
|
||||
if (input)
|
||||
*proc = typeStruct->typinput;
|
||||
else
|
||||
*proc = typeStruct->typoutput;
|
||||
switch (which_func)
|
||||
{
|
||||
case IOFunc_input:
|
||||
*proc = typeStruct->typinput;
|
||||
break;
|
||||
case IOFunc_output:
|
||||
*proc = typeStruct->typoutput;
|
||||
break;
|
||||
case IOFunc_receive:
|
||||
*proc = typeStruct->typreceive;
|
||||
break;
|
||||
case IOFunc_send:
|
||||
*proc = typeStruct->typsend;
|
||||
break;
|
||||
}
|
||||
ReleaseSysCache(typeTuple);
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catversion.h,v 1.189 2003/05/09 21:19:49 tgl Exp $
|
||||
* $Id: catversion.h,v 1.190 2003/05/09 23:01:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200305092
|
||||
#define CATALOG_VERSION_NO 200305093
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_proc.h,v 1.296 2003/05/09 21:19:49 tgl Exp $
|
||||
* $Id: pg_proc.h,v 1.297 2003/05/09 23:01:45 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.sh reads this file and generates .bki
|
||||
@ -3153,9 +3153,9 @@ DATA(insert OID = 2311 ( md5 PGNSP PGUID 12 f f t f i 1 25 "25" md5_text -
|
||||
DESCR("calculates md5 hash");
|
||||
|
||||
|
||||
DATA(insert OID = 2400 ( array_recv PGNSP PGUID 12 f f t f s 1 2277 "2281" array_recv - _null_ ));
|
||||
DATA(insert OID = 2400 ( array_recv PGNSP PGUID 12 f f t f s 2 2277 "2281 26" array_recv - _null_ ));
|
||||
DESCR("I/O");
|
||||
DATA(insert OID = 2401 ( array_send PGNSP PGUID 12 f f t f s 1 17 "2277" array_send - _null_ ));
|
||||
DATA(insert OID = 2401 ( array_send PGNSP PGUID 12 f f t f s 2 17 "2277 26" array_send - _null_ ));
|
||||
DESCR("I/O");
|
||||
DATA(insert OID = 2402 ( record_recv PGNSP PGUID 12 f f t f i 1 2249 "2281" record_recv - _null_ ));
|
||||
DESCR("I/O");
|
||||
|
@ -143,7 +143,9 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
(p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype);
|
||||
((p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype) OR
|
||||
(p2.pronargs = 2 AND p2.proargtypes[0] = 'internal'::regtype AND
|
||||
p2.proargtypes[1] = 'oid'::regtype));
|
||||
oid | typname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
@ -114,7 +114,9 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
||||
FROM pg_type AS p1, pg_proc AS p2
|
||||
WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
||||
(p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype);
|
||||
((p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype) OR
|
||||
(p2.pronargs = 2 AND p2.proargtypes[0] = 'internal'::regtype AND
|
||||
p2.proargtypes[1] = 'oid'::regtype));
|
||||
|
||||
-- As of 7.4, this check finds refcursor, which is borrowing
|
||||
-- other types' I/O routines
|
||||
|
Loading…
Reference in New Issue
Block a user