#python #mysql #user-defined-functions
#python #mysql #определяемые пользователем функции
Вопрос:
Я хотел бы иметь возможность вызывать Python через хранимые процедуры MySQL.
По этой причине мне было интересно, могу ли я использовать Python для написания UDF, который я могу вызывать из MySQL.
Если это невозможно, какой альтернативный способ я мог бы использовать, чтобы это произошло.
Ответ №1:
В документах MySQL 5.0 говорится, что триггер может вызывать UDF, так что эта часть кажется возможной. Просмотр исходного кода некоторых расширений UDF даст вам хорошее представление о сложности. Вы можете найти пакеты с открытым исходным кодом в репозитории UDF MySQL.
Хотелось бы, чтобы у меня был простой ответ на часть «создать UDF MySQL на Python», но я не знаю простого готового способа сделать это.
В Postgres есть язык PL / Python, который позволяет вам писать процедуры и функции непосредственно с использованием Python внутри базы данных. Этот код может быть лучшим руководством для выяснения того, как подключить Python к MySQL; однако, насколько мне известно, никто этого еще не сделал (но я бы хотел ошибаться).
Несколько запутанных деталей о том, как это может быть сделано:
UDF — это общие объекты, которые загружаются в демон MySQL, поэтому для его создания вам нужно иметь возможность генерировать заглушки C, которые (среди прочего) инициализируют интерпретатор Python, загружают и компилируют ваш скрипт Python в байт-код, а затем переводят аргументы UDF MySQL в вызов функции Python, а затем переводят возвращаемое значение обратно.
Для простой строковой функции UDF с именем myfunc
общий объект будет иметь следующие функции:
// initialize state when 'myfunc' is loaded.
my_bool myfunc_init(UDF_INIT *initid, UDF_ARGS *args, ...)
// call myfunc, this would need to translate the args, invoke the
// python function, then return the string, may need to create and cache
// python sub-interpreters on the fly, etc
char *myfunc(UDF_INIT *initid, UDF_ARGS *args, ...)
// clean up the state when 'myfunc' is unloaded.
void myfunc_deinit(UDF_INIT *initid);
Поскольку может быть несколько вызовов вашего UDF, выполняемых одновременно на отдельных
потоки, поэтому вам нужно будет найти
способ эффективного создания и кэширования субинтерпретаторов по требованию внутри
контекст одного вызова функции или безопасное повторное использование одного интерпретатора
в нескольких потоках (с блокировкой, которая может неприемлемо замедлить работу).