Расширения для Safari: блокировщик контента в 50 строчек кода (Вадим Дробинин)
Расширения для PostgreSQL
-
Upload
anastasia-lubennikova -
Category
Data & Analytics
-
view
1.025 -
download
2
Transcript of Расширения для PostgreSQL
www.postgrespro.ru
РАСШИРЕНИЯ ДЛЯ POSTGRESQL
Hacking PostgreSQL
10.03.2016
2
Содержание
1. Расширение (contrib)
2. Новый тип данных
3. SPI (Server Programming Interface)
4. Особенности функций на Си
5. SRF (Set-Returning Function)
3
Расширение (contrib)
● Инфраструктура сборки PGXS● PGXN (PostgreSQL Extension Network)● PgFoundry● Управляется каталогом pg_extension
SELECT * FROM pg_extension;-[ RECORD 1 ]--+--------extname | plpgsqlextowner | 10extnamespace | 11extrelocatable | fextversion | 1.0extconfig | extcondition |
4
Управление расширением
CREATE EXTENSION [ IF NOT EXISTS ] extension_name
[ WITH ] [ SCHEMA schema_name ]
[ VERSION version ]
[ FROM old_version ]
DROP EXTENSION [ IF EXISTS ] extension_name [, ...] [ CASCADE | RESTRICT ]
ALTER EXTENSION extension_name UPDATE [ TO new_version ]
ALTER EXTENSION extension_name SET SCHEMA new_schema
ALTER EXTENSION extension_name ADD member_object
ALTER EXTENSION extension_name DROP member_object
5
Объекты в расширении
AGGREGATE agg_name (agg_type [, ...] ) |
CAST (source_type AS target_type) |
COLLATION object_name |
CONVERSION object_name |
DOMAIN object_name |
FOREIGN DATA WRAPPER object_name |
FOREIGN TABLE object_name |
FUNCTION function_name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) |
OPERATOR operator_name (left_type, right_type) |
OPERATOR CLASS object_name USING index_method |
OPERATOR FAMILY object_name USING index_method |
6
Объекты в расширении
[ PROCEDURAL ] LANGUAGE object_name |
SCHEMA object_name |
SEQUENCE object_name |
SERVER object_name |
TABLE object_name |
TEXT SEARCH CONFIGURATION object_name |
TEXT SEARCH DICTIONARY object_name |
TEXT SEARCH PARSER object_name |
TEXT SEARCH TEMPLATE object_name |
TYPE object_name |
VIEW object_name
7
Из чего состоит расширение?
pg_example.control – управляющий файл
pg_example.c – исходный текст на C
Makefile – файл для сборки с помощью GNU make
pg_example--1.0.sql – SQL-скрипт, создающий объекты БД
sql/pg_example.sql – регрессионные тесты
data/example.data – данные для регрессионных тестов
expected/pg_example.out – ожидаемые результаты
README.txt
8
pg_example.control
# pg_example extention
comment = 'my first extension'
default_version = '1.0'
module_pathname = '$libdir/pg_example'
relocatable = true
directory #Каталог, содержащий файл(ы) SQL скриптов
encoding #Кодировка набора символов, используемая файлами скриптов
requires #Расширения, от которых зависит данное расширение
superuser #Нужны ли права суперпользователя для установки/обновления расширения
schema #Схема, в которую должно быть загружено расширение. Только для не relocatable
9
Makefile
# pg_example/Makefile
# Название собираемого .so файла
MODULE_big = pg_example
# Список .o файлов, из которых собирается .so
OBJS = pg_example.o
# Название расширения
EXTENSION = pg_example
DATA = pg_example—1.0.sql
# Список тестов
REGRESS = pg_example
10
Makefile (2)
ifdef USE_PGXS
# Если USE_PGXS установлено, то нужные для сборки файлы# PostgreSQL находятся с помощью утилиты pg_config
PG_CONFIG = pg_config
PGXS := $( shell $( PG_CONFIG ) --pgxs )
include $(PGXS)
else
# Если нет, то считается что расширение помещено в папку# contrib исходников PostgreSQL
subdir = contrib/pg_example
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
11
Содержание
1. Расширение (contrib)
2. Новый тип данных
3. SPI (Server Programming Interface)
4. Особенности функций на Си
5. SRF (Set-Returning Function)
12
pair
Простейшая реализация типа данных пара key/value
/* pg_example--1.0.sql */
CREATE TYPE pair AS ( k text, v text );
CREATE OR REPLACE FUNCTION pair(anyelement, anyelement)
RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair';
CREATE OPERATOR ~> (
LEFTARG = anyelement,
RIGHTARG = anyelement,
PROCEDURE = pair
);
13
pair
CREATE EXTENSION pg_example;
CREATE TABLE keyvalue(kv pair);
INSERT INTO keyvalue VALUES ('key'::text~>'value'::text), ('foo'::text~>'bar'::text);
SELECT * FROM keyvalue;
SELECT (kv).k, (kv).v FROM keyvalue ORDER BY (kv).k;
kv ------------- (key,value) (foo,bar)
k | v -----+------- foo | bar key | value
14
contrib/hstore
Реализация key/value типа данных.
Предшественник json.
Документация модуля hstore
Презентация про hstore.
15
CREATE TYPE
CREATE TYPE hstore ( INTERNALLENGTH = -1, INPUT = hstore_in, OUTPUT = hstore_out, RECEIVE = hstore_recv, SEND = hstore_send, STORAGE = extended);
pg_type---------------+------------typname | hstoretypnamespace | 2200typowner | 16384typlen | -1typbyval | ftypinput | hstore_intypoutput | hstore_outtypreceive | hstore_recvtypsend | hstore_sendtypstorage | x (extended).......
16
hstore_in
CREATE FUNCTION hstore_in(cstring)RETURNS hstoreAS '$libdir/hstore','hstore_in'LANGUAGE C STRICTIMMUTABLE;
pg_proc----------------+---------------proname | hstore_inpronamespace | 2200proowner | 16384prolang | 13procost | 1prorows | 0provariadic | 0prorettype | 16385 (hstore)proargtypes | 2275 (cstring)prosrc | hstore_inprobin | $libdir/hstore.......
17
Новый оператор
CREATE OPERATOR -> ( LEFTARG = hstore, RIGHTARG = text, PROCEDURE = fetchval);
pg_operator-------------+------------oprname | ->oprnamespace | 2200oprowner | 16384oprkind | boprleft | 16385 (hstore)Oprright | 25 (text)oprresult | 25oprcom | 0oprnegate | 0oprcode | fetchval
18
Функция для оператора
CREATE FUNCTION fetchval(hstore,text)RETURNS textAS '$libdir/hstore','hstore_fetchval'LANGUAGE C STRICT IMMUTABLE;
pg_proc----------------+----------------proname | fetchvalpronamespace | 2200proowner | 16384prolang | 13procost | 1prosrc | hstore_fetchvalprobin | $libdir/hstoreproconfig | proacl | .......
19
Индексная поддержка
CREATE OPERATOR CLASS gist_hstore_opsDEFAULT FOR TYPE hstore USING gistAS
OPERATOR 7 @> ,OPERATOR 9 ?(hstore,text) ,OPERATOR 10 ?|(hstore,text[]) ,OPERATOR 11 ?&(hstore,text[]) ,OPERATOR 13 @ ,FUNCTION 1 ghstore_consistent (internal, hstore,
smallint, oid, internal),FUNCTION 2 ghstore_union (internal, internal),FUNCTION 3 ghstore_compress (internal),FUNCTION 4 ghstore_decompress (internal),FUNCTION 5 ghstore_penalty (internal, internal, internal),FUNCTION 6 ghstore_picksplit (internal, internal),FUNCTION 7 ghstore_same (ghstore, ghstore, internal),STORAGE ghstore;
20
Ещё примеры
● math3d● IMCS (In-Memory Columnar Store)
21
Содержание
1. Расширение (contrib)
2. Новый тип данных
3. SPI (Server Programming Interface)
4. Особенности функций на Си
5. SRF (Set-Returning Function)
22
SPI. Функции
SPI - Server Programming Interface● Процедурные языки
(PL/pgSQL, PL/python, PL/perl, PL/R ...)● API для расширений (pg_paxos api)● Триггеры (contrib/spi)
23
SPI. Функции
● SPI_connect / SPI_finish● SPI_push / SPI_pop● SPI_execute / SPI_exec● SPI_prepare● SPI_execute_plan● SPI_keepplan / SPI_saveplan
24
SPI. Функции (2)
● SPI_gettype / SPI_gettypeid● SPI_getrelname / SPI_getnspnam● SPI_copytuple● SPI_returntuple● SPI_modifytuple
25
SPI. Функции (3)
● SPI_palloc● SPI_repalloc● SPI_pfree
26
SPI. Timetravel
timetravel ('date_on', 'date_off' [,'insert_user', 'update_user',
'delete_user' ] )
set_timetravel(relname, on)
get_timetravel(relename)
27
SPI. Timetravel
CREATE EXTENSION timetravel;
CREATE TABLE tttest(
price_id int4, price_val int4,
price_on abstime, price_off abstime);
CREATE UNIQUE INDEX tttest_idx ON tttest (price_id,price_off);
CREATE TRIGGER timetravel
BEFORE INSERT OR DELETE OR UPDATE ON tttest
FOR EACH ROW EXECUTE PROCEDURE timetravel (price_on, price_off);
28
SPI. Timetravel. INSERT
INSERT INTO tttest VALUES (1, 1, NULL, NULL);
INSERT INTO tttest(price_id, price_val)VALUES (2, 2);
INSERT INTO tttest(price_id, price_val, price_off) VALUES (3, 3, 'infinity');
price_id | price_val | price_on | price_off ---------+-----------+------------------------+----------- 1 | 1 | 2016-03-07 17:59:46+03 | infinity 2 | 2 | 2016-03-07 18:00:09+03 | infinity 3 | 3 | 2016-03-07 18:00:32+03 | infinity
29
SPI. Timetravel. INSERT
if (TRIGGER_FIRED_BY_INSERT(trigdata→tg_event)) isinsert = true;
…
if (isinsert) {oldtimeon = SPI_getbinval(trigtuple,
tupdesc, attnum[a_time_on], &isnull);
if (isnull)
/* Установить в a_time_on * значение GetCurrentAbsoluteTime */
rettuple = SPI_modifytuple(rel, trigtuple, chnattrs, chattrs, newvals, newnulls);
return PointerGetDatum(rettuple);
30
SPI. Timetravel. DELETE
DELETE FROM tttest WHERE price_id = 1;
price_id | price_val | price_on | price_off ----------+-----------+------------------------+------------------------ 2 | 2 | 2016-03-07 18:00:09+03 | infinity 3 | 3 | 2016-03-07 18:00:32+03 | infinity 1 | 1 | 2016-03-07 17:59:46+03 | 2016-03-07 18:04:16+03
31
SPI. Timetravel. UPDATE
UPDATE tttest SET price_val = 30 WHERE price_id = 3;
price_id | price_val | price_on | price_off ----------+-----------+------------------------+------------------------ 2 | 2 | 2016-03-07 18:00:09+03 | infinity 1 | 1 | 2016-03-07 17:59:46+03 | 2016-03-07 18:04:16+03 3 | 3 | 2016-03-07 18:00:32+03 | 2016-03-07 18:06:19+03 3 | 30 | 2016-03-07 18:06:19+03 | infinity
32
SPI. Timetravel. SELECT
SELECT * FROM tttest WHERE price_off = 'infinity';
price_id | price_val | price_on | price_off ----------+-----------+------------------------+------------------------ 2 | 2 | 2016-03-07 18:00:09+03 | infinity 3 | 30 | 2016-03-07 18:06:19+03 | infinity
33
SPI. Timetravel. CHANGE DATE
SELECT set_timetravel('tttest', 0);
UPDATE tttest SET price_on = '01-Jan-1990 00:00:01'
WHERE price_id = 3 AND price_off <> 'infinity';
SELECT set_timetrave l('tttest', 1);
SELECT * FROM tttest WHERE price_id = 3AND price_on <= '10-Jan-1990' AND price_off > '10-Jan-1990';
price_id | price_val | price_on | price_off ----------+-----------+------------------------+------------------------ 3 | 3 | 1990-01-01 00:00:01+03 | 2016-03-07 18:06:19+03
34
Ещё примеры SPI
● pg_pathman● pg_paxos
35
Недостатки SPI
● Низкая скорость● Доступ только к HeapTuples
36
Содержание
1. Расширение (contrib)
2. Новый тип данных
3. SPI (Server Programming Interface)
4. Особенности функций на Си
5. SRF (Set-Returning Function)
37
Datum
● Datum – абстрактный тип данных в PostgreSQL
● Значения, которые помещаются в Datum, могут быть переданы по значению, остальные передаются по указателю.
● Аргументы функции и возвращаемые значения передаются как Datum.
● src/include/postgres.h
● src/include/utils/datum.h
38
Datum (2)
typedef uintptr_t Datum;
#define DatumGetPointer(X) ((Pointer) (X))
#define PointerGetDatum(X) ((Datum) (X))
#define DatumGetInt32(X) ((int32) GET_4_BYTES(X))
#define Int32GetDatum(X) ((Datum) SET_4_BYTES(X))
Size datumGetSize(Datum value, bool typByVal, int typLen);
Datum datumCopy(Datum value, bool typByVal, int typLen);
bool datumIsEqual(Datum value1, Datum value2,bool typByVal, int typLen);
39
Function manager
● src/backend/utils/fmgr/README● src/include/fmgr.h● src/include/funcapi.h
40
PG_MODULE_MAGIC
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
void _PG_init(void)
{
/* Define custom GUC variables */
/* Install hooks */
}
/* Source code */
41
Calling convention 1
/* Standard parameter list for fmgr-compatible functions */
#define PG_FUNCTION_ARGS FunctionCallInfo fcinfo
/* Макросы для доступа к параметрам */
#define PG_GETARG_DATUM(n) (fcinfo->arg[n])
#define PG_GETARG_INT32(n) DatumGetInt32(PG_GETARG_DATUM(n))
#define PG_NARGS() (fcinfo->nargs)
#define PG_ARGISNULL(n) (fcinfo->argnull[n])
/* Макросы для возврата параметров */
#define PG_RETURN_DATUM(x) return (x)
#define PG_RETURN_VOID() return (Datum) 0
#define PG_RETURN_NULL()
42
Пример
/* функция на Си */PG_FUNCTION_INFO_V1(add_one)Datumadd_one(PG_FUNCTION_ARGS){ int32 arg = PG_GETARG_INT32(0); PG_RETURN_INT32(arg + 1);}
/* SQL объявление функции */CREATE FUNCTION add_one(integer) RETURNS integer AS 'DIRECTORY/funcs', 'add_one' LANGUAGE C STRICT;
43
Работа с Tuple
#include "funcapi.h"
/* Узнать возвращаемый тип данных, * и, если он составной, получить TupleDesc */TypeFuncClass get_call_result_type(
FunctionCallInfo fcinfo,
Oid *resultTypeId,
TupleDesc *resultTupleDesc)
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
HeapTuple heap_form_tuple(TupleDesc tupdesc,Datum *values, bool *isnull)
HeapTupleGetDatum(HeapTuple tuple)
44
Ещё примеры SRF
● src/include/access/tupdesc.h● src/backend/access/common/tupdesc.c
45
Содержание
1. Расширение (contrib)
2. Новый тип данных
3. SPI (Server Programming Interface)
4. Особенности функций на Си
5. SRF (Set-Returning Function)
46
SRF
● 35.9.9. Returning Sets● src/include/funcapi.h
47
SRF (Set Returning Functions)
#Определить, что функция вызвана первый разSRF_IS_FIRSTCALL()
#Инициализировать FuncCallContext при первом вызовеSRF_FIRSTCALL_INIT()
#Очистить контекст при каждом последующем вызовеSRF_PERCALL_SETUP()
#Вернуть очередное значение функцииSRF_RETURN_NEXT(funcctx, result)
#Завершить выполнение SRF, сбросить контекстSRF_RETURN_DONE(funcctx)
48
SRF (1)
Datummy_Set_Returning_Function(PG_FUNCTION_ARGS){
FuncCallContext *funcctx;Datum result;MemoryContext oldcontext;<user defined declarations>
49
SRF (2)
...
if (SRF_IS_FIRSTCALL()){ funcctx = SRF_FIRSTCALL_INIT(); /* switch context when allocating stuff * to be used in later calls */ oldcontext = MemoryContextSwitchTo( funcctx->multi_call_memory_ctx); <user defined code> <if returning composite> <build TupleDesc, and perhaps AttInMetaData> <endif returning composite> <user defined code> /* return to original context * when allocating transient memory */ MemoryContextSwitchTo(oldcontext);}
50
SRF (3)
...<user defined code>funcctx = SRF_PERCALL_SETUP();<user defined code>
if (funcctx->call_cntr < funcctx->max_calls){ <user defined code> <obtain result Datum> SRF_RETURN_NEXT(funcctx, result);}else SRF_RETURN_DONE(funcctx);
}
51
contrib/pg_buffercache
pg_buffercache – информация о shared buffers в реальном времени
52
pg_buffercache--1.1.sql
CREATE FUNCTION pg_buffercache_pages()
RETURNS SETOF RECORD
AS 'MODULE_PATHNAME', 'pg_buffercache_pages'
LANGUAGE C;
CREATE VIEW pg_buffercache AS
SELECT P.* FROM pg_buffercache_pages() AS P
(bufferid integer, relfilenode oid,
reltablespace oid, reldatabase oid,
relforknumber int2, relblocknumber int8,
isdirty bool, usagecount int2,
pinning_backends int4);
53
pg_buffercache_pages.c
PG_FUNCTION_INFO_V1(pg_buffercache_pages);
Datumpg_buffercache_pages(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
Datum result;
MemoryContext oldcontext;
BufferCachePagesContext *fctx; /*User function context.*/
TupleDesc tupledesc;
TupleDesc expected_tupledesc;
HeapTuple tuple;
/* Продолжение по ссылке pg_buffercache_pages */
54
Ещё примеры SRF
● generate_series● contrib/pageinspect
55
Домашнее задание
● Написать на [email protected], какими расширениями вы часто пользуетесь и каких вам очень не хватает.
● Написать, используя SPI, расширение, которое на любое изменение строки добавляет в зарезервированные столбцы текущее время и имя пользователя.
● Ревью amcheck (B-Tree integrity checking tool).● Написать расширение bufferinspect по аналогии с
pageinspect для страниц в разделяемой памяти. Можно добавить дополнительные функции в pg_buffercache.
● Расширение dirtyread, которое позволяет прочитать (насколько возможно) битый файл из другой базы.
56
Продолжение следует...
В следующий раз:
– Обзор source tree– Путь разных запросов от получения
текста до выдачи результата