### Set Global MySQL Plugin Options Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Configures global settings for the MySQL plugin, such as enabling duplicate connections to the same database. This example demonstrates allowing multiple connection handles to the same database. ```pawn public OnGameModeInit() { // Allow two separate handles to the same database mysql_global_options(DUPLICATE_CONNECTIONS, true); new MySQL:conn1 = mysql_connect("127.0.0.1", "root", "pass", "db"); new MySQL:conn2 = mysql_connect("127.0.0.1", "root", "pass", "db"); printf("conn1 == conn2: %s", (conn1 == conn2) ? "yes" : "no"); // Output: "conn1 == conn2: no" return 1; } ``` -------------------------------- ### Set Global MySQL Options Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Configures global settings for the MySQL plugin. Use DUPLICATE_CONNECTIONS to allow multiple connections to the same database, which is useful for testing or specific configurations. This example demonstrates enabling duplicate connections and then establishing two connections. ```pawn public OnGameModeInit() { mysql_global_options(DUPLICATE_CONNECTIONS, true); //allows the use of dupl. connections new MySQL:g_Sql1 = mysql_connect("127.0.0.1", "root", "mypass", "mydatabase"); new MySQL:g_Sql2 = mysql_connect("127.0.0.1", "root", "mypass", "mydatabase"); printf("connection 1 and connection 2 are %s.", g_Sql1 == g_Sql2 ? "the same" : "not the same"); //output: "connection 1 and connection 2 are the same." return 1; } ``` -------------------------------- ### Get Query Execution Time and String Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Use `cache_get_query_exec_time` to measure query duration in milliseconds or microseconds. `cache_get_query_string` retrieves the original SQL query that was executed. ```pawn forward OnHeavyQueryDone(); public OnHeavyQueryDone() { new Float:ms = float(cache_get_query_exec_time(UNIT_MILLISECONDS)); new us = cache_get_query_exec_time(UNIT_MICROSECONDS); new qstr[256]; cache_get_query_string(qstr); printf("[PERF] Query took %.1f ms (%d µs): %s", ms, us, qstr); // Output: [PERF] Query took 12.0 ms (12048 µs): SELECT * FROM `large_table` return 1; } ``` -------------------------------- ### Get MySQL Server Status Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the current status of the MySQL server. The destination buffer must be large enough to hold the status string. ```pawn new stats[150]; mysql_stat(stats); print(stats); //Output would be something like: // Uptime: 380 Threads: 1 Questions: 3 Slow queries: 0 Opens: 12 Flush tables: 1 // Open tables: 6 Queries per second avg: 0.008 ``` -------------------------------- ### Set MySQL Connection Option Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Modifies a specific option for a given MySQL connection options instance. This example disables auto-reconnect and connection pooling for a new connection. ```pawn new MySQLOpt:options = mysql_init_options(); mysql_set_option(options, AUTO_RECONNECT, false); //disable auto-reconnect mysql_set_option(options, POOL_SIZE, 0); //disable connection pool (and thus mysql_pquery) g_Sql = mysql_connect("127.0.0.1", "root", "mypass", "mydatabase", options); ``` -------------------------------- ### Get Query Execution Time with cache_get_query_exec_time Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the execution time of the last query. It accepts an optional time unit parameter (defaulting to microseconds) and returns -1 on error. Be cautious of buffer overflows when using microseconds with long queries. ```pawn mysql_tquery(MySQL, "SELECT * FROM `data`", "OnDataRetrieved"); // ... public OnDataRetrieved() { printf("The query \"SELECT * FROM `data`\" took %d milliseconds / %d microseconds to execute.", cache_get_query_exec_time(UNIT_MILLISECONDS), cache_get_query_exec_time(UNIT_MICROSECONDS)); //output: // The query "SELECT * FROM `data`" took 9 milliseconds / 9311 microseconds to execute. return 1; } ``` -------------------------------- ### Initialize Connection Options and Connect Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Initializes connection options, sets pool size and auto-reconnect, then establishes a connection to the MySQL server. Handles connection errors by shutting down the server. ```pawn #include #define MYSQL_HOST "127.0.0.1" #define MYSQL_USER "root" #define MYSQL_PASSWORD "secret" #define MYSQL_DATABASE "gameserver" new MySQL:g_SQL; public OnGameModeInit() { new MySQLOpt:opts = mysql_init_options(); mysql_set_option(opts, AUTO_RECONNECT, true); // reconnect on connection loss mysql_set_option(opts, POOL_SIZE, 4); // 4 parallel connections for mysql_pquery g_SQL = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, opts); if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0) { print("[DB] Connection failed. Shutting down."); SendRconCommand("exit"); return 1; } print("[DB] Connected successfully."); return 1; } ``` -------------------------------- ### Get Cache Field Count Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the number of fields from the active cache. Use this only if a cache is active. ```pawn new field_count; if(!cache_get_field_count(field_count)) printf("couldn't retrieve field count"); else printf("There are %d fields in the current result set.", field_count); ``` -------------------------------- ### Initialize MySQL Connection and Create Player Table Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Sets up the MySQL connection with auto-reconnect enabled and creates the 'players' table if it doesn't exist. Ensure your database credentials and name are correctly defined. ```pawn #include #include #define MYSQL_HOST "127.0.0.1" #define MYSQL_USER "root" #define MYSQL_PASSWORD "pass" #define MYSQL_DATABASE "samp" new MySQL:g_SQL; enum E_PLAYER { ID, Name[MAX_PLAYER_NAME], Password[65], Salt[17], Kills, Deaths, Cache:CacheID, bool:LoggedIn }; new Player[MAX_PLAYERS][E_PLAYER]; public OnGameModeInit() { new MySQLOpt:o = mysql_init_options(); mysql_set_option(o, AUTO_RECONNECT, true); g_SQL = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, o); if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0) { print("DB connect failed."); SendRconCommand("exit"); return 1; } mysql_tquery(g_SQL, "CREATE TABLE IF NOT EXISTS `players` (" "`id` INT AUTO_INCREMENT PRIMARY KEY," "`username` VARCHAR(24) UNIQUE NOT NULL," "`password` CHAR(64) NOT NULL," "`salt` CHAR(16) NOT NULL," "`kills` MEDIUMINT DEFAULT 0," "`deaths` MEDIUMINT DEFAULT 0)"); return 1; } ``` -------------------------------- ### Get Cache Row Count Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the number of rows from the active cache. Use this only if a cache is active. ```pawn new row_count; if(!cache_get_row_count(row_count)) printf("couldn't retrieve row count"); else printf("There are %d rows in the current result set.", row_count); ``` -------------------------------- ### Get Cache Field Name Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the name of a field by its index from the active cache. Use this only if a cache is active. ```pawn new field_name[32]; cache_get_field_name(0, field_name); printf("The first field name in the current result set is '%s'.", field_name); ``` -------------------------------- ### Initialize MySQL Connection Options Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Creates a new instance for MySQL connection options with default values. This instance can then be modified using mysql_set_option. ```pawn new MySQLOpt:options = mysql_init_options(); ``` -------------------------------- ### Get Cache Field Type Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the data type of a field by its index from the active cache. Use this only if a cache is active. ```pawn new E_MYSQL_FIELD_TYPE:type = cache_get_field_type(0); if(type == MYSQL_TYPE_VAR_STRING) printf("The first field is of type VARCHAR."); ``` -------------------------------- ### Connect to MySQL Database Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Establishes a connection to a MySQL server. If no options are provided, default options are used. Returns a connection handle or MYSQL_INVALID_HANDLE on error. ```pawn new MySQL:g_Sql; // ... public OnGameModeInit() { g_Sql = mysql_connect("127.0.0.1", "root", "mypass", "mydatabase"); // ... return 1; } ``` -------------------------------- ### Get Unprocessed Queries Count Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Returns the number of queries currently being processed in a separate thread. Useful for monitoring asynchronous query execution. ```pawn printf("There are %d unprocessed queries.", mysql_unprocessed_queries()); ``` -------------------------------- ### Connect using INI file Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Connects to the MySQL database by reading credentials and options from a configuration file. The default file is 'mysql.ini', but a custom file can be specified. ```ini // mysql.ini (place in server root) hostname = 127.0.0.1 username = gameuser password = s3cur3pass database = samp_db auto_reconnect = true pool_size = 2 server_port = 3306 ``` ```pawn public OnGameModeInit() { new MySQL:g_SQL = mysql_connect_file(); // reads "mysql.ini" by default // or: mysql_connect_file("production.ini") if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0) { print("[DB] Failed to connect via config file."); SendRconCommand("exit"); return 1; } print("[DB] Connected via config file."); return 1; } ``` -------------------------------- ### Connect to MySQL Using Configuration File Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Connects to a MySQL server using credentials and options specified in a configuration file (defaulting to 'mysql.ini'). The file must be in the SA-MP server root folder. Returns a connection handle or MYSQL_INVALID_HANDLE on error. ```c hostname = 127.0.0.1 ; this is a comment username = tester # this is also a comment password = 1234 database = test # auto_reconnect = false multi_statements = true # pool_size = 3 ; server_port = 3306 ``` ```pawn new MySQL:g_Sql; // ... public OnGameModeInit() { g_Sql = mysql_connect_file(); // ... return 1; } ``` -------------------------------- ### Handle Login and Registration Dialog Responses Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Processes user input from login and registration dialogs. For login, it hashes the entered password with the stored salt and compares it. For registration, it generates a new salt, hashes the password, and inserts the new record into the database. ```pawn forward OnPlayerRegister(playerid); public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { if (dialogid == 1 && response) // login { new hashed[65]; SHA256_PassHash(inputtext, Player[playerid][Salt], hashed, 65); if (!strcmp(hashed, Player[playerid][Password])) { cache_set_active(Player[playerid][CacheID]); cache_get_value_name_int(0, "id", Player[playerid][ID]); cache_get_value_name_int(0, "kills", Player[playerid][Kills]); cache_get_value_name_int(0, "deaths", Player[playerid][Deaths]); cache_unset_active(); cache_delete(Player[playerid][CacheID]); Player[playerid][LoggedIn] = true; SpawnPlayer(playerid); } else Kick(playerid); } else if (dialogid == 2 && response) // register { for (new i = 0; i < 16; i++) Player[playerid][Salt][i] = random(94) + 33; SHA256_PassHash(inputtext, Player[playerid][Salt], Player[playerid][Password], 65); new q[220]; mysql_format(g_SQL, q, sizeof q, "INSERT INTO `players` (`username`,`password`,`salt`) VALUES ('%e','%s','%e')", Player[playerid][Name], Player[playerid][Password], Player[playerid][Salt]); mysql_tquery(g_SQL, q, "OnPlayerRegister", "d", playerid); } return 1; } public OnPlayerRegister(playerid) { Player[playerid][ID] = cache_insert_id(); Player[playerid][LoggedIn] = true; SpawnPlayer(playerid); return 1; } ``` -------------------------------- ### Retrieve Insert ID with cache_insert_id Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Use this function after an INSERT query to get the ID of the newly created AUTO_INCREMENT row. It takes no parameters and returns -1 on error. ```pawn mysql_tquery(MySQL, "INSERT INTO `players` (`name`, `password`) VALUES ('Ownage', MD5('mypass'))", "OnPlayerRegister", "d", playerid); // ... public OnPlayerRegister(playerid) { printf("New player registered with ID '%d'.", cache_insert_id()); return 1; } ``` -------------------------------- ### Execute Queries from SQL File - mysql_tquery_file Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Execute SQL statements from a file located in the `scriptfiles/` directory using `mysql_tquery_file`. This is useful for applying schema changes or running batch SQL scripts. ```sql // scriptfiles/schema.sql // CREATE TABLE IF NOT EXISTS `players` ( // `id` int(11) NOT NULL AUTO_INCREMENT, // `username` varchar(24) NOT NULL, // PRIMARY KEY (`id`) // ); // CREATE TABLE IF NOT EXISTS `logs` ( // `id` int(11) NOT NULL AUTO_INCREMENT, // `message` text NOT NULL, // `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, // PRIMARY KEY (`id`) // ); ``` ```pawn forward OnSchemaReady(); public OnGameModeInit() { mysql_tquery_file(g_SQL, "schema.sql", "OnSchemaReady"); return 1; } public OnSchemaReady() { print("[DB] Schema applied successfully."); LoadHouses(); LoadVehicles(); return 1; } ``` -------------------------------- ### mysql_connect_file Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Connects to a MySQL server and database using a configuration file. ```APIDOC ## mysql_connect_file ### Description Connects to a MySQL server and database using a INI-like file where all connection credentials and options are specified. ### Parameters - **file_name** (const file_name[] = "mysql.ini") - Optional - Name for the connection file. The file must be in the SA-MP server root folder. ### Return Values Connection handle or MYSQL_INVALID_HANDLE on error. ### Available Fields in Connection File | Field | Type | Description | |---|---|---| | hostname | string | The IP/hostname. | | username | string | The name of the user. | | password | string | The password of the user. | | database | string | The database to use. | | auto_reconnect | boolean (optional, true by default) | Whether automatically reconnect to the server on connection loss or not. | | multi_statements | boolean (optional, false by default) | Allow/Disallow executing multiple SQL statements in one query. | | pool_size | unsigned integer (optional, 2 by default) | Size of connection pool for [mysql_pquery](#mysql_pquery). | | server_port | unsigned integer (optional, 3306 by default) | Server port. | | ssl_enable | boolean (optional, false by default) | Enable/disable SSL. | | ssl_key_file | string (optional) | Path to key file. | | ssl_cert_file | string (optional) | Path to certificate file. | | ssl_ca_file | string (optional) | Path to certificate authority file. | | ssl_ca_path | string (optional) | Path name to a directory that contains trusted SSL CA certificates in PEM format. | | ssl_cipher | string (optional) | List of permissible ciphers to use for SSL encryption. | ### Example Connection File ```c hostname = 127.0.0.1 ; this is a comment username = tester # this is also a comment password = 1234 database = test # auto_reconnect = false multi_statements = true # pool_size = 3 ; server_port = 3306 ``` ### Example Usage ```pawn new MySQL:g_Sql; // ... public OnGameModeInit() { g_Sql = mysql_connect_file(); // ... return 1; } ``` ``` -------------------------------- ### Get ORM Error Number - Pawn Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the error ID from the last ORM operation. This is useful for debugging and handling specific error conditions after an ORM call. ```pawn orm_select(Player[playerid][ORM_ID], "OnStuffSelected", "d", playerid); public OnStuffSelected(playerid) { switch(orm_errno(Player[playerid][ORM_ID])) { case ERROR_INVALID: printf("Invalid ORM id."); break; case ERROR_OK: printf("There is no error."); break; case ERROR_NO_DATA: printf("No data in the table found."); break; } return 1; } ``` -------------------------------- ### Get Row Count with cache_num_rows / cache_get_row_count Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Retrieve the number of rows in the active result set. This is typically used after executing a query to determine how many records were returned. ```pawn forward OnVehiclesLoaded(); public OnGameModeInit() { mysql_tquery(g_SQL, "SELECT `id`,`model`,`pos_x`,`pos_y`,`pos_z` FROM `vehicles`", "OnVehiclesLoaded"); return 1; } public OnVehiclesLoaded() { new rows; cache_get_row_count(rows); // or: rows = cache_num_rows(); printf("[DB] Loading %d vehicles from database.", rows); for (new i = 0; i < rows; i++) { new id, model; new Float:x, Float:y, Float:z; cache_get_value_name_int(i, "id", id); cache_get_value_name_int(i, "model", model); cache_get_value_name_float(i, "pos_x", x); cache_get_value_name_float(i, "pos_y", y); cache_get_value_name_float(i, "pos_z", z); CreateVehicle(model, x, y, z, 0.0, -1, -1, -1); } return 1; } ``` -------------------------------- ### ORM Instance Lifecycle Management Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Create and destroy ORM instances using `orm_create` and `orm_destroy`. `orm_create` binds an instance to a specific table and optionally a connection handle. Ensure `orm_save` is called before destroying to persist changes. ```pawn public OnPlayerConnect(playerid) { // Create ORM bound to "players" table Player[playerid][ORM_ID] = orm_create("players", g_SQL); return 1; } public OnPlayerDisconnect(playerid, reason) { orm_save(Player[playerid][ORM_ID]); // flush to DB first orm_destroy(Player[playerid][ORM_ID]); // free memory return 1; } ``` -------------------------------- ### mysql_init_options Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Creates a MySQLOpt handle for configuring connection options before establishing a connection. Options include AUTO_RECONNECT, POOL_SIZE, MULTI_STATEMENTS, SERVER_PORT, and SSL settings. ```APIDOC ## mysql_init_options — Create a connection options instance ### Description Creates a `MySQLOpt` handle that can be configured before opening a connection. Options include `AUTO_RECONNECT`, `POOL_SIZE`, `MULTI_STATEMENTS`, `SERVER_PORT`, and SSL settings. ### Usage ```pawn new MySQLOpt:opts = mysql_init_options(); mysql_set_option(opts, AUTO_RECONNECT, true); mysql_set_option(opts, POOL_SIZE, 4); ``` ``` -------------------------------- ### Player Login System with ORM API Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt This snippet demonstrates a player login and registration system using the ORM layer for automatic query generation. It handles player data loading, password hashing, and saving player information. ```pawn #include #include new MySQL:g_SQL; enum E_PLAYER { ORM:ORM_ID, ID, Name[MAX_PLAYER_NAME], Password[65], Salt[17], Kills, Deaths, Float:PX, Float:PY, Float:PZ, Float:PA, Interior, bool:LoggedIn }; new Player[MAX_PLAYERS][E_PLAYER]; public OnPlayerConnect(playerid) { GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME); new ORM:ormid = Player[playerid][ORM_ID] = orm_create("players", g_SQL); orm_addvar_int( ormid, Player[playerid][ID], "id"); orm_addvar_string(ormid, Player[playerid][Name], MAX_PLAYER_NAME, "username"); orm_addvar_string(ormid, Player[playerid][Password], 65, "password"); orm_addvar_string(ormid, Player[playerid][Salt], 17, "salt"); orm_addvar_int( ormid, Player[playerid][Kills], "kills"); orm_addvar_int( ormid, Player[playerid][Deaths], "deaths"); orm_addvar_float( ormid, Player[playerid][PX], "x"); orm_addvar_float( ormid, Player[playerid][PY], "y"); orm_addvar_float( ormid, Player[playerid][PZ], "z"); orm_setkey(ormid, "username"); // → SELECT * FROM `players` WHERE `username` = '' orm_load(ormid, "OnPlayerDataLoaded", "d", playerid); return 1; } forward OnPlayerDataLoaded(playerid); public OnPlayerDataLoaded(playerid) { orm_setkey(Player[playerid][ORM_ID], "id"); // switch key to id for future UPDATE switch (orm_errno(Player[playerid][ORM_ID])) { case ERROR_OK: ShowPlayerDialog(playerid, 1, DIALOG_STYLE_PASSWORD, "Login", "Enter password:", "Login", "Quit"); case ERROR_NO_DATA: ShowPlayerDialog(playerid, 2, DIALOG_STYLE_PASSWORD, "Register", "Choose a password:", "Register", "Quit"); } return 1; } forward OnPlayerRegister(playerid); public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { if (dialogid == 1 && response) // login { new hashed[65]; SHA256_PassHash(inputtext, Player[playerid][Salt], hashed, 65); if (!strcmp(hashed, Player[playerid][Password])) { Player[playerid][LoggedIn] = true; SpawnPlayer(playerid); } else Kick(playerid); } else if (dialogid == 2 && response) // register { for (new i = 0; i < 16; i++) Player[playerid][Salt][i] = random(94) + 33; SHA256_PassHash(inputtext, Player[playerid][Salt], Player[playerid][Password], 65); // INSERT — id is 0, so orm_save fires INSERT and fills ID via cache_insert_id() orm_save(Player[playerid][ORM_ID], "OnPlayerRegister", "d", playerid); } return 1; } public OnPlayerRegister(playerid) { Player[playerid][LoggedIn] = true; SpawnPlayer(playerid); return 1; } public OnPlayerDisconnect(playerid, reason) { if (Player[playerid][LoggedIn]) { if (reason == 1) // normal quit { GetPlayerPos(playerid, Player[playerid][PX], Player[playerid][PY], Player[playerid][PZ]); GetPlayerFacingAngle(playerid, Player[playerid][PA]); } Player[playerid][Interior] = GetPlayerInterior(playerid); // UPDATE `players` SET `kills`=.., `x`=.., ... WHERE `id`= orm_save(Player[playerid][ORM_ID]); } orm_destroy(Player[playerid][ORM_ID]); return 1; } ``` -------------------------------- ### Get Warning Count with cache_warning_count Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Returns the number of warnings generated by the last executed query. This can be useful for diagnosing issues with queries that execute but produce unexpected results or warnings. ```pawn mysql_tquery(MySQL, "DROP TABLE IF EXISTS `nope`", "OnStuffHappened"); // ... public OnStuffUpdated() { if(cache_warning_count()) printf("table 'nope' doesn't exist."); return 1; } ``` -------------------------------- ### Execute Threaded Queries from File Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Use this native to read and execute all queries from a specified file in a threaded manner. Ensure the file is within the scriptfiles directory and all queries end with a semicolon. Callbacks must be public functions. ```pawn public OnGameModeInit() { mysql_tquery_file(db_handle, "my_tables.sql", OnDatabaseTablesChecked); return 1; } forward OnDatabaseTablesChecked(); public OnDatabaseTablesChecked() { LoadHouses(); LoadVehicles(); return 1; } ``` -------------------------------- ### Get Current MySQL Character Set Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home This function retrieves the current character set being used by the MySQL connection. It requires a destination buffer, its maximum size, and an optional connection handle. ```pawn new charset[20]; mysql_get_charset(charset); ``` -------------------------------- ### Retrieve MySQL Error Message Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Use this function to get the error message of the last unthreaded MySQL command. It requires a destination buffer, its maximum size, and optionally a connection handle. ```pawn new MySQL: handle, errno; handle = mysql_connect("127.0.0.1", "root", "mypass", "mydatabase"); errno = mysql_errno(handle); if (errno != 0) { new error[100]; mysql_error(error, sizeof (error), handle); printf("[ERROR] #%d '%s'", errno, error); ``` -------------------------------- ### mysql_init_options Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Creates a MySQL connection options instance with default values. This instance can then be modified using `mysql_set_option` before being passed to `mysql_connect`. ```APIDOC ## mysql_init_options ### Description Creates a MySQL connection options instance with default values. ### Parameters This function has no parameters. ### Return Values - MySQL connection options id. ``` -------------------------------- ### Get Cache Value by Index Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves a specific value from the active cache result set as a string, using row and column indices. Use this only if a cache is active. Ensure the destination buffer is adequately sized. ```pawn new dest[128]; cache_get_value_index(0, 0, dest); printf("The very first value in the current result set is '%s'.", dest); ``` -------------------------------- ### Get Previous MySQL Operation Error Code Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the error code from the last MySQL operation. Returns 0 if no error occurred, or -1 otherwise. This native is relevant after operations like mysql_connect, mysql_query, and mysql_escape_string. ```pawn mysql_connect("127.0.0.1", "root", "mypass", "mydatabase"); if(mysql_errno() != 0) print("Could not connect to database!"); ``` -------------------------------- ### mysql_connect Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Connects to a MySQL server and database. ```APIDOC ## mysql_connect ### Description Connects to a MySQL server and database. ### Parameters - **host** (const host[]) - Required - IP or hostname of the MySQL server. - **user** (const user[]) - Required - Username of the account you want to connect to. - **password** (const password[]) - Required - Password of the account you want to connect to. - **database** (const database[]) - Required - Name of the database you want to connect to. - **option_id** (MySQLOpt:option_id) - Optional - MySQL connection options instance, see [mysql_init_options](#mysql_init_options) and [mysql_set_option](#mysql_set_option). ### Return Values Connection handle or MYSQL_INVALID_HANDLE on error. ### Notes If no option id is specified, the default options will be used. ### Example ```pawn new MySQL:g_Sql; // ... public OnGameModeInit() { g_Sql = mysql_connect("127.0.0.1", "root", "mypass", "mydatabase"); // ... return 1; } ``` ``` -------------------------------- ### Get DML Operation Metadata Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Retrieve metadata after INSERT, UPDATE, or DELETE operations. `cache_affected_rows` returns the number of rows modified, `cache_insert_id` provides the ID of the last inserted row, and `cache_warning_count` indicates any warnings generated. ```pawn forward OnPlayerRegistered(playerid); public OnPlayerRegistered(playerid) { new newid = cache_insert_id(); // new AUTO_INCREMENT id new affected = cache_affected_rows(); // should be 1 new warnings = cache_warning_count(); printf("[DB] Registered player %d with db id=%d (affected=%d, warnings=%d)", playerid, newid, affected, warnings); Player[playerid][ID] = newid; Player[playerid][IsLoggedIn] = true; SpawnPlayer(playerid); return 1; } ``` -------------------------------- ### Load Player Data on Connect Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Fetches player data from the 'players' table upon connection. If the player exists, their data is loaded into the cache; otherwise, the registration dialog is shown. ```pawn forward OnPlayerDataLoaded(playerid); public OnPlayerConnect(playerid) { GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME); new q[128]; mysql_format(g_SQL, q, sizeof q, "SELECT * FROM `players` WHERE `username`='%e' LIMIT 1", Player[playerid][Name]); mysql_tquery(g_SQL, q, "OnPlayerDataLoaded", "d", playerid); return 1; } public OnPlayerDataLoaded(playerid) { if (cache_num_rows() > 0) { cache_get_value_name(0, "password", Player[playerid][Password], 65); cache_get_value_name(0, "salt", Player[playerid][Salt], 17); Player[playerid][CacheID] = cache_save(); // save full row for later ShowPlayerDialog(playerid, 1, DIALOG_STYLE_PASSWORD, "Login", "Enter your password:", "Login", "Quit"); } else { ShowPlayerDialog(playerid, 2, DIALOG_STYLE_PASSWORD, "Register", "Choose a password:", "Register", "Quit"); } return 1; } ``` -------------------------------- ### Execute MySQL Query Asynchronously with Callback (pawn) Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Use mysql_tquery to send a query that executes in a separate thread. A callback function can be specified to run upon completion. This native is suitable when query order is important or when transactions are needed. ```pawn enum E_PLAYER { Id, Name[MAX_PLAYER_NAME], Stuff }; new Players[MAX_PLAYERS][E_PLAYER] forward OnPlayerDataLoaded(playerid); public OnPlayerConnect(playerid) { new query[128], pname[MAX_PLAYER_NAME]; GetPlayerName(playerid, pname, sizeof(pname)); mysql_format(MySQL, query, sizeof(query), "SELECT * FROM `players` WHERE `Name` LIKE '%e'", pname); mysql_tquery(MySQL, query, "OnPlayerDataLoaded", "r", Players[playerid]); return 1; } public OnPlayerDataLoaded(player[E_PLAYER]) { //Query processed, you can now execute cache functions (like cache_get_value_index) here. printf("There are %d players with the name %s.", cache_num_rows(), player[Name]); return 1; } } public OnPlayerDataLoaded(playerid, array[], array_size) { //Query processed, you can now execute cache functions (like cache_get_value_index) here. printf("There are %d players with the same name.", cache_num_rows()); return 1; } ``` -------------------------------- ### Get Affected Rows with cache_affected_rows Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Retrieves the number of rows affected by the last INSERT, UPDATE, REPLACE, or DELETE query. Note that for DELETE queries without a WHERE clause, this function may return zero even if all records were deleted. ```pawn mysql_tquery(MySQL, "DELETE FROM mylogs WHERE log_id > 10", "OnLogsDeleted"); // ... public OnLogsDeleted() { printf("%d logs deleted!", cache_affected_rows()); return 1; } ``` -------------------------------- ### Read Connection Errors with mysql_errno and mysql_error Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Retrieve the numeric error code or descriptive message of the last unthreaded MySQL operation on a handle. Check the error code to determine if an error occurred and use mysql_error to get the message. ```pawn new MySQL:handle = mysql_connect("127.0.0.1", "root", "wrongpass", "db"); new errcode = mysql_errno(handle); if (errcode != 0) { new errmsg[256]; mysql_error(errmsg, sizeof(errmsg), handle); printf("[DB] Connection error #%d: %s", errcode, errmsg); // Output: [DB] Connection error #1045: Access denied for user 'root'@'localhost' } ``` -------------------------------- ### Minimal MySQL Connection Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Establishes a basic MySQL connection. It's crucial to check for an invalid handle and error codes to ensure the connection was successful. ```pawn // Minimal connection without custom options new MySQL:g_SQL = mysql_connect("127.0.0.1", "root", "pass", "mydb"); if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0) { new err[128]; mysql_error(err, sizeof(err), g_SQL); printf("[DB] Error %d: %s", mysql_errno(g_SQL), err); SendRconCommand("exit"); } ``` -------------------------------- ### Create ORM Instance - Pawn Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Creates an ORM instance for a specified table. Use this when you need to manage database operations for a particular table using the ORM. ```pawn public OnPlayerConnect(playerid) { new ORM:orm = Player[playerid][ORM_ID] = orm_create("players"); return 1; } ``` -------------------------------- ### Execute MySQL Query Asynchronously with Callback (pawn) Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Use mysql_pquery to send a query that executes in a separate thread. A callback function can be specified to run upon completion. Queries sent with this native may execute out of order and do not support transactions. ```pawn forward OnPlayerDataLoaded(playerid); public OnPlayerConnect(playerid) { new query[128], pname[MAX_PLAYER_NAME]; new array[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; GetPlayerName(playerid, pname, MAX_PLAYER_NAME); mysql_format(MySQL, query, sizeof(query), "SELECT * FROM `players` WHERE `name` LIKE '%e'", pname); mysql_pquery(MySQL, query, "OnPlayerDataLoaded", "dad", playerid, array, sizeof array); return 1; } public OnPlayerDataLoaded(playerid, array[], array_size) { //Query processed, you can now execute cache functions (like cache_get_value_index) here. printf("There are %d players with the same name.", cache_num_rows()); return 1; } ``` -------------------------------- ### mysql_connect_file Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Connects to a MySQL database using credentials and options read from an INI file. The default file is 'mysql.ini', but a custom file path can be provided. ```APIDOC ## mysql_connect_file — Connect using an INI file ### Description Reads all connection credentials and options from a `.ini`-style file located in the SA:MP server root directory. ### Usage ```pawn new MySQL:g_SQL = mysql_connect_file(); // reads "mysql.ini" by default // or: mysql_connect_file("production.ini") if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0) { print("[DB] Failed to connect via config file."); SendRconCommand("exit"); return 1; } print("[DB] Connected via config file."); ``` ``` -------------------------------- ### Execute Non-Threaded Queries from File Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Reads and executes all queries from a specified file in a non-threaded manner. Use this only if you understand the implications of blocking the main server thread. Ensure the file is in scriptfiles and queries are semicolon-terminated. ```pawn mysql_query_file(g_Sql, "players.sql"); ``` -------------------------------- ### mysql_connect Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Opens a database connection to a MySQL server and returns a MySQL handle. It's crucial to check the handle for validity and use mysql_errno to ensure a successful connection. ```APIDOC ## mysql_connect — Open a database connection ### Description Connects to a MySQL server and returns a `MySQL` handle. Pass `MYSQL_INVALID_HANDLE` check and `mysql_errno` check together to validate a successful connection. ### Usage ```pawn new MySQL:g_SQL = mysql_connect("127.0.0.1", "root", "pass", "mydb"); if (g_SQL == MYSQL_INVALID_HANDLE || mysql_errno(g_SQL) != 0) { new err[128]; mysql_error(err, sizeof(err), g_SQL); printf("[DB] Error %d: %s", mysql_errno(g_SQL), err); SendRconCommand("exit"); } ``` ``` -------------------------------- ### Select Data with ORM Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Sends a SELECT query and applies retrieved data to registered variables. Specify a callback for post-query operations. ```pawn orm_select(Player[playerid][ORM_ID], "OnPlayerDataLoaded", "d", playerid); public OnPlayerDataLoaded(playerid) { printf("Player %s has %d Money and is on PosX with %f.", Player[playerid][Name], Player[playerid][Money], Player[playerid][PosX]); return 1; } ``` -------------------------------- ### Load Data with `orm_load` Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Sends a `SELECT * FROM WHERE = ` query and populates registered variables. Handles cases where data exists or is missing. Alias: `orm_load` == `orm_select`. ```pawn forward OnPlayerDataLoaded(playerid); public OnPlayerConnect(playerid) { // ... (orm_create + orm_addvar_* + orm_setkey as above) orm_load(Player[playerid][ORM_ID], "OnPlayerDataLoaded", "d", playerid); return 1; } public OnPlayerDataLoaded(playerid) { switch (orm_errno(Player[playerid][ORM_ID])) { case ERROR_OK: { // Variables already populated — show login dialog printf("Welcome back %s (kills: %d)", Player[playerid][Name], Player[playerid][Kills]); ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", "Enter password:", "OK", "Quit"); } case ERROR_NO_DATA: { // Player not registered — show registration dialog ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Register", "Choose a password:", "OK", "Quit"); } } return 1; } ``` -------------------------------- ### mysql_tquery_file Source: https://github.com/pblueg/sa-mp-mysql/wiki/Home Reads all queries from a specified file and executes them in a threaded manner. Supports optional callback and format specifiers. ```APIDOC ## mysql_tquery_file ### Description This native reads all queries from the specified file and executes them in a threaded manner. ### Parameters - `MySQL:handle` - The connection handle this will be processed on. - `const file_path[]` - The file to read the queries from. - `const callback[]` - The query you want to process (optional). - `const format[]` - The format specifier string (optional). - `{Float,_}:...` - Indefinite number of arguments (optional). ### Return Values 1 if the query was successfully queued for execution, 0 otherwise. ### Notes - Only files inside the scriptfiles directory are considered. - The file path has to be absolute (relative to the scriptfiles directory). - All queries have to end with a semicolon. - Comments (starting with # or -- ) are ignored (except C-style comments). - Queries can be written over multiple lines. - The callback must be a public function. ### Example ```pawn public OnGameModeInit() { mysql_tquery_file(db_handle, "my_tables.sql", OnDatabaseTablesChecked); return 1; } forward OnDatabaseTablesChecked(); public OnDatabaseTablesChecked() { LoadHouses(); LoadVehicles(); return 1; } ``` ``` -------------------------------- ### mysql_tquery_file / mysql_query_file Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Reads and executes SQL statements from a file located in the `scriptfiles/` directory. Useful for schema creation. ```APIDOC ## mysql_tquery_file / mysql_query_file ### Description Reads and executes all SQL statements (separated by `;`) from a file inside the `scriptfiles/` directory. Useful for schema creation scripts. ### Method `mysql_tquery_file(connection, filename, callback_name, format, ...)` or `mysql_query_file(connection, filename)` ### Parameters - **connection**: The MySQL connection handle. - **filename**: The name of the SQL file in the `scriptfiles/` directory. - **callback_name**: (For `mysql_tquery_file`) The name of the public PAWN callback to invoke upon completion. - **format**: (For `mysql_tquery_file`) A format string for arguments passed to the callback. - **...**: (For `mysql_tquery_file`) Arguments to be passed to the callback. ### Request Example ```pawn // scriptfiles/schema.sql // CREATE TABLE IF NOT EXISTS `players` ( // `id` int(11) NOT NULL AUTO_INCREMENT, // `username` varchar(24) NOT NULL, // PRIMARY KEY (`id`) // ); // CREATE TABLE IF NOT EXISTS `logs` ( // `id` int(11) NOT NULL AUTO_INCREMENT, // `message` text NOT NULL, // `created_at` timestamp DEFAULT CURRENT_TIMESTAMP, // PRIMARY KEY (`id`) // ); forward OnSchemaReady(); public OnGameModeInit() { mysql_tquery_file(g_SQL, "schema.sql", "OnSchemaReady"); return 1; } public OnSchemaReady() { print("[DB] Schema applied successfully."); LoadHouses(); LoadVehicles(); return 1; } ``` ``` -------------------------------- ### Register PAWN Variables with Database Columns Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Links PAWN variables to their corresponding database columns for automatic ORM operations. Ensure the ORM is created with `orm_create` before adding variables. ```pawn public OnPlayerConnect(playerid) { new ORM:ormid = Player[playerid][ORM_ID] = orm_create("players", g_SQL); orm_addvar_int( ormid, Player[playerid][ID], "id"); orm_addvar_string(ormid, Player[playerid][Name], MAX_PLAYER_NAME, "username"); orm_addvar_string(ormid, Player[playerid][Password], 65, "password"); orm_addvar_string(ormid, Player[playerid][Salt], 17, "salt"); orm_addvar_int( ormid, Player[playerid][Kills], "kills"); orm_addvar_int( ormid, Player[playerid][Deaths], "deaths"); orm_addvar_float( ormid, Player[playerid][X_Pos], "pos_x"); orm_addvar_float( ormid, Player[playerid][Y_Pos], "pos_y"); orm_addvar_float( ormid, Player[playerid][Z_Pos], "pos_z"); orm_setkey(ormid, "id"); // primary key column GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME); orm_setkey(ormid, "username"); // use username for initial lookup orm_load(ormid, "OnPlayerDataLoaded", "d", playerid); return 1; } ``` -------------------------------- ### Execute Threaded Query with Callback - mysql_tquery Source: https://context7.com/pblueg/sa-mp-mysql/llms.txt Use `mysql_tquery` to send a query to a worker thread. A callback function is invoked when the result is ready. Queries are guaranteed to execute in order. ```pawn forward OnPlayerDataLoaded(playerid); public OnPlayerConnect(playerid) { new name[MAX_PLAYER_NAME], query[128]; GetPlayerName(playerid, name, sizeof(name)); mysql_format(g_SQL, query, sizeof(query), "SELECT `id`,`kills`,`deaths` FROM `players` WHERE `username` = '%e' LIMIT 1", name); mysql_tquery(g_SQL, query, "OnPlayerDataLoaded", "d", playerid); return 1; } public OnPlayerDataLoaded(playerid) { if (cache_num_rows() == 0) { printf("[DB] New player: %d", playerid); return 1; } new id, kills, deaths; cache_get_value_name_int(0, "id", id); cache_get_value_name_int(0, "kills", kills); cache_get_value_name_int(0, "deaths", deaths); printf("[DB] Player %d loaded — id=%d kills=%d deaths=%d", playerid, id, kills, deaths); return 1; } ```