Skip to content

SQL Queries

The SQL API lets you query the game database directly from Lua scripts using ODBC connections.

Getting a Connection

local db = GetConnection("GameDB")
db:Connect("MuOnline_GameDB", "sa", "your_password")

Tip

Connections are cached per name. Calling GetConnection("GameDB") a second time returns the same instance — no need to reconnect.

Reading Player Data

local function GetPlayerResets(playerName)
    local db = GetConnection("GameDB")
    db:ExecQuery("SELECT Reset, MasterReset FROM Character WHERE Name = '" .. playerName .. "'")

    if db:Fetch() then
        local resets = db:GetAsInteger("Reset")
        local masterResets = db:GetAsInteger("MasterReset")
        db:Close()
        return resets, masterResets
    end

    db:Close()
    return 0, 0
end

-- Usage in a command handler
BridgeFunctionAttach("OnCommandManager", function(aIndex, code, arg)
    if code == 200 then
        local player = GetUser(aIndex)
        if player == nil then return 0 end

        local resets, mr = GetPlayerResets(player.Name)
        GCNoticeSend(aIndex, 1, "Resets: " .. resets .. " | Master Resets: " .. mr)
        return 1
    end
    return 0
end)

Online Player Ranking

local function ShowTopPlayers(aIndex)
    local db = GetConnection("GameDB")
    db:ExecQuery("SELECT TOP 5 Name, Reset, MasterReset FROM Character ORDER BY MasterReset DESC, Reset DESC")

    GCNoticeSend(aIndex, 1, "--- Top 5 Players ---")
    local rank = 1

    while db:Fetch() do
        local name = db:GetAsString("Name")
        local resets = db:GetAsInteger("Reset")
        local mr = db:GetAsInteger("MasterReset")

        GCNoticeSend(aIndex, 1, "#" .. rank .. " " .. name .. " - MR:" .. mr .. " R:" .. resets)
        rank = rank + 1
    end

    db:Close()
end

Writing Data

local function SaveCustomData(playerName, eventScore)
    local db = GetConnection("GameDB")

    local query = string.format(
        "IF EXISTS (SELECT 1 FROM CustomEventScores WHERE Name = '%s') "..
        "UPDATE CustomEventScores SET Score = %d WHERE Name = '%s' "..
        "ELSE INSERT INTO CustomEventScores (Name, Score) VALUES ('%s', %d)",
        playerName, eventScore, playerName, playerName, eventScore
    )

    db:ExecQuery(query)
    db:Close()
end

SQL Injection

The examples above use string concatenation for simplicity. In production, use BindParameterAsString for user-provided input to prevent SQL injection.

Using Parameterized Queries

local function SafeGetPlayer(playerName)
    local db = GetConnection("GameDB")

    db:BindParameterAsString(1, playerName)
    db:ExecQuery("SELECT Reset FROM Character WHERE Name = ?")

    local resets = 0
    if db:Fetch() then
        resets = db:GetAsInteger("Reset")
    end

    db:Close()
    return resets
end

QueryManager Methods Reference

Method Description
Connect(dsn, user, pass) Open ODBC connection
ExecQuery(sql) Execute SQL query
Fetch() Get next result row (true/false)
Close() Close current query
GetAsInteger(col) Read integer column
GetAsFloat(col) Read float column
GetAsInteger64(col) Read 64-bit integer
GetAsString(col) Read string column
GetAsBinary(col) Read binary data
BindParameterAsString(n, val) Bind string parameter
BindParameterAsBinary(n, val) Bind binary parameter