sa-mp-mysql Plugin

repository·master·Indexed 42 days ago

https://github.com/pblueg/sa-mp-mysql

A MySQL plugin for San Andreas Multiplayer (SA:MP) that enables MySQL database functionality within the PAWN scripting language. It provides synchronous and asynchronous query execution via CConnection and CThreadedConnection, connection pooling with CConnectionPool, and an ORM system via COrmManager for mapping database columns to Pawn variables.

Tokens
5.5K
Snippets
17
Records
24
Agent score
52%

What's inside sa-mp-mysql

  1. Understand MySQL connection pooling behavior

    master
    When using mysql_connect, you may see multiple debug messages regarding connections even if you only call the function once. This is expected behavior. The plugin uses multiple direct database connections per connection handle. The total number of direct connections is calculated as 2 + pool_size.
  2. Install the MySQL Plugin for SA:MP

    master

    To install the plugin, follow these steps:

    1. Extract the contents of the downloaded archive into the root directory of your SA-MP server.
    2. Update your server.cfg file to include the plugin:
      • Windows: Add plugins mysql to the plugins line.
      • Linux: Add plugins mysql.so to the plugins line.
    ### Windows (server.cfg)
    plugins mysql
    
    ### Linux (server.cfg)
    plugins mysql.so
  3. Build the MySQL Plugin from source

    master

    The plugin must be compiled as a 32-bit library. All required libraries must be 32-bit and the compiler must support 32-bit builds.

    Windows Build Requirements

    1. A C++ compiler
    2. MySQL C Connector (version 6.1.6)
    3. Boost libraries (version 1.57 or higher)
    4. CMake

    Steps:

    1. Clone the repository.
    2. Create a build folder.
    3. Run CMake inside the build folder.
    4. Build the generated project files with your C++ compiler.

    Linux Build Requirements

    1. A C++ compiler
    2. MySQL client (version 5.5 or higher) via package manager
    3. Boost libraries (version 1.57 or higher)
    4. CMake

    Steps:

    1. Clone the repository.
    2. Create a build folder and run CMake: mkdir build && cd build && cmake ..
    3. Build the generated project files with your C++ compiler.
    # Linux build sequence
    mkdir build && cd build && cmake ..
  4. Troubleshoot Linux loading errors

    master

    If you encounter issues loading the plugin on Linux, check the following:

    • version GLIBCXX_3.4.15' not found: Your system's GCC version is too old. You need a distribution that provides GCC 4.8 or higher (e.g., upgrade from CentOS 6 to CentOS 7).
    • Failed (libmysqlclient_r.so.18: cannot open shared object file: No such file or directory): The MySQL client library is missing. Install the 32-bit version (i386, i686, etc.) via your package manager.
    • Failed (plugins/mysql.so: symbol __cxa_pure_virtual...): You are likely using a 64-bit libmysqlclient library. You must either install the 32-bit version of the MySQL client package or use the statically linked plugin file: mysql_static.so.
    • Missing libmysqlclient installation: If you cannot install the required library on your distribution, use the mysql_static.so plugin instead, as it is statically linked.
  5. Troubleshoot Windows loading errors

    master

    If the plugin fails to load on Windows, ensure you have the following x86/32-bit Microsoft C++ redistributables installed:

    • 2010
    • 2010 SP1
    • 2012
    • 2015

    If you are on an older version of Windows (not Windows 10) and the redistributables do not resolve the issue, download the universal Windows CRT and ensure the following requirements are met:

  6. Register callbacks for query execution results and errors

    master

    The CQuery class provides two primary methods for attaching callbacks to handle the outcome of a query execution:

    • OnExecutionFinished(function<void(ResultSet_t)> cb): Registers a callback that is triggered when the query execution completes successfully. The callback receives a ResultSet_t.
    • OnError(function<void(unsigned int, string)> cb): Registers a callback that is triggered if an error occurs during execution. The callback receives an unsigned int error ID and a string containing the error message.

    Note: These callbacks are intended to be called internally via CallCallback() and CallErrorCallback() during the query lifecycle.

  7. Configure MySQL connection options using COptions

    master

    The COptions class allows you to manage specific configuration settings for a MySQL connection. You can set and retrieve options using SetOption<T>(Type, T) and GetOption<T>(Type).

    Available COptions::Type options and their expected types/defaults:

    • AUTO_RECONNECT (bool, default: true)
    • MULTI_STATEMENTS (bool, default: false)
    • POOL_SIZE (unsigned int, default: 2)
    • SERVER_PORT (unsigned int, default: 3306)
    • SSL_ENABLE (bool, default: false)
    • SSL_KEY_FILE (string, default: nullptr)
    • SSL_CERT_FILE (string, default: nullptr)
    • SSL_CA_FILE (string, default: nullptr)
    • SSL_CA_PATH (string, default: nullptr)
    • SSL_CIPHER (string, default: nullptr)
    // Example of setting and getting options
    COptions* options = COptionManager::Get().GetOptionHandle(my_id);
    if (options) {
        options->SetOption(COptions::Type::POOL_SIZE, 5);
        unsigned int poolSize = options->GetOption<unsigned int>(COptions::Type::POOL_SIZE);
    }
  8. Set a primary key variable in COrm

    master

    The ORM requires a key variable to perform UPDATE, DELETE, or specific SELECT operations. Use SetKeyVariable with the name of the column that acts as the primary key.

    // Set 'id' as the primary key for this ORM instance
    CError<COrm> error = orm->SetKeyVariable("id");
  9. Create and execute a query using CQuery

    master

    To execute a SQL query, use the CQuery::Create(string query) factory function to generate a Query_t (a shared pointer to a CQuery instance). You can then call Execute(MYSQL *connection) on the instance to run the query against a specific MySQL connection.

    To handle the results or errors asynchronously, you can register callbacks using OnExecutionFinished (for successful results) and OnError (for error handling). After execution, the result set can be retrieved via GetResult().

    // Example of creating and executing a query
    auto query = CQuery::Create("SELECT * FROM users");
    
    query->OnExecutionFinished([](ResultSet_t result) {
        // Handle the successful result set
    });
    
    query->OnError([](unsigned int errorid, string error) {
        // Handle the error
    });
    
    bool success = query->Execute(mysql_connection);
  10. Apply database results to variables

    master

    Once a query has been executed, use ApplyResult or ApplyResultByName to map the data from a Result_t object back into the registered Pawn variables.

    // Apply results from a specific row index to the registered variables
    // rowidx defaults to 0
    orm->ApplyResult(result, row_index);
    
    // Alternatively, apply by name
    bool success = orm->ApplyResultByName(result, row_index);
  11. Use CConnectionPool for managing multiple threaded connections

    master

    The CConnectionPool class manages a collection of CThreadedConnection instances. It provides a high-level interface to queue queries across the pool, which is useful for distributing database load and increasing throughput in highly concurrent environments.

    // Example usage of CConnectionPool
    // Creates a pool of 5 connections
    CConnectionPool* pool = new CConnectionPool(5, "host", "user", "pass", "db", options);
    
    // Queue a query to the pool
    Query_t query = "INSERT INTO logs (event) VALUES ('login')";
    pool->Queue(query);
    
    // Check total unprocessed queries across the entire pool
    unsigned int totalPending = pool->GetUnprocessedQueryCount();
  12. Use CThreadedConnection for asynchronous query queuing

    master

    The CThreadedConnection class allows you to offload MySQL queries to a dedicated worker thread. This prevents the main SA:MP server thread from blocking while waiting for database responses. You can push queries into a lock-free queue using Queue(), and monitor the workload using GetUnprocessedQueryCount().

    // Example usage of CThreadedConnection
    CThreadedConnection* threadedConn = new CThreadedConnection("host", "user", "pass", "db", options);
    
    // Queue a query to be processed by the worker thread
    Query_t query = "UPDATE players SET score = 100 WHERE id = 1";
    if (threadedConn->Queue(query)) {
        // Query is successfully queued
    }
    
    // Check how many queries are still waiting in the queue
    unsigned int pending = threadedConn->GetUnprocessedQueryCount();