Обсуждение: 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 );
}