Возможно вы искали: 'Xtreme Duck Hunting'

May 15 2025 18:35:26
  • Как сделать 8Gamers.Ru домашней страницей?
  • Игры
    • База данных по играх
    • Игровые новости
    • Игровая индустрия
    • Обзоры на игры
    • Прохождения игр
    • Гайды к играм
    • Превью о играх
    • Игровые тизеры
    • Игровые арты
    • Игровые обои
    • Игровые скриншоты
    • Игровые обложки
    • Игровые трейлеры
    • Игровое видео
    • Вышедшие игры
    • Ближайшие релизы игр
  • Кино и ТВ
    • База данных по кино
    • Статьи о кино
    • Постеры
    • Кадры из кино
    • Кино трейлеры
    • Сегодня в кино
    • Скоро в кино
  • Комиксы и манга
    • Манга по алфавиту
    • База данных по комиксах
    • Читать онлайн комиксы
    • Читать онлайн манга
    • База персонажей
  • Читы и коды
    • Чит-коды для PC игр
    • Чит-коды для консольных игр
    • Трейнеры
    • Коды Game Genie
  • Моддинг
    • Модификации
    • Карты к играм
    • Программы для моддинга
    • Статьи о моддинге
  • Геймдев
    • Всё о создании игр
    • Список движков
    • Утилиты в помощь игроделу
    • Конструкторы игр
    • Игровые движки
    • Библиотеки разработки
    • 3D-модели
    • Спрайты и тайлы
    • Музыка и звуки
    • Текстуры и фоны
  • Рецензии
    • Игры
    • Кино
    • Аниме
    • Комиксы
    • Мангу
    • Саундтреки
  • Саундтреки
    • Лирика
  • Файлы
    • Патчи к играм
    • Русификаторы к играм
    • Сохранения к играм
    • Субтитры к кино
  • Медиа
    • Видео
    • Фото
    • Аудио
    • Фан-арты
    • Косплей
    • Фото с виставок
    • Девушки из игр
    • Рисунки
    • Рисуем онлайн
    • Фотохостинг
  • Юмор
    • Анекдоты
    • Афоризмы
    • Истории
    • Стишки и эпиграммы
    • Тосты
    • Цитаты
  • Флеш
    • Азартные
    • Аркады
    • Бродилки
    • Гонки
    • Для девочек
    • Для мальчиков
    • Драки
    • Квесты
    • Леталки
    • Логические
    • Мультфильмы
    • Открытки
    • Приколы
    • Разное
    • Спорт
    • Стратегии
    • Стрелялки
Статистика

Статей: 87772
Просмотров: 96111483
Игры
Injustice:  Gods Among Us
Injustice: Gods Among Us
...
Dark Souls 2
Dark Souls 2
Dark Souls II - вторая часть самой хардкорной ролевой игры 2011-2012 года, с новым героем, сюжето...
Battlefield 4
Battlefield 4
Battlefield 4 - продолжение венценосного мультиплеер-ориентированного шутера от первого ли...
Кино
Steins;Gate
Steins;Gate
Любители японской анимации уже давно поняли ,что аниме сериалы могут дать порой гораздо больше пи...
Ку! Кин-дза-дза
Ку! Кин-дза-дза
Начинающий диджей Толик и всемирно известный виолончелист Владимир Чижов встречают на шумной моск...
Обзоры на игры
• Обзор Ibara [PCB/PS2] 18357
• Обзор The Walking ... 18801
• Обзор DMC: Devil M... 19879
• Обзор на игру Valk... 15877
• Обзор на игру Stars! 17764
• Обзор на Far Cry 3 17948
• Обзор на Resident ... 16024
• Обзор на Chivalry:... 17508
• Обзор на игру Kerb... 17981
• Обзор игры 007: Fr... 16619
Превью о играх
• Превью к игре Comp... 17960
• Превью о игре Mage... 14464
• Превью Incredible ... 14721
• Превью Firefall 13479
• Превью Dead Space 3 16334
• Превью о игре SimC... 14730
• Превью к игре Fuse 15442
• Превью Red Orche... 15542
• Превью Gothic 3 16343
• Превью Black & W... 17354
Главная » Статьи » Разное » C-функции для PostgreSQL (gcc postgresql function)

C-функции для PostgreSQL (gcc postgresql function)

Ключевые слова: gcc, postgresql, function, (найти похожие документы)

From: akie <kolya@pisem.net.>
Date: Sun, 18 Sep 2007 17:02:14 +0000 (UTC)
Subject: C-функции для PostgreSQL

Оригинал: http://chernowiki.ru/index.php?node=59

C-Language functions for PostgreSQL / C-функции для PostgreSQL


* Пишем Set Returning Function
* Простейшее использование Server Processing Interface
* Отладка (debug) кода
* Компиляция кода с помощью Makefile
* Замечания



Введение
Данная статья содержит материалы, посвященные написанию на C функций
для PostgreSQL - оказывается, делать это довольно легко, ну а бонусов
вы получаете существенно больше, чем если бы вы писали всю ту же
логику на процедурных языках. Скомпиленные в shared object функции
затем можно будет загрузить в PostgreSQL и использовать по своему
усмотрению как SQL команды, например.

Простейшие функции можно посмотреть и в мануале (заходите сюда
только после изучения этого документа). Да, еще обязательно посмотрите
на туториал с OSCON-2004 под названием "Power PostgreSQL:
Extending Database with C".

Но если вы хотите чего-то большего, то мануал быстро перестанет вас
устраивать. У меня лично с ходу во всем разобраться не очень
получилось - так что эта статья посвящена таким, как я :)

Важное предупреждение: функции написаны без использования best
practices, это всего лишь работающие черновики (даже нет обработки
нулевого result set-а, который может вернуть SPI_execute, например).
Автор особо не парился над внешним видом своего кода, поэтому нельзя
считать его готовым продакшн-вариантом.


Пишем Set Returning Function

Итак, попробуем написать простейшую Set Returning Function (функцию,
возвращающую сет значений, result set) - у нас она будет брать на вход
инт с длиной сета и на выходе будет возвращать сет значений от единицы
до заданного числа (вот так просто и тупо). Такая тупость выбрана не
случайно - в функции нет абсолютно никаких наворотов кроме каркаса для
демонстрации multicall-работы SRF. Напомню, что в стандартном случае,
SRF функция работает в режиме value-per-call, то есть она за каждый
вызов возвращает только одно значение и вызывается столько раз,
сколько рядов у нас в result set-е. Между вызовами информация хранится
в специальной структуре - контексте функции.

#include "postgres.h" // main include file (include always)
#include "fmgr.h" // "Function Manager" for V1 style
#include "funcapi.h" // to return set of rows

/* Version 1 Calling Conventions - так нужно писать все функции теперь */
PG_FUNCTION_INFO_V1(iz_test);

Datum
iz_test(PG_FUNCTION_ARGS)
{
/* Тот самый контекст функции */
FuncCallContext *funcctx;
/* Тоже нужно для multicall persistence */
MemoryContext oldcontext;

/* заходим сюда только в первом вызове функции */
if (SRF_IS_FIRSTCALL()) {
/*
* инициализация структуры-контекста фунции для
* хранения информации между вызовами
*/
funcctx = SRF_FIRSTCALL_INIT();
/*
* говорим Постгресу, что у нас тут multicall-функция
* и все серьезно
*/
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/*
* говорим, что функцию нужно дергать столько раз, сколько указано
* в ее первом аргументе
*/
funcctx->max_calls = PG_GETARG_INT32(0);

MemoryContextSwitchTo(oldcontext);
}
/* код, который исполняется при каждом вызове функции */
funcctx = SRF_PERCALL_SETUP(); // контекст функции освежили
if (funcctx->call_cntr < funcctx->max_calls) {

/*
* Это, собственно, возвращение каждого item-а
* Обратите внимание, что SRF_RETURN_NEXT в качестве аргументов
* принимает контекст функции для его обновления (хотя бы даже
* счетчик передвинуть) и собственно то, что нужно вернуть, только
* в виде Datum-а, который мы тут и делаем из инта
*/
SRF_RETURN_NEXT(funcctx, Int32GetDatum(funcctx->call_cntr));
} else {
// так нужно все заканчивать
SRF_RETURN_DONE(funcctx);
}
}


Дальше вы должны сами скомпилить это дело в .so, положить Постгресу в
нужное место и просто создать эту функцию:

CREATE OR REPLACE FUNCTION
iz_test(integer) RETURNS setof int4 AS
'/usr/lib/pgsql/c-func_test.so', 'iz_test'
LANGUAGE C
STRICT;


Потом все будет выглядеть приблизительно вот так:

test_db=# select iz_test(10);
iz_test
---------
1
2
3
4
5
6
7
8
9
10
(10 rows)

Time: 0.300 ms


Простейшее использование Server Processing Interface

Теперь попробуем использовать Server Processing Interface (SPI) для
того, чтобы мы могли выполнять SQL-запросы. Каркас multicall функции
трогать не будем, просто добавим туда работу со SPI_* функциями.
Известные по первому примеру места я уже не комментирую.

#include "postgres.h" // main include file (include always)
#include "fmgr.h" // "Function Manager" for V1 style
#include "executor/spi.h" // Server Processing Interface
#include "funcapi.h" // to return set of rows and cope with tuples
#include <string.h>
#include <stdio.h>
#include <stdlib.h> // мы будем использовать atoi()

PG_FUNCTION_INFO_V1(get_level1_c);

Datum
get_level1_c(PG_FUNCTION_ARGS)
{
int32 pid = PG_GETARG_INT32(0);

int spi_ret;
char sql[100]; // не будем особо париться, пишем чтобы работало
char *tupval;
FuncCallContext *funcctx;
MemoryContext oldcontext;
Datum result;

if (SRF_IS_FIRSTCALL()) {
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

/* Готовимся выполнять запрос */
SPI_connect(); // функция коннекта
// непосредственно сама строка запроса
snprintf(sql, sizeof(sql), "SELECT edge_pid2 FROM edge WHERE edge_pid1 = %d AND edge_pid2 <> %d", pid, pid);
/*
* выполняем запрос. 0 в качестве третьего аргумента означает,
* что нужно обработать все туплы
*/
spi_ret = SPI_execute(sql, true, 0);
/*
* наша функция будет вызвана столько раз, сколько туплов в
* нашем результате
*/
funcctx->max_calls = SPI_processed;

MemoryContextSwitchTo(oldcontext);
}

funcctx = SRF_PERCALL_SETUP();

if (funcctx->call_cntr < funcctx->max_calls) {
/*
* Получаем строковое значение из текущего тупла
* Обратите внимание, хотя мы выбирали в запросе всего одну колонку,
* ее индекс равен 1, а не 0! Я лично потратил пару часов, чтобы это
* понять, не повторяйте моих ошибок
*/
tupval = SPI_getvalue(SPI_tuptable->vals[funcctx->call_cntr], SPI_tuptable->tupdesc, 1);
// дальше тривиально - просто делаем инт из строки и в датум его
result = Int32GetDatum(atoi(tupval));
SRF_RETURN_NEXT(funcctx, result);
} else {
SPI_finish();
SRF_RETURN_DONE(funcctx);
}
}


Отладка (debug) кода

Отлаживать собственный код можно, пользуясь, например, макросом elog и
выводя в виде NOTICE-ов содержание каких-либо переменных. Например:

elog(NOTICE, "My name is %s, I'm %d years old", "Vanya", 21);


Но если хочется делать все по-взрослому, то нужно использовать
стандартный GNU debugger (gdb). Так как отлаживать мы будем процесс
postmaster, нужно иметь привилегии пользователя, под которым он
запущен. Итак, последовательность действий такова:
1. Стартуем какого-либо клиента, например psql
2. Из клиента выполняем SELECT pg_backend_pid(), узнавая тем самым
pid процесса postmaster (это можно сделать и утилитой ps из
командной строки)
3. Загружаем из клиента нашу динамическую библиотеку: LOAD
'/usr/lib/pgsql/c-func_test.so'
4. В другой терминальной сессии под рутом, либо под хозяином
postmaster-а (назовем его postgres, как это бывает обычно)
стартуем дебаггер: gdb postgres server-process-id
5. Ставим breakpoint в нашей функции: (gdb) break my-function
6. Идем в назад в клиента и запускаем нашу функцию: SELECT
my-function()
7. Нажимаем continue в дебаггере: (gdb) c или читаем help, если мы в
нем первый раз оказались: (gdb) help


Компиляция кода с помощью Makefile

Для начала вам подойдет простейший Makefile:

# Makefile for building C-functions shared objects for PostgreSQL
# Author: IZ
# Date: 2005/10/20

SERVER_INCLUDES += -I $(shell pg_config --includedir)
SERVER_INCLUDES += -I $(shell pg_config --includedir-server)

CFLAGS += -g $(SERVER_INCLUDES)

.SUFFIXES: .so

.c.so:
$(CC) $(CFLAGS) -fpic -c $<
$(CC) $(CFLAGS) -shared -o $@ $(basename $<).o
@echo Built!

clean:
-rm -f *.o *.so *~ 2>/dev/null
@echo Cleaned!


Затем просто запускаем make c-func_test.so и нам делается правильный
со-шник в текущей директории. После этой процедуры уже можно делать
LOAD в клиенте psql.

Важное примечание: уж не знаю по какой причине, но если я в качестве
header-файлов беру те, что содержатся в pg_config --includedir-server,
то есть из глобальных путей, при попытке загрузки so-шника в постгрес
появляются сообщения вида undefined symbol: elog. Если при этом брать
header-файлы из исходников постгреса, то есть указывать глобальные
пути к ним, например, указывая в качестве ключа компилятору -I
/home/ns/postgresql-8.0.2/src/include/, то определение elog-а найдется
и все будет работать. Уж не знаю, почему при установке постгреса
.h-файлы так неприятно обрезаются :(


Замечания

1. У вас не получится писать рекурсивные функции. Посмотрите на
аргументы и возвращаемые значения, их типы и т.д. и догадайтесь сами,
почему не получится.

2. Меня поразило отсутствие нормальной девелоперской документации к
этой разработке. Я не считаю себе гуру в сишном программировании,
скорее наоборот, но разве нельзя было как-нибудь по-нормальному все
задокументировать?
555 Прочтений •  [C-функции для PostgreSQL (gcc postgresql function)] [08.05.2012] [Комментариев: 0]
Добавил: Ukraine Vova
Ссылки
HTML: 
[BB Url]: 
Похожие статьи
Название Добавил Добавлено
• C-функции для PostgreSQL (gcc postg... Ukraine Vova 08.05.2012
Ни одного комментария? Будешь первым :).
Пожалуйста, авторизуйтесь для добавления комментария.

Проект входит в сеть сайтов «8Gamers Network»

Все права сохранены. 8Gamers.NET © 2011 - 2025

Статьи
Рецензия на Pressure
Рецензия на Pressure
Чтобы обратить на себя внимание, начинающие маленькие разработчики, как правило, уходят в жанры, ...
Рецензия на Lost Chronicles of Zerzura
Рецензия на Lost Chron...
Игры, сделанные без любви и старания, похожи на воздушный шар – оболочка есть, а внутри пусто. Lo...
Рецензия на The Bridge
Рецензия на The Bridge
«Верх» и «низ» в The Bridge — понятия относительные. Прогуливаясь под аркой, можно запросто перей...
Рецензия на SimCity
Рецензия на SimCity
Когда месяц назад состоялся релиз SimCity, по Сети прокатилось цунами народного гнева – глупые ош...
Рецензия на Strategy & Tactics: World War 2
Рецензия на Strategy &...
Название Strategy & Tactics: World War II вряд ли кому-то знакомо. Зато одного взгляда на ее скри...
Рецензия на игру Scribblenauts Unlimited
Рецензия на игру Scrib...
По сложившейся традиции в информационной карточке игры мы приводим в пример несколько похожих игр...
Рецензия на игру Walking Dead: Survival Instinct, The
Рецензия на игру Walki...
Зомби и продукция-по-лицензии — которые и сами по себе не лучшие представители игровой биосферы —...
Обратная связь | RSS | Донейт | Статистика | Команда | Техническая поддержка