问题
I' trying to add 3 user_defined function to the PostgreSQL-8.4.15. Here are 3 functions:
(1) start_create_profile();
(2) make_profile();
(3) check_anomaly();
All of them are written in file "test.c" located in src/backend/tcop. I want to call (1) and (3) from the middle of exec_simple_query()
. exec_simple_query()
is PostgreSQL function that is written in "postgres.c" located in src/backend/tcop. I want to call (2) directly through my GUI.
here is the my code written in "test.c" :
#include "postgres.h"
#ifndef PROGPROFILE_H_
#define PROGPROFILE_H_
/* interfaces */
extern void start_create_profile(List *querytree_list);
extern void create_profile();
extern void check_anomaly(List *querytree_list);
#endif /* Test ProgProf */
void start_create_profile(List *querytree_list){
ListCell *l;
ListCell *tl;
FILE *f;
//if the file exist just open and write
//else create and write
f = fopen ("QueryParsed.txt", "a+");
Query *query_idr = (Query *)linitial(querytree_list);
// CMD_SELECT=0 CMD_INSERT=1 CMD_UPDATE=2
switch (query_idr->commandType)
{
case CMD_SELECT:
fputs("CMD_SELECT, ", f);
break;
case CMD_INSERT:
fputs("CMD_INSERT, ", f);
break;
case CMD_UPDATE:
fputs("CMD_UPDATE, ", f);
break;
default:
break;
}
//to have the ID of the table
foreach(l, query_idr->rtable){
Oid tab_idT = ((RangeTblEntry *) lfirst(l)) ->relid;
//char temp1[10];
char *tab_idTConverted = itoa(tab_idT);
/* This is not a table */
if (tab_idT == 0)
continue;
fputs(" tab_id: , ", f);
fputs(tab_idTConverted, f);
}
//to have the name of the targer list
foreach(tl, query_idr->targetList){
TargetEntry *tle = (TargetEntry *) lfirst(tl);
Oid tab_id = tle->resorigtbl;
int tab_idCast=(int)tab_id;
//char temp[10];
char *tab_idConverted = itoa(tab_idCast);
char *resname=tle->resname;
fputs("Name of column: ", f);
fputs(resname, f);
fputs(" ID: ", f);
fputs(tab_idConverted, f);
fputs("\n", f);
}
//close the file that we write
fputs("$", f);
fclose (f);
}
void create_profile(){
}
void check_anomaly(List *querytree_list){
}
Now I've created a very simple GUI including 3 buttons(by netbeans in java). Button1, button2, button3 corresponding by order to start_create_profile()
, make_profile, check_anomaly()
.
I want to use a global variable(Let's consider "button" that can be set to 3 different values like 0, 1, 2. I want that whenever I push the button1 or button3 the global variable become set to 1 or 2 in order to use "if" that I've written in exec_simple_query()
. here is "if"
//initially button=0;
//inside exec_simple_query
if(button==1) start_create_profile();
if(button==2) check_anomaly;
and whenever I push the button2, the function(2) has to be called directly. Any idea how do I have to set that variable to make me able choosing one of those 3 function using my GUI?? How do I have to call the function(2) directly through my GUI??
回答1:
There are several problems here.
You can't call just any C function from SQL
First, you can't just call arbitrary functions from SQL, you must use PostgreSQL's C extension APIs and macros; look at the existing implementations of SQL-callable functions in the sources for examples.
You usually don't have to modify the core code, extensions are often sufficient
Second, if you want to add functions to the core PostgreSQL, you must add them to src/include/catalog/pg_proc.h
so they're defined during initdb
.
It's much better, however, to use the proper extension loading facilities:
- http://www.postgresql.org/docs/current/static/xfunc-c.html
- http://www.postgresql.org/docs/current/static/extend-pgxs.html
This way you can LOAD
an extension module, CREATE FUNCTION
the C functions as per the docs, and call them from SQL.
In your specific case it looks like you do need to modify the core codebase, but this is quite unusual, so I'm preserving this advice for others.
A C function in the PostgreSQL backend cannot be called "directly" from a GUI
You have a Java Swing GUI and you envision somehow calling a C function in a different process, possibly even on a different host, from it.
This won't work for a bunch of reasons, including:
- Java can't directly call C functions without glue code like
JNI
orJNA
. - It is not possible to call a C function in a different process directly; you must instead use inter-process communication (shared memory, pipes, sockets, shared files, etc) to exchange information
- While you could embed a Java interpreter in the Pg backend and call the C function via JNI kind-of-directly, you really don't want to try to display a Swing GUI directly from inside a Pg backend.
What you need is a multi-stage process:
Collect the data you wish to capture in the PostgreSQL backend. If you intend to access it from the same connection that it's created in you can use an ordinary
palloc
'd buffer. Otherwise you will need to allocate a buffer out of shared memory or exchange data using the file system.Access that data from a C function that has been created with an SQL-callable interface as per PostgreSQL's C extension function documentation (above)
Use a PostgreSQL connection to transfer the data from your SQL-callable interface function to your Java application. Decode it in your application and display it as desired.
Alternately:
Require that your Java program, or an agent for it, run on the same system as the PostgreSQL server and have the agent write files in a location writable to Pg and readable by your program.
Read the files using your program or its agent and process them for display
You could even have Pg write to a socket your program is listening on, but I don't recommend this as a stall in your program would cause performance problems in PostgreSQL.
来源:https://stackoverflow.com/questions/15019257/calling-a-user-defined-function-located-in-postgres-c-in-postgresql-using-a-gu