#include <sourcemod>
#include <dbi>
#include <dbupdater>
public void OnPluginStart()
{
// Получаем указатель на соединение с базой данных любым удобным способом.
//
// Для примера, я буду получать его в один поток с игровым тиком.
// В реальности, так делать не надо, ибо может вызвать фриз.
char szError[256];
Database hDb = SQL_Connect("my_database_configuration", true, szError, sizeof(szError));
if (!hDB)
{
SetFailState("Database failure: %s", szError);
return;
}
// Теперь инициализируем "мигратор".
// Он на вход ничего не принимает при инициализации.
// Для настроек, у него есть отдельные методы.
DBUpdater_Start();
// Настроим имя таблицы для хранения миграций (опционально).
DBUpdater_SetTableName("mysuperplugin_migrations");
// Настроим идентификатор плагина для хранения миграций (опционально).
//
// Желательно делать это: по-умолчанию, DBUpdater использует в качестве
// идентификатора плагина - путь к нему относительно папки plugins.
// Если плагин резко будет перемещён/переименован, DBUpdater попытается
// ещё раз применить все миграции.
//
// Если плагин лежит по пути "/addons/sourcemod/plugins/test/teeest/core.smx",
// то во внутренней таблице он получит идентификатор "test/teeest/core.smx".
DBUpdater_SetPluginIdentifier("Core");
// Для добавления миграций, используется метод "DBUpdater_Add()".
//
// На вход ему передаётся идентификатор версии (в виде числа)
// и указатель на функцию, которая отвечает за генерацию запросов
// для выполнения.
//
// Мы рекомендуем использовать следующий формат версий:
// abbccde
// Расшифровка: a.b.c d (alpha: 1, beta: 3, RC: 5, stable: 7, PL: 9) e
// Например, версию 1001070 можно прочитать как "1.0.0".
//
// В DBUpdater входят вспомогательные макросы для добавления и
// объявления самих функций-миграторов. Их можно выключить, объявив
// перед подключением инклуды константу "_dbupdater_withoutmacros":
// #define _dbupdater_withoutmacros
// #include <dbupdater>
//
// В этом примере, мы не стали выключать, и покажем, как удобно их
// использовать. Единственный макрос для добавления миграции в очередь
// принимает только один аргумент: идентификатор версии.
__DBUPDATER_ADD(1000070);
__DBUPDATER_ADD(1001070);
// Ещё можете включить "unsafe" режим. Он отличается от стандартного
// тем, что Вы можете получать указатель на соединение с базой данных
// посередине миграции, если не сохранили его. Делать так - НЕ
// РЕКОМЕНДУЕТСЯ, но если очень хочется - всегда пожалуйста.
// Но мы рекомендуем избегать использования соединения с БД в момент
// работы "мигратора".
// DBUpdater_MarkAsUnsafe();
// Как только всё готово - можете запускать миграции.
// "Раннер" на вход берёт три параметра:
// - соединение с базой данных
// - указатель на функцию, которая будет вызвана по окончанию работы
// - любые кастомные данные. По-умолчанию, "0".
// Обратите внимание: функция, которая будет вызвана по окончанию работы,
// так же получит указатель на соединение с базой данных, но временный.
// Если он Вам нужен - склонируйте его. Но лучше держите свой где-нибудь
// в глобальных переменных.
DBUpdater_Run(hDb, DBUpdater_OnFinished);
// Всё. После этого, DBUpdater посмотрит на последнюю установленную миграцию,
// и, если необходимо, запустит другие.
// Если нужды нет - сразу вызовет переданную в раннер функцию.
}
// Объявляем сами миграции.
// Выше мы упоминали "удобные макросы". Один из таких - __DBUPDATER_MAKEMIGRATION().
// Он генерирует прототип функции и имя для неё, получая на вход только идентификатор
// версии.
// Например, "вызвав" его с аргументом 1000070, сгенерируется статическая функция с
// именем "_DBUpdater_1000070_Migration".
__DBUPDATER_MAKEMIGRATION(1000070)
{
// В самой миграции нам доступны:
// - int iInstalledVersion. Текущая установленная версия.
// - int iProcessableVersion. Текущая обрабатываемая версия.
// - Transaction hTxn. Транзакция, которая будет отправлена на выполнение по
// завершению выполнения Вашей функции-"мигратора".
// - DBDriver hDriver. Драйвер соединения с базой данных. Полезно, если Вы
// поддерживаете несколько возможных драйверов (MySQL,
// SQLite), и хотите отдавать запросы, которые точно
// сработают на сервере.
// - any data. Переданные данные при добавлении миграции. Для "макросов",
// это всегда "0".
// типа создаём таблицы...
hTxn.AddQuery(" ... ");
hTxn.AddQuery(" ... ");
}
__DBUPDATER_MAKEMIGRATION(1001070)
{
// В обновлении мы решили создать ещё пару таблиц, обновить старые.
// Типа создаём...
hTxn.AddQuery(" ... ");
hTxn.AddQuery(" ... ");
// Один из запросов зависит от драйвера.
if (hDriver == view_as<DBDriver>(SQL_GetDriver("sqlite"))) // SQLite
{
// ...
}
else if (hDriver == view_as<DBDriver>(SQL_GetDriver("mysql"))) // MySQL
{
// ...
}
else if (hDriver == view_as<DBDriver>(SQL_GetDriver("pgsql"))) // PostgreSQL
{
// ...
}
// .. ещё какие-то сверхсложные запросы ..
}
// Функция, которой заканчивается исполнение всех миграций.
static void DBUpdater_OnFinished(int iInstalledVersion, Database hDB, const char[] szError, any data)
{
// - int iInstalledVersion. Последняя успешно установленная версия.
// - Database hDB. Соединение с базой, которое прилетело из последнего Database.Query()
// ОБРАТИТЕ ВНИМАНИЕ: Этот указатель на соединение с базой умрёт по
// завершению выполнения этой функции. Если он Вам нужен - склонируйте
// его.
// - char[] szError. Ошибка, если она произошла.
// - any data. Кастомные данные, переданные в раннер.
// ... суперсложная логика по обработке результатов, стопа плагина (если произошла ошибка) ...
}