From: Nikolay Shaplov Date: Thu, 7 Aug 2025 14:25:21 +0000 (+0300) Subject: Зачатки лекции про типы данных X-Git-Url: http://gitweb.nataraj.world/?a=commitdiff_plain;h=7e61e6887bbd26df6dd7a1f99c60c9e43a61de0e;p=articles.git Зачатки лекции про типы данных --- diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/Makefile b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/Makefile new file mode 100644 index 0000000..f3bc8f7 --- /dev/null +++ b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/Makefile @@ -0,0 +1,13 @@ +MODULE_big = data_types_examples +EXTENSION = data_types_examples # Name of the extension +DATA = data_types_examples--0.0.1.sql +# REGRESS = my_first_extension-main-test + +OBJS = data_types_examples.o warn_me.o my_factorial.o + + +PG_CONFIG ?= pg_config # Path to the pg_config executable +PGXS := $(shell $(PG_CONFIG) --pgxs) # Get the PostgreSQL Extension Makefile from pg_config +include $(PGXS) # Include the PostgreSQL Extension Makefile + + diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples--0.0.1.sql b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples--0.0.1.sql new file mode 100644 index 0000000..bbd5d55 --- /dev/null +++ b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples--0.0.1.sql @@ -0,0 +1,15 @@ + +CREATE FUNCTION my_inc() +RETURNS INT +AS 'MODULE_PATHNAME', 'my_inc' +LANGUAGE C; + +CREATE FUNCTION warn_me(int) RETURNS int +AS 'MODULE_PATHNAME', 'warn_me' +LANGUAGE C; + + +CREATE FUNCTION my_factorial(int) RETURNS int +AS 'MODULE_PATHNAME', 'my_factorial' +LANGUAGE C; + diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.bc b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.bc new file mode 100644 index 0000000..7978b75 Binary files /dev/null and b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.bc differ diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.c b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.c new file mode 100644 index 0000000..e53bb30 --- /dev/null +++ b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.c @@ -0,0 +1,13 @@ +#include "postgres.h" +#include "fmgr.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(my_inc); + +Datum +my_inc(PG_FUNCTION_ARGS) +{ + + PG_RETURN_INT32(2); +} diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.control b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.control new file mode 100644 index 0000000..99d98e9 --- /dev/null +++ b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.control @@ -0,0 +1,8 @@ +# my_first_extension.control +# Comment line to provide additional information about the extension +comment = 'Data Types Exampls' + +# Specifies the default version of the extension +default_version = '0.0.1' +module_pathname = '$libdir/data_types_examples' + diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.o b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.o new file mode 100644 index 0000000..adbe744 Binary files /dev/null and b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.o differ diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.so b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.so new file mode 100755 index 0000000..0ff0684 Binary files /dev/null and b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/data_types_examples.so differ diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.bc b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.bc new file mode 100644 index 0000000..42a2409 Binary files /dev/null and b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.bc differ diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.c b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.c new file mode 100644 index 0000000..2e60743 --- /dev/null +++ b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.c @@ -0,0 +1,24 @@ +#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); +} + diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.o b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.o new file mode 100644 index 0000000..e0852f0 Binary files /dev/null and b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/my_factorial.o differ diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.bc b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.bc new file mode 100644 index 0000000..33a0e4f Binary files /dev/null and b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.bc differ diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.c b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.c new file mode 100644 index 0000000..4da0231 --- /dev/null +++ b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.c @@ -0,0 +1,13 @@ +#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); +} + diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.o b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.o new file mode 100644 index 0000000..3a1d04c Binary files /dev/null and b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/data_types_examples/warn_me.o differ diff --git a/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/log.md b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/log.md new file mode 100644 index 0000000..f32f1bd --- /dev/null +++ b/slides/2025 - Becoming PosgtreSQL Developer. 2. Basic Structures: Register Data Types/src/log.md @@ -0,0 +1,245 @@ + +* Свободное ПО замечательно тем, что всегда можно самому посмтреть как и что устроено + +*Сеанс белой магии с разоблачениями* + +Не только знания о структуре, но и навыки работы с кодом + + +## Стандартные арифметические типы + +Исторические причины: + +* Postgres95 моложе С99 +* Сколько байт займет `signed i;` ? + +Поэтому: + +``` +/* Historical names for types in . */ +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`, как она устроена внутри +