http://postgres.cz/index.php?title=Jak_se_st%C3%A1t_hackerem_II&feed=atom&action=historyJak se stát hackerem II - Historie editací2024-03-29T10:31:42ZHistorie editací této stránkyMediaWiki 1.36.0http://postgres.cz/index.php?title=Jak_se_st%C3%A1t_hackerem_II&diff=386&oldid=prev85.160.73.157 v 24. 2. 2008, 13:122008-02-24T13:12:36Z<p></p>
<p><b>Nová stránka</b></p><div>''Implementace pojmenovaných parametrů a variadických funkcí, podpora protokolu JSON''<br />
<br />
Tento článek navazuje na článek [[Jak se stát hackerem]].<br />
<br />
Autor: [[Pavel Stěhule]] - únor 2008<br />
<br />
V Postgresu chybí možnost implementace funkcí s variabilním počtem parametrů - tyto funkce se označují jako variadické. Variadické funkce se sice v pg vyskytují, jedná se ale o implementaci na úrovni parseru, kdy se určité funkce nevolají prostřednictvím executoru funkcí, ale přímo. Tj. nedochází k vyhledávání implementace funkce v tabulce ''pg_proc''. Tato tabulka obsahuje seznam všech funkcí s fixním počtem parametrů (včetně přetížených funkcí). Vyhledává se na základě shody počtu parametrů, a na základě shody typů případně možnosti přetypování a dosažení shody typů parametrů. Velká většina vestavěných funkcí je nevariadické - pokud mohou mít různé typy parametrů, tak jsou implementovány jako množina přetížených funkcí. Najdou se ale výjimky - např. funkce ''greatest'' nebo ''least'' (případně novější ''xmlforest''). Při implementaci těchto funkcí bylo nutné modifikovat parser a executor. <br />
<br />
Cílem je umožnit implementaci variadických funkcí bez nutnosti modifikace parseru. Plánem je změna procedury, která porovnává shodu parametrů a to tak, že pokud nedojde ke shodě, tak se vygeneruje dynamicky (bez zápisu do pg_proc) fiktivní funkce, která bude obsahovat nutný počet anyelement parametrů. Aby bylo možné tyto funkce spouštět z jazyka SQL a PL/pgSQL, tak při volání se nevytvoří seznam parametrů, ale pole parametrů - za předpokladu, že skutečné parametry nejsou pole. K tomu je potřeba vytvořit nový fiktivní datovy typ: ''ANYNONARRAYS''. Funkce může obsahovat pouze jeden parametr tohoto typu a tento parametr musí být uložen jako poslední.<br />
<pre><br />
CREATE OR REPLACE FUNCTION Least(ANYNONARRAYS)<br />
RETURNS ANYELEMENT AS $$<br />
SELECT MIN($1[i])<br />
FROM generate_series(array_lower($1,1),<br />
array_upper($1,1)) g(i)<br />
$$ LANGUAGE SQL IMMUTABLE;<br />
<br />
SELECT Least(10,1,8,8,1,3); --> 1<br />
</pre><br />
<br />
==Zavedení nových fiktivních typů==<br />
Vytvořím nové datové typy ANYPARAMS (variadic k ANY) a ANYNONARRAYS (variadic k ANYNONARRAY). Veškeré vestavěné typy jsou evidovány v souboru (src/include/catalog/pg_type.h). Na základě obsahu tohoto souboru se generují systémové tabulky.<br />
<pre> <br />
DATA(insert OID = 3534 ( anyparams PGNSP PGUID 4 t p t \054 0 0 0 anyparams_in anyparams_out - - - - - i p f 0 -1 0 _null_ _null_ ));<br />
#define ANYPARAMSOID 3534<br />
DATA(insert OID = 3535 ( anynonarrays PGNSP PGUID 4 t p t \054 0 0 0 anynonarrays_in anynonarrays_out - - - - - i p f 0 -1 0 _null_ _null_ ));<br />
#define ANYNONARRAYSOID 3535<br />
</pre><br />
Každý datový typ bez výjimky musí mít přiřazeny vstupní a vstupní funkce (/src/include/catalog/pg_proc.h):<br />
<pre><br />
DATA(insert OID = 2964 ( anyparams_in PGNSP PGUID 12 1 0 f f t f i 1 3534 "2275" _null_ _null_ _null_ anyelement_in - _null_ _null_ ));<br />
DESCR("I/O");<br />
DATA(insert OID = 2967 ( anyparams_out PGNSP PGUID 12 1 0 f f t f i 1 2275 "3534" _null_ _null_ _null_ anyelement_out - _null_ _null_ ));<br />
DESCR("I/O");<br />
DATA(insert OID = 2965 ( anynonarrays_in PGNSP PGUID 12 1 0 f f t f i 1 3535 "2275" _null_ _null_ _null_ anyelement_in - _null_ _null_ ));<br />
DESCR("I/O");<br />
DATA(insert OID = 2966 ( anynonarrays_out PGNSP PGUID 12 1 0 f f t f i 1 2275 "3534" _null_ _null_ _null_ anyelement_out - _null_ _null_ ));<br />
DESCR("I/O");<br />
</pre><br />
Reálně nelze do těchto typů uložit žádnou hodnotu. Proto jsou v/v funkce triviální - při volání spustí výjimku (pseudotypes.c):<br />
<pre><br />
/* <br />
* anyparams_in - input routine for pseudo-type ANYPARAMS. <br />
*/ <br />
Datum <br />
anyparams_in(PG_FUNCTION_ARGS) <br />
{ <br />
ereport(ERROR, <br />
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), <br />
errmsg("cannot accept a value of type anyparams"))); <br />
<br />
PG_RETURN_VOID(); /* keep compiler quiet */ <br />
} <br />
</pre><br />
Po přeložení nesmíme zapomenout inicializovat db cluster příkazem ''initdb''. Přidáním vestavěných datových typů a funkcí dojde k posunu přiřazených jedinečných identifikátorů, čímž se datové soubory stanou nekompatibilní.<br />
==Úprava parseru==<br />
Při parsování dochází k určení Oid funkce na základě shody parametrů volané funkce a záznamu v systémové tabulce pg_proc. Klíčovou roli hraje funkce ''FuncnameGetCandidates'' (/src/backend/catalog/namespace.c). Parametrem této funkce je úplný název funkce (může obsahovat schéma) a počet parametrů. Výstupem je pak seznam potenciálních funkcí, které teoreticky mohou obsloužit požadavek (teoreticky - jinde se kontroluje shoda parametrů). Celý trik je v tom, že pokud zjistíme, že funkce obsahuje parametr ANYPARAMS nebo ANYNONARRAYS, tak nahradíme tento parametr n parametry ANY nebo ANYNONARRAY, tak aby souhlasil seznam parametrů:<br />
<pre><br />
<br />
</pre><br />
==Transformace seznamu parametrů na pole parametrů==<br />
<br />
Po tomto kroku můžeme psát variadické funkce - zatím pouze v jazyce C.</div>85.160.73.157