Golangian procedural language for Postgresql

I am trying to compile and run go code as a Postgresql stored procedure. My motivation is that postgresql can have sets written in C, and golang can be compiled as c-shared

So, I have files, pl.go:

package main

/*
#cgo CFLAGS: -Wall -Wpointer-arith -Wno-declaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong -fpic -I. -I./ -I/usr/include/postgresql/server -I/usr/include/postgresql/internal -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -I/usr/include/libxml2
#cgo LDFLAGS: -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong -fpic -L/usr/lib -Wl,-O1,--sort-common,--as-needed,-z,relro  -Wl,--as-needed -Wl,-rpath,'/usr/lib',--enable-new-dtags -shared

#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

//the return value must be allocated trough palloc
void* ret(void *val, uint64 *size) {
    void *retDatum = palloc(*size);
    memcpy(retDatum, val, *size);
    return retDatum;
}

PG_FUNCTION_INFO_V1(plgo_func);
*/
import "C"
import "unsafe"

func main() {}

//PGVal returns the Postgresql C type from Golang type (currently implements just stringtotext)
func PGVal(val interface{}) (ret interface{}) {
    var size uintptr
    switch v := val.(type) {
    case string:
        ret = C.cstring_to_text(C.CString(v))
        size = unsafe.Sizeof(ret)
    default:
        ret = val
        size = unsafe.Sizeof(ret)
    }
    return C.ret(ret, (*C.uint64)(unsafe.Pointer(size)))
}

CFLAGSand LDFLAGSI got frompg_config

and the file where I create the function to call is plgo.go:

package main

/*
#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"
*/
import "C"

//export plgo_func
func plgo_func(fcinfo *C.FunctionCallInfoData) interface{} {
    return PGVal("meh")
}

a shared library is created using: go build -buildmode=c-shared -o plgo.so plgo.go pl.go && sudo cp plgo.so /usr/lib/postgresql

A function in postgresql is created using:

CREATE OR REPLACE FUNCTION public.plgo_func(integer)
  RETURNS text AS
'$libdir/plgo', 'plgo_func'
  LANGUAGE c IMMUTABLE STRICT
  COST 1;

but when I ran: psql -U root -d meh -c "select plgo_func(0)"

server crash:

server closed the connection unexpectedly
    This probably means the server terminated abnormally
    before or while processing the request.
connection to server was lost

EDIT: I successfully created the golang library to create stored procedures and triggers in golang plgo :)

+4
source share
1 answer

, 0, C, , 1.

C PG_MODULE_MAGIC.

, , , .

, , , .

https://github.com/dbudworth/gopgfuncs

, ...

1

.go , CGO

package main

//#include "postgres.h"
//#include "fmgr.h"
//#include <string.h>
import "C"
import (
    "log"
    "sync/atomic"
)

// Functions are scoped to the db session
var counter int64

//Inc atomically increments a session local counter by a given delta
//export Inc
func Inc(delta C.int64) C.int64 {
    log.Printf("Inc(%v) called", delta)
    return C.int64(atomic.AddInt64(&counter, int64(delta)))
}

//AddOne adds one to the given arg and retuns it
//export AddOne
func AddOne(i C.int) C.int {
    log.Printf("AddOne(%v) called", i)
    return i + 1
}

func main() {
}

2

.c , PG_MODULE_MAGIC postgres.h, . Go C , .

#include "postgres.h"
#include "fmgr.h"

PG_MODULE_MAGIC;

3

, - -buildmode = c-shared

go build -buildmode=c-shared -o libMyMod.so

4

SQL . , , , "install.sql" script .

PGMOD=`pwd`/libMyMod.so
psql $(DBNAME) --set=MOD=\'$(PGMOD)\' -f install.sql

script .

, /, , , , . pg c-

create or replace function add_one(integer)
  returns integer as :MOD,'AddOne'
  LANGUAGE C STRICT;
+3

Source: https://habr.com/ru/post/1649164/


All Articles