--- /dev/null
+
+* Свободное ПО замечательно тем, что всегда можно самому посмтреть как и что устроено
+
+*Сеанс белой магии с разоблачениями*
+
+Не только знания о структуре, но и навыки работы с кодом
+
+
+## Стандартные арифметические типы
+
+Исторические причины:
+
+* Postgres95 моложе С99
+* Сколько байт займет `signed i;` ?
+
+Поэтому:
+
+```
+/* Historical names for types in <stdint.h>. */
+typedef int8_t int8;
+typedef int16_t int16;
+typedef int32_t int32;
+typedef int64_t int64;
+typedef uint8_t uint8;
+typedef uint16_t uint16;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+```
+`src/include/c.h`
+
+## Волшебные макросы pg-функций
+
+Создание расширения начинается с вызова макроса
+
+```
+PG_MODULE_MAGIC;
+```
+
+На этом магия не заканчивается, а только начинается.
+
+// сам макрос создает функцию проверяющую совместимость подгружаемого расширения с ядрос PostgreSQL
+
+// текст макроса можно прочитать в `src/include/fmgr.h` но это для джедаев
+
+### Аргументы
+
+Вспоминаем функцию из предыдущей лекции
+
+```
+Datum
+my_get_two(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_INT32(2);
+}
+```
+
+Макрос `PG_FUNCTION_ARGS` разворачивается в
+
+```
+/* Standard parameter list for fmgr-compatible functions */
+#define PG_FUNCTION_ARGS FunctionCallInfo fcinfo
+```
+см. `src/include/fmgr.h`
+
+---
+Структура `FunctionCallInfo` имеет развесистую структуру содержит информацию о параметрах переданных в pg-функцию, пользоваться ей напрямую затруднительно (если ты не джедай темной стороны силы)
+
+Но есть специальный набор макросов для удобной работы с аргументами pg-функции
+
+---
+
+Пример использования аргумента
+
+```
+#include "postgres.h"
+#include "fmgr.h"
+
+PG_FUNCTION_INFO_V1(warn_me);
+
+Datum
+warn_me(PG_FUNCTION_ARGS)
+{
+ int32 n = PG_GETARG_INT32(0);
+ elog(WARNING, "Предупреждаю: %i", n);
+ PG_RETURN_INT32(n);
+}
+```
+
+```
+CREATE FUNCTION warn_me(int) RETURNS int
+AS 'MODULE_PATHNAME', 'warn_me'
+LANGUAGE C;
+```
+
+Мы видим что макром `PG_GETARG_INT32` используется для получения первого аргумента.
+И этот аргумент сразу приводится к типу `int32`
+
+```
+# select warn_me(12);
+WARNING: Предупреждаю: 12
+ warn_me
+---------
+ 12
+(1 row)
+```
+
+---
+
+Посмотрим на реализацию `PG_GETARG_INT32` в `src/include/fmgr.h`:
+
+```
+/* Macros for fetching arguments of standard types */
+
+#define PG_GETARG_DATUM(n) (fcinfo->args[n].value)
+#define PG_GETARG_INT32(n) DatumGetInt32(PG_GETARG_DATUM(n))
+#define PG_GETARG_UINT32(n) DatumGetUInt32(PG_GETARG_DATUM(n))
+#define PG_GETARG_INT16(n) DatumGetInt16(PG_GETARG_DATUM(n))
+#define PG_GETARG_UINT16(n) DatumGetUInt16(PG_GETARG_DATUM(n))
+#define PG_GETARG_CHAR(n) DatumGetChar(PG_GETARG_DATUM(n))
+#define PG_GETARG_BOOL(n) DatumGetBool(PG_GETARG_DATUM(n))
+```
+
+Тут мы видим что как и все ее близницы братья `PG_GETARG_INT32` суммарно обращается к струкуре `fcinfo` о которой говорилось выше.
+
+Так же если мы проведем некоторое исследование мы узнаем что выражение `fcinfo->args[n].value` имеет тип `Datum`.
+
+И по всей видимости функция `DatumGetInt32` преобразует этот мифический пока для нас `Datum` к типу `int32`.
+
+К ним мы вернемся позже.
+
+(\*) задача со звездочкой: убедитесь самостоятельно что `fcinfo->args[n].value` имеет тип Datum
+
+---
+
+Если мы обратим свой взор к макросу `PG_RETURN_INT32` в том же `src/include/fmgr.h` то там увидем схожую картину
+
+```
+/* Macros for returning results of standard types */
+
+#define PG_RETURN_DATUM(x) return (x)
+#define PG_RETURN_INT32(x) return Int32GetDatum(x)
+#define PG_RETURN_UINT32(x) return UInt32GetDatum(x)
+#define PG_RETURN_INT16(x) return Int16GetDatum(x)
+#define PG_RETURN_UINT16(x) return UInt16GetDatum(x)
+#define PG_RETURN_CHAR(x) return CharGetDatum(x)
+#define PG_RETURN_BOOL(x) return BoolGetDatum(x)
+```
+
+Только тут направление преобразование другое `Int32GetDatum` из `int32` в `Datum`
+
+---
+
+Так что же такое Datum?
+
+`src/include/postgres.h`
+
+
+```
+/*
+ * A Datum contains either a value of a pass-by-value type or a pointer to a
+ * value of a pass-by-reference type. Therefore, we require:
+ *
+ * sizeof(Datum) == sizeof(void *) == 4 or 8
+ *
+ * The functions below and the analogous functions for other types should be used to
+ * convert between a Datum and the appropriate C type.
+ */
+
+typedef uintptr_t Datum;
+```
+
+`man uintptr_t`:
+
+`uintptr_t` is an unsigned integer type such that any valid (void *) value can be converted to this type and then converted back.
+
+Т.е. по сути это "машинное слово" определяемое разрядностью архитектуры.
+---
+
+В случае если размер данных позволяет, значение помещается в само "машинное слово".
+В случае если размеры данных выходят за рамки "машииного слова", данные размещаются в опертивной памяти а в переменную типа Datum помещается указатель на них.
+
+`src/include/postgres.h`
+
+```
+/*
+ * DatumGetInt32
+ * Returns 32-bit integer value of a datum.
+ */
+static inline int32
+DatumGetInt32(Datum X)
+{
+ return (int32) X;
+}
+```
+
+```
+/*
+ * Int32GetDatum
+ * Returns datum representation for a 32-bit integer.
+ */
+static inline Datum
+Int32GetDatum(int32 X)
+{
+ return (Datum) X;
+}
+```
+
+Т.е. тут мы просто явно приводим тип "машинного слова" к требуемому, ничего более
+
+(***) Задача с тремя звездочками: поразмышляйте, почему `DatumGetInt32` реализована как intine функция, а не как макрос
+
+---
+
+С хранением сложных типов данных в Datum мы будем резбираться на следующей лекции.
+
+А пока поиграем со стандартными типами
+
+```
+#include "postgres.h"
+#include "fmgr.h"
+
+PG_FUNCTION_INFO_V1(my_factorial);
+
+Datum
+my_factorial(PG_FUNCTION_ARGS)
+{
+ int32 res, n = PG_GETARG_INT32(0);
+ Datum d;
+
+ if (n < 0)
+ elog(ERROR, "Так нельзя!");
+
+ if (n == 0)
+ PG_RETURN_INT32(1);
+
+ d = DirectFunctionCall1(my_factorial, Int32GetDatum(n - 1));
+
+ res = DatumGetInt32(d) * n;
+
+ PG_RETURN_INT32(res);
+}
+```
+
+(*) Задача со звездочкой: Посмотрите на реализацию вызова `DirectFunctionCall1`, как она устроена внутри
+