Thread: Example of a pg_gethostname() function. Feedback?
I had a need recently to get the server hostname of some databases that we were unit-testing and couldn't find a built-in function for it. One of my coworkers put together a C function that seems to work well. Does anyone have any suggestions or improvements to the code below? Some testing was done with both 9.0 and and 9.1, linux, x86_64 To use: select pg_gethostname(); /* A PostgreSQL function for getting the hostname. File: `pg_config --libdir`/pg_gethostname.c To compile: //gcc -fpic -c pg_gethostname.c //gcc -shared -o pg_gethostname.so pg_gethostname.o Note: the compile options above did work, amended steps: // make sure pg_config is in your path gcc -I`pg_config --includedir-server` -fpic -c pg_gethostname.c -L`pg_config --libdir` gcc -shared -o pg_gethostname.so pg_gethostname.o To create the function in PostgreSQL. //DROP FUNCTION IF EXISTS pg_gethostname(); CREATE OR REPLACE FUNCTION pg_gethostname() RETURNS text AS 'pg_gethostname' LANGUAGE C IMMUTABLE STRICT; */ #include "postgres.h" #include <unistd.h> #include <string.h> #include "fmgr.h" #include "utils/palloc.h" #include "utils/elog.h" #include "storage/bufpage.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif #define MAX_HOSTNAME_LENGTH 255 PG_FUNCTION_INFO_V1( pg_gethostname ); Datum pg_gethostname( PG_FUNCTION_ARGS ); Datum pg_gethostname( PG_FUNCTION_ARGS ) { text *t; char server_hostname[MAX_HOSTNAME_LENGTH]; size_t length; if ( gethostname( server_hostname, MAX_HOSTNAME_LENGTH ) != 0 ) { // things are not okay strncpy( server_hostname, "UNKNOWN", MAX_HOSTNAME_LENGTH ); } length = strnlen( server_hostname, MAX_HOSTNAME_LENGTH ); t = (text *) palloc(VARHDRSZ + length ); SET_VARSIZE( t, VARHDRSZ + length ); memcpy( VARDATA(t), server_hostname, length ); PG_RETURN_TEXT_P( t ); }
On 24/12/2011 2:47 AM, bricklen wrote: > I had a need recently to get the server hostname of some databases > that we were unit-testing and couldn't find a built-in function for > it. One of my coworkers put together a C function that seems to work > well. > Does anyone have any suggestions or improvements to the code below? Only that it might be less hassle to wrap gethostname from pl/perl or pl/python rather than adding a new C function, particularly if this is only for DB testing and is not performance critical. -- Craig Ringer
On Fri, Dec 23, 2011 at 8:22 PM, Craig Ringer <ringerc@ringerc.id.au> wrote: > Only that it might be less hassle to wrap gethostname from pl/perl or > pl/python rather than adding a new C function, particularly if this is only > for DB testing and is not performance critical. > > -- > Craig Ringer Hi Craig, That was my first thought. However, in two of our servers, Perl is mis-configured in some way that it causes the db to abort and crash when a simple plperlu function is run. I reported a test case a few months ago and that was Tom's conclusion and I didn't have the time or inclination to pursue it. We rarely use any pl language other than plpgsql, so I deemed it safer in this instance to avoid using plperlu altogether. Cheers, Bricklen Note, my coworker revised the C function slightly: - Used HOST_NAME_MAX from limits.h, which is portable. - Return an empty string on failure instead of "UNKNOWN" because that makes more sense and allows for the host name "UNKNOWN". - Fixed the comments. /* A PostgreSQL function for getting the hostname. To compile... (make sure pg_config is in your PATH) gcc -I$(pg_config --includedir-server) -fpic -c pg_gethostname.c -L$(pg_config --libdir) gcc --shared -o pg_gethostname.so pg_gethostname.o To create the funciton in PostgreSQL... CREATE OR REPLACE FUNCTION pg_gethostname() RETURNS text AS 'pg_gethostname' LANGUAGE C IMMUTABLE STRICT; */ #include "postgres.h" #include <limits.h> #include <unistd.h> #include <string.h> #include "fmgr.h" #include "utils/palloc.h" #include "utils/elog.h" #include "storage/bufpage.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1( pg_gethostname ); Datum pg_gethostname( PG_FUNCTION_ARGS ); Datum pg_gethostname( PG_FUNCTION_ARGS ) { text *t; char server_hostname[HOST_NAME_MAX]; size_t length; if ( gethostname( server_hostname, HOST_NAME_MAX ) != 0 ) { // returning an empty string for the hostname if it fails makes // sense because if it succeeded, we would have a name server_hostname[0] = '\0'; } length = strnlen( server_hostname, HOST_NAME_MAX ); t = (text *) palloc(VARHDRSZ + length ); SET_VARSIZE( t, VARHDRSZ + length ); memcpy( VARDATA(t), server_hostname, length ); PG_RETURN_TEXT_P( t ); }