Returning Vector of Pairs with a PostgreSQL C Extension Function

Started by TalGlozover 7 years ago9 messagesgeneral
Jump to latest
#1TalGloz
glozmantal@gmail.com

Hello,

I want to return an vector of pairs using a C extension. This is a simple
code I have:

extern "C" {
Datum pair(PG_FUNCTION_ARGS){

// For text aka. character varying parameter
text *t1 = PG_GETARG_TEXT_PP(0);
text *t2 = PG_GETARG_TEXT_PP(1);
std::string localT1 = text_to_cstring(t1);
std::string localT2 = text_to_cstring(t2);

/* Construct the return value of the C extention to PostgreSQl */
// Returns Text ponter of casted cstrings to text
//PG_RETURN_TEXT_P(cstring_to_text_with_len(localT1.c_str(),
localT1.size()));
//PG_RETURN_TEXT_P(cstring_to_text_with_len(encodedLocalT1.c_str(),
encodedLocalT1.size()));
//PG_RETURN_TEXT_P(cstring_to_text_with_len(outputParam.c_str(),
outputParam.size()));

// Return vector of pairs
std::vector<std::pair&lt;std::string, std::string>> ret;
ret.emplace_back(encodedLocalT1, encodedLocalT2);
PG_RETURN_ARRAYTYPE_P(ret);

};
PG_FUNCTION_INFO_V1(pair);
}

But it doesn't work like it. Even using this doesn't work:
ArrayType *array;
std::vector<std::pair&lt;std::string, std::string>> ret;
ret.emplace_back(encodedLocalT1, encodedLocalT2);
array = ret;
PG_RETURN_POINTER(array);

Is it possible to return a vector of pairs? If not then how can I return 2
strings in an Array?

Best regards,
Tal

--
Sent from: http://www.postgresql-archive.org/PostgreSQL-general-f1843780.html

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: TalGloz (#1)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

TalGloz <glozmantal@gmail.com> writes:

I want to return an vector of pairs using a C extension.

You're going to have to work a lot harder than this:

// Return vector of pairs
std::vector<std::pair&lt;std::string, std::string>> ret;
ret.emplace_back(encodedLocalT1, encodedLocalT2);
PG_RETURN_ARRAYTYPE_P(ret);

I do not know what the internal representation of std::vector is in
your C++ library, but it seems highly unlikely that it exactly matches
what Postgres arrays look like. Nor has Postgres ever heard of a
std::pair. You'd need to either create a composite type of two text
columns and then build an array of those, or else decide to return a
two-dimensional array to represent this case. In any case, you must
use Postgres functions to construct the return value; the C++ library
is completely useless for that.

regards, tom lane

#3TalGloz
glozmantal@gmail.com
In reply to: Tom Lane (#2)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

OK so I think I'm on the right way with this code and now my goal is to
return a text array (text[ ]) with 2 fields

extern "C" {
Datum text_array(PG_FUNCTION_ARGS){

// For text aka. character varying parameter
text *t1 = PG_GETARG_TEXT_PP(0);
text *t2 = PG_GETARG_TEXT_PP(1);
std::string localT1 = text_to_cstring(t1);
std::string localT2 = text_to_cstring(t2);

ArrayType *array;
Datum* elements[2];
int16 typlen;
bool typbyval;
char typalign;

elements[0] = CStringGetDatum(localT1.c_str());
elements[1] = CStringGetDatum(localT2.c_str());

get_typlenbyvalalign(TEXTOID, &typlen, &typbyval, &typalign);
array = construct_array(elements, 2, TEXTOID, typlen, typbyval,
typalign);

PG_RETURN_ARRAYTYPE_P(array);

};
PG_FUNCTION_INFO_V1(text_array);
}

But I'm getting this:

g++ -std=c++17 -fPIC -Wall -Werror -g -O0 -pthread
-I/usr/pgsql-10/include/server -I/usr/local/include
-I/usr/local/include/cppcodec -o seal_diff_cpp.o -c seal_diff_cpp.cpp
In file included from seal_diff_cpp.cpp:2:
seal_diff_cpp.cpp: In function ‘Datum seal_diff_cpp(FunctionCallInfo)’:
/usr/pgsql-10/include/server/postgres.h:562:29: error: invalid conversion
from ‘Datum’ {aka ‘long unsigned int’} to ‘Datum*’ {aka ‘long unsigned
int*’} [-fpermissive]
#define PointerGetDatum(X) ((Datum) (X))
~^~~~~~~~~~~~
/usr/pgsql-10/include/server/postgres.h:584:28: note: in expansion of macro
‘PointerGetDatum’
#define CStringGetDatum(X) PointerGetDatum(X)
^~~~~~~~~~~~~~~
seal_diff_cpp.cpp:168:23: note: in expansion of macro ‘CStringGetDatum’
elements[0] = CStringGetDatum(localT1.c_str());
^~~~~~~~~~~~~~~
/usr/pgsql-10/include/server/postgres.h:562:29: error: invalid conversion
from ‘Datum’ {aka ‘long unsigned int’} to ‘Datum*’ {aka ‘long unsigned
int*’} [-fpermissive]
#define PointerGetDatum(X) ((Datum) (X))
~^~~~~~~~~~~~
/usr/pgsql-10/include/server/postgres.h:584:28: note: in expansion of macro
‘PointerGetDatum’
#define CStringGetDatum(X) PointerGetDatum(X)
^~~~~~~~~~~~~~~
seal_diff_cpp.cpp:169:16: note: in expansion of macro ‘CStringGetDatum’
elements[1] = CStringGetDatum(localT2.c_str());
^~~~~~~~~~~~~~~
seal_diff_cpp.cpp:171:26: error: cannot convert ‘Datum**’ {aka ‘long
unsigned int**’} to ‘Datum*’ {aka ‘long unsigned int*’}
array = construct_array(elements, 2, TEXTOID, typlen, typbyval, typalign);
^~~~~~~~
In file included from /usr/pgsql-10/include/server/utils/acl.h:38,
from
/usr/pgsql-10/include/server/catalog/objectaddress.h:18,
from
/usr/pgsql-10/include/server/catalog/pg_publication.h:21,
from /usr/pgsql-10/include/server/utils/rel.h:21,
from seal_diff_cpp.cpp:6:
/usr/pgsql-10/include/server/utils/array.h:370:42: note: initializing
argument 1 of ‘ArrayType* construct_array(Datum*, int, Oid, int, bool,
char)’
extern ArrayType *construct_array(Datum *elems, int nelems,
~~~~~~~^~~~~
make: *** [Makefile:19: seal_diff_cpp.o] Error 1

Best regards,
Tal

--
Sent from: http://www.postgresql-archive.org/PostgreSQL-general-f1843780.html

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: TalGloz (#3)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

TalGloz <glozmantal@gmail.com> writes:

Datum* elements[2];

Datum, not Datum*.

regards, tom lane

#5TalGloz
glozmantal@gmail.com
In reply to: Tom Lane (#4)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

Yes, that was the problem and now everything works.

Thanks,
Tal

--
Sent from: http://www.postgresql-archive.org/PostgreSQL-general-f1843780.html

#6TalGloz
glozmantal@gmail.com
In reply to: Tom Lane (#4)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

Hello,

I'm having a small problem. The code works but the array cells don't hold
the whole length of *localT1* and *localT2* texts, I think it has something
to do with *int16 typlen* in my set parameters:

ArrayType *array;
Datum elements[2];
int16 typlen;
bool typbyval;
char typalign;

elements[0] = CStringGetDatum(localT1.c_str());
elements[1] = CStringGetDatum(localT2.c_str());

get_typlenbyvalalign(TEXTOID, &typlen, &typbyval, &typalign);
array = construct_array(elements, 2, TEXTOID, typlen, typbyval, typalign);

I can't change the int16 to int32 or int64 because the
get_typlenbyvalalign() function takes an int16. Is there a way to change my
settings so that each input (in this example the *localT1* and *localT2*)
fits fully in each sell?

Best regards,
Tal

--
Sent from: http://www.postgresql-archive.org/PostgreSQL-general-f1843780.html

#7TalGloz
glozmantal@gmail.com
In reply to: TalGloz (#6)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

It looks like changing the

elements[0] = CStringGetDatum(localT1.c_str());
elements[1] = CStringGetDatum(localT2.c_str());

to:

elements[0] = PointerGetDatum(cstring_to_text(localT1.c_str()));
elements[1] = PointerGetDatum(cstring_to_text(localT2.c_str()));

Solved the problem. If anyone thinks that there is a better way please tell
me.

Best regards,
Tal

--
Sent from: http://www.postgresql-archive.org/PostgreSQL-general-f1843780.html

#8Pavel Stehule
pavel.stehule@gmail.com
In reply to: TalGloz (#7)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

2018-08-27 14:40 GMT+02:00 TalGloz <glozmantal@gmail.com>:

It looks like changing the

elements[0] = CStringGetDatum(localT1.c_str());
elements[1] = CStringGetDatum(localT2.c_str());

to:

elements[0] = PointerGetDatum(cstring_to_text(localT1.c_str()));
elements[1] = PointerGetDatum(cstring_to_text(localT2.c_str()));

Solved the problem. If anyone thinks that there is a better way please tell
me.

There is not better or worst way - you have to use just correct way, that
is one

There are already prepared macros

#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s))
#define TextDatumGetCString(d) text_to_cstring((text *) DatumGetPointer(d))

you can use it.

Regards

Pavel

Show quoted text

Best regards,
Tal

--
Sent from: http://www.postgresql-archive.org/PostgreSQL-general-
f1843780.html

#9TalGloz
glozmantal@gmail.com
In reply to: Pavel Stehule (#8)
Re: Returning Vector of Pairs with a PostgreSQL C Extension Function

Pavel Stehule wrote

There are already prepared macros

#define CStringGetTextDatum(s) PointerGetDatum(cstring_to_text(s))
#define TextDatumGetCString(d) text_to_cstring((text *)
DatumGetPointer(d))

Thanks for pointing out the macros, for some reason I've missed them.

Best regards,
Tal

--
Sent from: http://www.postgresql-archive.org/PostgreSQL-general-f1843780.html