Вызов пользовательской функции, расположенной в "postgres.c" в postgreSQL, с использованием графического интерфейса, определенного NetBeans
Я пытаюсь добавить 3 user_defined функции в PostgreSQL-8.4.15. Вот 3 функции:
(1) start_create_profile();
(2) make_profile();
(3) check_anomaly();
Все они написаны в файле "test.c", расположенном в src/backend/tcop. Я хочу позвонить (1) и (3) с середины exec_simple_query()
, exec_simple_query()
является функцией PostgreSQL, которая написана в "postgres.c", расположенном в src/backend/tcop. Я хочу вызвать (2) напрямую через мой графический интерфейс.
Вот мой код, написанный в "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){
}
Теперь я создал очень простой графический интерфейс, включающий 3 кнопки (от netbeans в java). Button1, button2, button3, соответствующие порядку start_create_profile()
, make_profile, check_anomaly()
,
Я хочу использовать глобальную переменную (Давайте рассмотрим "кнопку", которая может быть установлена на 3 различных значения, таких как 0, 1, 2. Я хочу, чтобы всякий раз, когда я нажимаю кнопку 1 или кнопку 3, глобальная переменная становилась равной 1 или 2, чтобы используйте "если", что я написал в exec_simple_query()
, здесь "если"
//initially button=0;
//inside exec_simple_query
if(button==1) start_create_profile();
if(button==2) check_anomaly;
и всякий раз, когда я нажимаю кнопку2, функция (2) должна вызываться напрямую. Любая идея, как я должен установить эту переменную, чтобы я мог выбрать одну из этих трех функций, используя мой графический интерфейс? Как мне вызвать функцию (2) напрямую через мой графический интерфейс?
1 ответ
Здесь есть несколько проблем.
Вы не можете вызвать любую функцию C из SQL
Во-первых, вы не можете просто вызывать произвольные функции из SQL, вы должны использовать API и макросы расширения C PostgreSQL; посмотрите на существующие реализации SQL-вызываемых функций в источниках для примеров.
Обычно вам не нужно изменять основной код, часто достаточно расширений
Во-вторых, если вы хотите добавить функции в ядро PostgreSQL, вы должны добавить их в src/include/catalog/pg_proc.h
поэтому они определены во время initdb
,
Однако гораздо лучше использовать соответствующие средства загрузки расширений:
- http://www.postgresql.org/docs/current/static/xfunc-c.html
- http://www.postgresql.org/docs/current/static/extend-pgxs.html
Таким образом, вы можете LOAD
модуль расширения, CREATE FUNCTION
C функционирует согласно документам и вызывает их из SQL.
В вашем конкретном случае похоже, что вам нужно изменить базовую кодовую базу, но это довольно необычно, поэтому я оставляю этот совет для других.
Функция A C в бэкэнде PostgreSQL не может быть вызвана "напрямую" из GUI
У вас есть Java Swing GUI, и вы предполагаете каким-то образом вызвать функцию C в другом процессе, возможно, даже на другом хосте.
Это не будет работать по нескольким причинам, в том числе:
- Java не может напрямую вызывать функции C без склеенного кода, такого как
JNI
или жеJNA
, - Невозможно напрямую вызвать функцию C в другом процессе; вместо этого вы должны использовать межпроцессное взаимодействие (общая память, каналы, сокеты, общие файлы и т. д.) для обмена информацией
- Хотя вы можете встроить интерпретатор Java в бэкэнд Pg и вызывать функцию C через JNI, вы действительно не хотите пытаться отображать графический интерфейс Swing непосредственно из бэкэнда Pg.
Что вам нужно, это многоступенчатый процесс:
Соберите данные, которые вы хотите захватить, в бэкэнде PostgreSQL. Если вы намереваетесь получить к нему доступ через то же соединение, что и в нем, вы можете использовать обычный
palloc
Буфер В противном случае вам нужно будет выделить буфер из общей памяти или обмениваться данными с помощью файловой системы.Доступ к этим данным из функции C, созданной с помощью интерфейса, вызываемого SQL, согласно документации по функциям расширения C в PostgreSQL (выше).
Используйте соединение PostgreSQL для передачи данных из функции интерфейса, вызываемой SQL, в ваше Java-приложение. Декодируйте его в своем приложении и отображайте по желанию.
С другой стороны:
Требуйте, чтобы ваша Java-программа или агент для нее работали в той же системе, что и сервер PostgreSQL, и чтобы агент записывал файлы в место, доступное для записи в Pg и читаемое вашей программой.
Прочитайте файлы с помощью вашей программы или ее агента и обработайте их для отображения
Вы могли бы даже сделать так, чтобы Pg записывал в сокет, который слушает ваша программа, но я не рекомендую этого, так как остановка вашей программы вызовет проблемы с производительностью в PostgreSQL.