├── README.md ├── LICENSE ├── example.lua └── mysql.lua /README.md: -------------------------------------------------------------------------------- 1 | GLua-MySQL-Wrapper 2 | ================== 3 | 4 | A mysql wrapper for Garry's Mod supporting SQLite, MySQLOO and TMySQL4. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Alex Grist-Hucker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /example.lua: -------------------------------------------------------------------------------- 1 | include("mysql.lua"); 2 | 3 | mysql:Connect("localhost", "example", "password", "example", 3306); 4 | 5 | hook.Add("DatabaseConnected", "example.DatabaseConnected", function() 6 | 7 | --[[ Create the "example" table if it does not exist. --]] 8 | local queryObj = mysql:Create("example"); 9 | queryObj:Create("id", "INT NOT NULL AUTO_INCREMENT"); 10 | queryObj:Create("name", "VARCHAR(255) NOT NULL"); 11 | queryObj:Create("steam_id", "VARCHAR(25) NOT NULL"); 12 | queryObj:PrimaryKey("id"); 13 | queryObj:Execute(); 14 | 15 | end); 16 | 17 | hook.Add("PlayerInitialSpawn", "example.PlayerInitialSpawn", function(player) 18 | 19 | --[[ Select the player's database entry by their steam id. --]] 20 | local queryObj = mysql:Select("example"); 21 | queryObj:Where("steam_id", player:SteamID()); 22 | queryObj:Callback(function(result, status, lastID) 23 | if (type(result) == "table" and #result > 0) then 24 | 25 | --[[ Update the player's name in the database if it exists. --]] 26 | local updateObj = mysql:Update("example"); 27 | updateObj:Update("name", player:Name()); 28 | updateObj:Where("steam_id", player:SteamID()); 29 | updateObj:Execute(); 30 | 31 | else 32 | 33 | --[[ Insert the player's information into the example table. --]] 34 | local insertObj = mysql:Insert("example"); 35 | insertObj:Insert("name", player:Name()); 36 | insertObj:Insert("steam_id", player:SteamID()); 37 | insertObj:Callback(function(result, status, lastID) 38 | print(string.format("Added \"%\" to the example table", player:Name())); 39 | end); 40 | insertObj:Execute(); 41 | 42 | end; 43 | end); 44 | queryObj:Execute(); 45 | 46 | end); 47 | 48 | timer.Create("example.SaveData", 60, 0, function() 49 | for k, v in pairs(player.GetAll()) do 50 | 51 | --[[ Queue and update to the player's name in the database (would usually be for data saving). --]] 52 | local updateObj = mysql:Update("example"); 53 | updateObj:Update("name", v:Name()); 54 | updateObj:Where("steam_id", v:SteamID()); 55 | updateObj:Execute(true); 56 | --[[ Passing true to Execute will queue the query. ]]-- 57 | 58 | end; 59 | end); 60 | 61 | --[[ This will poll the database queue every second and process any queued queries. --]] 62 | timer.Create("example.Think", 1, 0, function() 63 | mysql:Think(); 64 | end); 65 | -------------------------------------------------------------------------------- /mysql.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | mysql - 1.0.3 3 | A simple MySQL wrapper for Garry's Mod. 4 | 5 | Alexander Grist-Hucker 6 | http://www.alexgrist.com 7 | --]] 8 | 9 | mysql = mysql or { 10 | module = "sqlite" 11 | } 12 | 13 | local QueueTable = {} 14 | local tostring = tostring 15 | local table = table 16 | 17 | --[[ 18 | Replacement tables 19 | --]] 20 | 21 | local Replacements = { 22 | sqlite = { 23 | Create = { 24 | {"UNSIGNED ", ""}, 25 | {"NOT NULL AUTO_INCREMENT", ""}, -- assuming primary key 26 | {"AUTO_INCREMENT", ""}, 27 | {"INT%(%d*%)", "INTEGER"}, 28 | {"INT ", "INTEGER"} 29 | } 30 | } 31 | } 32 | 33 | --[[ 34 | Phrases 35 | --]] 36 | 37 | local MODULE_NOT_EXIST = "[mysql] The %s module does not exist!\n" 38 | 39 | --[[ 40 | Begin Query Class. 41 | --]] 42 | 43 | local QUERY_CLASS = {} 44 | QUERY_CLASS.__index = QUERY_CLASS 45 | 46 | function QUERY_CLASS:New(tableName, queryType) 47 | local newObject = setmetatable({}, QUERY_CLASS) 48 | newObject.queryType = queryType 49 | newObject.tableName = tableName 50 | newObject.selectList = {} 51 | newObject.insertList = {} 52 | newObject.updateList = {} 53 | newObject.createList = {} 54 | newObject.whereList = {} 55 | newObject.orderByList = {} 56 | return newObject 57 | end 58 | 59 | function QUERY_CLASS:Escape(text) 60 | return mysql:Escape(tostring(text)) 61 | end 62 | 63 | function QUERY_CLASS:ForTable(tableName) 64 | self.tableName = tableName 65 | end 66 | 67 | function QUERY_CLASS:Where(key, value) 68 | self:WhereEqual(key, value) 69 | end 70 | 71 | function QUERY_CLASS:WhereEqual(key, value) 72 | self.whereList[#self.whereList + 1] = "`"..key.."` = '"..self:Escape(value).."'" 73 | end 74 | 75 | function QUERY_CLASS:WhereNotEqual(key, value) 76 | self.whereList[#self.whereList + 1] = "`"..key.."` != '"..self:Escape(value).."'" 77 | end 78 | 79 | function QUERY_CLASS:WhereLike(key, value, format) 80 | format = format or "%%%s%%" 81 | self.whereList[#self.whereList + 1] = "`"..key.."` LIKE '"..string.format(format, self:Escape(value)).."'" 82 | end 83 | 84 | function QUERY_CLASS:WhereNotLike(key, value, format) 85 | format = format or "%%%s%%" 86 | self.whereList[#self.whereList + 1] = "`"..key.."` NOT LIKE '"..string.format(format, self:Escape(value)).."'" 87 | end 88 | 89 | function QUERY_CLASS:WhereGT(key, value) 90 | self.whereList[#self.whereList + 1] = "`"..key.."` > '"..self:Escape(value).."'" 91 | end 92 | 93 | function QUERY_CLASS:WhereLT(key, value) 94 | self.whereList[#self.whereList + 1] = "`"..key.."` < '"..self:Escape(value).."'" 95 | end 96 | 97 | function QUERY_CLASS:WhereGTE(key, value) 98 | self.whereList[#self.whereList + 1] = "`"..key.."` >= '"..self:Escape(value).."'" 99 | end 100 | 101 | function QUERY_CLASS:WhereLTE(key, value) 102 | self.whereList[#self.whereList + 1] = "`"..key.."` <= '"..self:Escape(value).."'" 103 | end 104 | 105 | function QUERY_CLASS:WhereIn(key, value) 106 | value = istable(value) and value or {value} 107 | 108 | local values = "" 109 | local bFirst = true 110 | 111 | for k, v in pairs(value) do 112 | values = values .. (bFirst and "" or ", ") .. self:Escape(v) 113 | bFirst = false 114 | end 115 | 116 | self.whereList[#self.whereList + 1] = "`"..key.."` IN ("..values..")" 117 | end 118 | 119 | function QUERY_CLASS:OrderByDesc(key) 120 | self.orderByList[#self.orderByList + 1] = "`"..key.."` DESC" 121 | end 122 | 123 | function QUERY_CLASS:OrderByAsc(key) 124 | self.orderByList[#self.orderByList + 1] = "`"..key.."` ASC" 125 | end 126 | 127 | function QUERY_CLASS:Callback(queryCallback) 128 | self.callback = queryCallback 129 | end 130 | 131 | function QUERY_CLASS:Select(fieldName) 132 | self.selectList[#self.selectList + 1] = "`"..fieldName.."`" 133 | end 134 | 135 | function QUERY_CLASS:Insert(key, value) 136 | self.insertList[#self.insertList + 1] = {"`"..key.."`", "'"..self:Escape(value).."'"} 137 | end 138 | 139 | function QUERY_CLASS:Update(key, value) 140 | self.updateList[#self.updateList + 1] = {"`"..key.."`", "'"..self:Escape(value).."'"} 141 | end 142 | 143 | function QUERY_CLASS:Create(key, value) 144 | self.createList[#self.createList + 1] = {"`"..key.."`", value} 145 | end 146 | 147 | function QUERY_CLASS:Add(key, value) 148 | self.add = {"`"..key.."`", value} 149 | end 150 | 151 | function QUERY_CLASS:Drop(key) 152 | self.drop = "`"..key.."`" 153 | end 154 | 155 | function QUERY_CLASS:PrimaryKey(key) 156 | self.primaryKey = "`"..key.."`" 157 | end 158 | 159 | function QUERY_CLASS:Limit(value) 160 | self.limit = value 161 | end 162 | 163 | function QUERY_CLASS:Offset(value) 164 | self.offset = value 165 | end 166 | 167 | local function ApplyQueryReplacements(mode, query) 168 | if (!Replacements[mysql.module]) then 169 | return query 170 | end 171 | 172 | local result = query 173 | local entries = Replacements[mysql.module][mode] 174 | 175 | for i = 1, #entries do 176 | result = string.gsub(result, entries[i][1], entries[i][2]) 177 | end 178 | 179 | return result 180 | end 181 | 182 | local function BuildSelectQuery(queryObj) 183 | local queryString = {"SELECT"} 184 | 185 | if (!istable(queryObj.selectList) or #queryObj.selectList == 0) then 186 | queryString[#queryString + 1] = " *" 187 | else 188 | queryString[#queryString + 1] = " "..table.concat(queryObj.selectList, ", ") 189 | end 190 | 191 | if (isstring(queryObj.tableName)) then 192 | queryString[#queryString + 1] = " FROM `"..queryObj.tableName.."` " 193 | else 194 | ErrorNoHalt("[mysql] No table name specified!\n") 195 | return 196 | end 197 | 198 | if (istable(queryObj.whereList) and #queryObj.whereList > 0) then 199 | queryString[#queryString + 1] = " WHERE " 200 | queryString[#queryString + 1] = table.concat(queryObj.whereList, " AND ") 201 | end 202 | 203 | if (istable(queryObj.orderByList) and #queryObj.orderByList > 0) then 204 | queryString[#queryString + 1] = " ORDER BY " 205 | queryString[#queryString + 1] = table.concat(queryObj.orderByList, ", ") 206 | end 207 | 208 | if (isnumber(queryObj.limit)) then 209 | queryString[#queryString + 1] = " LIMIT " 210 | queryString[#queryString + 1] = queryObj.limit 211 | end 212 | 213 | return table.concat(queryString) 214 | end 215 | 216 | local function BuildInsertQuery(queryObj, bIgnore) 217 | local suffix = (bIgnore and (mysql.module == "sqlite" and "INSERT OR IGNORE INTO" or "INSERT IGNORE INTO") or "INSERT INTO") 218 | local queryString = {suffix} 219 | local keyList = {} 220 | local valueList = {} 221 | 222 | if (isstring(queryObj.tableName)) then 223 | queryString[#queryString + 1] = " `"..queryObj.tableName.."`" 224 | else 225 | ErrorNoHalt("[mysql] No table name specified!\n") 226 | return 227 | end 228 | 229 | for i = 1, #queryObj.insertList do 230 | keyList[#keyList + 1] = queryObj.insertList[i][1] 231 | valueList[#valueList + 1] = queryObj.insertList[i][2] 232 | end 233 | 234 | if (#keyList == 0) then 235 | return 236 | end 237 | 238 | queryString[#queryString + 1] = " ("..table.concat(keyList, ", ")..")" 239 | queryString[#queryString + 1] = " VALUES ("..table.concat(valueList, ", ")..")" 240 | 241 | return table.concat(queryString) 242 | end 243 | 244 | local function BuildUpdateQuery(queryObj) 245 | local queryString = {"UPDATE"} 246 | 247 | if (isstring(queryObj.tableName)) then 248 | queryString[#queryString + 1] = " `"..queryObj.tableName.."`" 249 | else 250 | ErrorNoHalt("[mysql] No table name specified!\n") 251 | return 252 | end 253 | 254 | if (istable(queryObj.updateList) and #queryObj.updateList > 0) then 255 | local updateList = {} 256 | 257 | queryString[#queryString + 1] = " SET" 258 | 259 | for i = 1, #queryObj.updateList do 260 | updateList[#updateList + 1] = queryObj.updateList[i][1].." = "..queryObj.updateList[i][2] 261 | end 262 | 263 | queryString[#queryString + 1] = " "..table.concat(updateList, ", ") 264 | end 265 | 266 | if (istable(queryObj.whereList) and #queryObj.whereList > 0) then 267 | queryString[#queryString + 1] = " WHERE " 268 | queryString[#queryString + 1] = table.concat(queryObj.whereList, " AND ") 269 | end 270 | 271 | if (isnumber(queryObj.offset)) then 272 | queryString[#queryString + 1] = " OFFSET " 273 | queryString[#queryString + 1] = queryObj.offset 274 | end 275 | 276 | return table.concat(queryString) 277 | end 278 | 279 | local function BuildDeleteQuery(queryObj) 280 | local queryString = {"DELETE FROM"} 281 | 282 | if (isstring(queryObj.tableName)) then 283 | queryString[#queryString + 1] = " `"..queryObj.tableName.."`" 284 | else 285 | ErrorNoHalt("[mysql] No table name specified!\n") 286 | return 287 | end 288 | 289 | if (istable(queryObj.whereList) and #queryObj.whereList > 0) then 290 | queryString[#queryString + 1] = " WHERE " 291 | queryString[#queryString + 1] = table.concat(queryObj.whereList, " AND ") 292 | end 293 | 294 | if (isnumber(queryObj.limit)) then 295 | queryString[#queryString + 1] = " LIMIT " 296 | queryString[#queryString + 1] = queryObj.limit 297 | end 298 | 299 | return table.concat(queryString) 300 | end 301 | 302 | local function BuildDropQuery(queryObj) 303 | local queryString = {"DROP TABLE"} 304 | 305 | if (isstring(queryObj.tableName)) then 306 | queryString[#queryString + 1] = " `"..queryObj.tableName.."`" 307 | else 308 | ErrorNoHalt("[mysql] No table name specified!\n") 309 | return 310 | end 311 | 312 | return table.concat(queryString) 313 | end 314 | 315 | local function BuildTruncateQuery(queryObj) 316 | local queryString = {"TRUNCATE TABLE"} 317 | 318 | if (isstring(queryObj.tableName)) then 319 | queryString[#queryString + 1] = " `"..queryObj.tableName.."`" 320 | else 321 | ErrorNoHalt("[mysql] No table name specified!\n") 322 | return 323 | end 324 | 325 | return table.concat(queryString) 326 | end 327 | 328 | local function BuildCreateQuery(queryObj) 329 | local queryString = {"CREATE TABLE IF NOT EXISTS"} 330 | 331 | if (isstring(queryObj.tableName)) then 332 | queryString[#queryString + 1] = " `"..queryObj.tableName.."`" 333 | else 334 | ErrorNoHalt("[mysql] No table name specified!\n") 335 | return 336 | end 337 | 338 | queryString[#queryString + 1] = " (" 339 | 340 | if (istable(queryObj.createList) and #queryObj.createList > 0) then 341 | local createList = {} 342 | 343 | for i = 1, #queryObj.createList do 344 | if (mysql.module == "sqlite") then 345 | createList[#createList + 1] = queryObj.createList[i][1].." "..ApplyQueryReplacements("Create", queryObj.createList[i][2]) 346 | else 347 | createList[#createList + 1] = queryObj.createList[i][1].." "..queryObj.createList[i][2] 348 | end 349 | end 350 | 351 | queryString[#queryString + 1] = " "..table.concat(createList, ", ") 352 | end 353 | 354 | if (isstring(queryObj.primaryKey)) then 355 | queryString[#queryString + 1] = ", PRIMARY KEY" 356 | queryString[#queryString + 1] = " ("..queryObj.primaryKey..")" 357 | end 358 | 359 | queryString[#queryString + 1] = " )" 360 | 361 | return table.concat(queryString) 362 | end 363 | 364 | local function BuildAlterQuery(queryObj) 365 | local queryString = {"ALTER TABLE"} 366 | 367 | if (isstring(queryObj.tableName)) then 368 | queryString[#queryString + 1] = " `"..queryObj.tableName.."`" 369 | else 370 | ErrorNoHalt("[mysql] No table name specified!\n") 371 | return 372 | end 373 | 374 | if (istable(queryObj.add)) then 375 | queryString[#queryString + 1] = " ADD "..queryObj.add[1].." "..ApplyQueryReplacements("Create", queryObj.add[2]) 376 | elseif (isstring(queryObj.drop)) then 377 | if (mysql.module == "sqlite") then 378 | ErrorNoHalt("[mysql] Cannot drop columns in sqlite!\n") 379 | return 380 | end 381 | 382 | queryString[#queryString + 1] = " DROP COLUMN "..queryObj.drop 383 | end 384 | 385 | return table.concat(queryString) 386 | end 387 | 388 | function QUERY_CLASS:Execute(bQueueQuery) 389 | local queryString = nil 390 | local queryType = string.lower(self.queryType) 391 | 392 | if (queryType == "select") then 393 | queryString = BuildSelectQuery(self) 394 | elseif (queryType == "insert") then 395 | queryString = BuildInsertQuery(self) 396 | elseif (queryType == "insert ignore") then 397 | queryString = BuildInsertQuery(self, true) 398 | elseif (queryType == "update") then 399 | queryString = BuildUpdateQuery(self) 400 | elseif (queryType == "delete") then 401 | queryString = BuildDeleteQuery(self) 402 | elseif (queryType == "drop") then 403 | queryString = BuildDropQuery(self) 404 | elseif (queryType == "truncate") then 405 | queryString = BuildTruncateQuery(self) 406 | elseif (queryType == "create") then 407 | queryString = BuildCreateQuery(self) 408 | elseif (queryType == "alter") then 409 | queryString = BuildAlterQuery(self) 410 | end 411 | 412 | if (isstring(queryString)) then 413 | if (!bQueueQuery) then 414 | return mysql:RawQuery(queryString, self.callback) 415 | else 416 | return mysql:Queue(queryString, self.callback) 417 | end 418 | end 419 | end 420 | 421 | --[[ 422 | End Query Class. 423 | --]] 424 | 425 | function mysql:Select(tableName) 426 | return QUERY_CLASS:New(tableName, "SELECT") 427 | end 428 | 429 | function mysql:Insert(tableName) 430 | return QUERY_CLASS:New(tableName, "INSERT") 431 | end 432 | 433 | function mysql:InsertIgnore(tableName) 434 | return QUERY_CLASS:New(tableName, "INSERT IGNORE") 435 | end 436 | 437 | function mysql:Update(tableName) 438 | return QUERY_CLASS:New(tableName, "UPDATE") 439 | end 440 | 441 | function mysql:Delete(tableName) 442 | return QUERY_CLASS:New(tableName, "DELETE") 443 | end 444 | 445 | function mysql:Drop(tableName) 446 | return QUERY_CLASS:New(tableName, "DROP") 447 | end 448 | 449 | function mysql:Truncate(tableName) 450 | return QUERY_CLASS:New(tableName, "TRUNCATE") 451 | end 452 | 453 | function mysql:Create(tableName) 454 | return QUERY_CLASS:New(tableName, "CREATE") 455 | end 456 | 457 | function mysql:Alter(tableName) 458 | return QUERY_CLASS:New(tableName, "ALTER") 459 | end 460 | 461 | local UTF8MB4 = "ALTER DATABASE %s CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci" 462 | 463 | -- A function to connect to the MySQL database. 464 | function mysql:Connect(host, username, password, database, port, socket, flags) 465 | port = port or 3306 466 | 467 | if (self.module == "mysqloo") then 468 | if (!istable(mysqloo)) then 469 | require("mysqloo") 470 | end 471 | 472 | if (mysqloo) then 473 | if (self.connection and self.connection:ping()) then 474 | return 475 | end 476 | 477 | local clientFlag = flags or 0 478 | 479 | if (!isstring(socket)) then 480 | self.connection = mysqloo.connect(host, username, password, database, port) 481 | else 482 | self.connection = mysqloo.connect(host, username, password, database, port, socket, clientFlag) 483 | end 484 | 485 | self.connection.onConnected = function(connection) 486 | local success, error_message = connection:setCharacterSet("utf8mb4") 487 | 488 | if (!success) then 489 | ErrorNoHalt("Failed to set MySQL encoding!\n") 490 | ErrorNoHalt(error_message .. "\n") 491 | else 492 | self:RawQuery(string.format(UTF8MB4, database)) 493 | end 494 | 495 | mysql:OnConnected() 496 | end 497 | 498 | self.connection.onConnectionFailed = function(database, errorText) 499 | mysql:OnConnectionFailed(errorText) 500 | end 501 | 502 | self.connection:connect() 503 | 504 | timer.Create("mysql.KeepAlive", 300, 0, function() 505 | self.connection:ping() 506 | end) 507 | else 508 | ErrorNoHalt(string.format(MODULE_NOT_EXIST, self.module)) 509 | end 510 | elseif (self.module == "sqlite") then 511 | mysql:OnConnected() 512 | end 513 | end 514 | 515 | -- A function to query the MySQL database. 516 | function mysql:RawQuery(query, callback, flags, ...) 517 | if (self.module == "mysqloo") then 518 | local queryObj = self.connection:query(query) 519 | 520 | queryObj:setOption(mysqloo.OPTION_NAMED_FIELDS) 521 | 522 | queryObj.onSuccess = function(queryObj, result) 523 | if (callback) then 524 | local bStatus, value = pcall(callback, result, true, tonumber(queryObj:lastInsert())) 525 | 526 | if (!bStatus) then 527 | error(string.format("[mysql] MySQL Callback Error!\n%s\n", value)) 528 | end 529 | end 530 | end 531 | 532 | queryObj.onError = function(queryObj, errorText) 533 | ErrorNoHalt(string.format("[mysql] MySQL Query Error!\nQuery: %s\n%s\n", query, errorText)) 534 | end 535 | 536 | queryObj:start() 537 | elseif (self.module == "sqlite") then 538 | local result = sql.Query(query) 539 | 540 | if (result == false) then 541 | error(string.format("[mysql] SQL Query Error!\nQuery: %s\n%s\n", query, sql.LastError())) 542 | else 543 | if (callback) then 544 | local bStatus, value = pcall(callback, result, true, tonumber(sql.QueryValue("SELECT last_insert_rowid()"))) 545 | 546 | if (!bStatus) then 547 | error(string.format("[mysql] SQL Callback Error!\n%s\n", value)) 548 | end 549 | end 550 | end 551 | else 552 | ErrorNoHalt(string.format("[mysql] Unsupported module \"%s\"!\n", self.module)) 553 | end 554 | end 555 | 556 | -- A function to add a query to the queue. 557 | function mysql:Queue(queryString, callback) 558 | if (isstring(queryString)) then 559 | QueueTable[#QueueTable + 1] = {queryString, callback} 560 | end 561 | end 562 | 563 | -- A function to escape a string for MySQL. 564 | function mysql:Escape(text) 565 | if (self.connection) then 566 | if (self.module == "mysqloo") then 567 | return self.connection:escape(text) 568 | end 569 | else 570 | return sql.SQLStr(text, true) 571 | end 572 | end 573 | 574 | -- A function to disconnect from the MySQL database. 575 | function mysql:Disconnect() 576 | if (self.connection) then 577 | if (self.module == "mysqloo") then 578 | self.connection:disconnect(true) 579 | end 580 | end 581 | end 582 | 583 | function mysql:Think() 584 | if (#QueueTable > 0) then 585 | if (istable(QueueTable[1])) then 586 | local queueObj = QueueTable[1] 587 | local queryString = queueObj[1] 588 | local callback = queueObj[2] 589 | 590 | if (isstring(queryString)) then 591 | self:RawQuery(queryString, callback) 592 | end 593 | 594 | table.remove(QueueTable, 1) 595 | end 596 | end 597 | end 598 | 599 | -- A function to set the module that should be used. 600 | function mysql:SetModule(moduleName) 601 | self.module = moduleName 602 | end 603 | 604 | -- Called when the database connects sucessfully. 605 | function mysql:OnConnected() 606 | MsgC(Color(25, 235, 25), "[mysql] Connected to the database!\n") 607 | 608 | hook.Run("DatabaseConnected") 609 | end 610 | 611 | -- Called when the database connection fails. 612 | function mysql:OnConnectionFailed(errorText) 613 | ErrorNoHalt(string.format("[mysql] Unable to connect to the database!\n%s\n", errorText)) 614 | 615 | hook.Run("DatabaseConnectionFailed", errorText) 616 | end 617 | 618 | -- A function to check whether or not the module is connected to a database. 619 | function mysql:IsConnected() 620 | return self.module == "mysqloo" and (self.connection and self.connection:ping()) or self.module == "sqlite" 621 | end 622 | 623 | return mysql 624 | --------------------------------------------------------------------------------