Skip to content

Models Active Record

Xyranaut edited this page Jun 1, 2026 · 1 revision

Models (active-record)

The mysql_model_* natives are a higher-level way to read/write a single row without writing SQL by hand. You describe a table once by binding Pawn variables to columns; then find / insert / update / save / delete move data between those variables and the database.

It's optional sugar over prepared statements — under the hood it builds safe, parameterized SQL for you.

When to use it

  • ✅ Reading/writing one row keyed by an id (a player's account, a house, a car).
  • ❌ Not for multi-row SELECTs, joins, or aggregates — use mysql_execute for those.

Define a model

Bind each column to a Pawn variable. Pick a key column (usually the id).

enum E_ACCOUNT {
    acc_id,
    acc_name[24],
    acc_money,
    Float:acc_health
}
new g_Acc[MAX_PLAYERS][E_ACCOUNT];

new Model:g_AccModel[MAX_PLAYERS];

CreateAccountModel(playerid)
{
    // mysql_model_create(table[], MySQL:handle)
    new Model:m = mysql_model_create("accounts", g_DB);
    // bind: variable FIRST, then the column name (strings also take the max length)
    mysql_model_bind_int   (m, g_Acc[playerid][acc_id],     "id");
    mysql_model_bind_string(m, g_Acc[playerid][acc_name], 24, "name");
    mysql_model_bind_int   (m, g_Acc[playerid][acc_money],  "money");
    mysql_model_bind_float (m, g_Acc[playerid][acc_health], "health");
    mysql_model_set_key(m, "id");          // the primary key column
    g_AccModel[playerid] = m;
}

Bind the actual variables you use in your gamemode — a find writes the row's values straight into them, and save/update reads from them.

Load a row (find)

Set the key variable, then find:

g_Acc[playerid][acc_id] = 5;                 // who to load
mysql_model_find(g_AccModel[playerid], "OnAccFound", "d", playerid);

forward OnAccFound(playerid);
public OnAccFound(playerid)
{
    // g_Acc[playerid][acc_money] etc. are now filled from the DB row
    GivePlayerMoney(playerid, g_Acc[playerid][acc_money]);
    return 1;
}

Create a row (insert)

Fill the bound variables, then insert. The new auto-increment id is written back into your key variable:

g_Acc[playerid][acc_id] = 0;                 // 0/unset = new row
g_Acc[playerid][acc_name] = "Carol";
g_Acc[playerid][acc_money] = 0;
mysql_model_insert(g_AccModel[playerid], "OnAccInserted", "d", playerid);

forward OnAccInserted(playerid);
public OnAccInserted(playerid)
{
    printf("new account id = %d", g_Acc[playerid][acc_id]);  // filled in for you
    return 1;
}

Save changes (update / save)

  • mysql_model_update — UPDATE the row matching the key.
  • mysql_model_save — INSERT if the key is unset, else UPDATE (upsert convenience).
g_Acc[playerid][acc_money] = GetPlayerMoney(playerid);
mysql_model_update(g_AccModel[playerid]);    // fire-and-forget, or pass a callback

Delete

mysql_model_delete(g_AccModel[playerid]);    // deletes the row with the bound key

Cleanup

Free the model when you're done with it (e.g. on disconnect):

mysql_model_destroy(g_AccModel[playerid]);

Models are also cleaned up on disconnect/gamemode restart.

Why it's still safe

Every value is sent as a bound parameter, exactly like a prepared statement — so models are injection-safe too. They're just a friendlier API when you're moving one row in and out of Pawn variables.

API summary

Model:mysql_model_create(const table[], MySQL:handle = MYSQL_DEFAULT_HANDLE);
mysql_model_bind_int(Model:m, &variable, const column[]);
mysql_model_bind_float(Model:m, &Float:variable, const column[]);
mysql_model_bind_string(Model:m, variable[], variable_maxlen, const column[]);
mysql_model_set_key(Model:m, const column[]);
mysql_model_find/insert/update/save/delete(Model:m, const cb[]="", const fmt[]="", ...);
mysql_model_unbind(Model:m, const column[]);
mysql_model_clear(Model:m);
mysql_model_destroy(Model:m);

See the Native reference for the full list.

Next: Cookbook · Performance

Clone this wiki locally