Skip to content

GetDatabase

The mode’s database handle, or nil when the server has none.

The handle is one table with these methods (db:Query(...), with the colon). The answers arrive later, on the server’s own thread, in the callback: a query never waits on the tick.

Method What it does The callback
db:Query(sql, params, cb) rows cb(rows, err) - rows a list of {column = value} tables (a NULL column absent from its row)
db:Execute(sql, params, cb) a write cb(affected, insertId, err) - insertId on MySQL / MariaDB (PostgreSQL uses RETURNING)
db:Scalar(sql, params, cb) the first column of the first row cb(value, err)
db:Batch({ {sql, params}, ... }, cb) several writes in one transaction, all or nothing cb(ok, err)
db:QuerySync(sql, params) rows, now returns rows, err - during OnGameModeInit only, refused anywhere else
db:ExecuteSync(sql, params) a write, now returns affected, insertId, err - the same rule

params is {name = value} for @name in the SQL (or nil): strings, numbers (an integer stays an integer), booleans, and DB_NULL for a NULL (a nil value would vanish from the table). Values come back as strings, numbers, booleans; dates as ISO 8601 text. db.driver is "mysql" or "postgres": the SQL is yours and your engine’s. The owner’s timeout_seconds, max_rows and slow_query_ms bound every call; a callback that errors is logged like any script error. The rule that keeps the tick fast: read a player’s row once on the connect into SetPlayerData and your tables, answer every callback from memory, write on change and on the disconnect (a batch is one round trip).

GetDatabase()

table | nil - the handle, with driver and the methods above; nil without a [gamemode.database]

local db = GetDatabase()
function OnGameModeInit()
if not db then Log("no database: scores are not kept") return end
db:ExecuteSync("CREATE TABLE IF NOT EXISTS scores (name VARCHAR(24) PRIMARY KEY, kills INTEGER NOT NULL DEFAULT 0)")
end
function OnPlayerConnect(pid)
if not db then return end
db:Query("SELECT kills FROM scores WHERE name = @n", { n = GetPlayerName(pid) }, function(rows, err)
if err then Log("scores: " .. err) return end
SetPlayerData(pid, "kills", rows[1] and rows[1].kills or 0) -- from here the tick reads memory
end)
end
function OnPlayerDisconnect(pid)
if not db then return end
local name, kills = GetPlayerName(pid), GetPlayerData(pid, "kills") or 0 -- read now: the write runs later
db:Execute("UPDATE scores SET kills = @k WHERE name = @n", { k = kills, n = name }, function(affected, _, err)
if err then Log("scores: " .. err) return end
if affected == 0 then db:Execute("INSERT INTO scores (name, kills) VALUES (@n, @k)", { n = name, k = kills }) end
end)
end

SetPlayerData · SetSecretCommand · HashPassword · the The game mode’s database group of the index