/** * vim: set ts=4 : * ================================================================ * SourceMod MySQL Extension * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * ================================================================ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License, * version 3.0, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, AlliedModders LLC gives you permission to * link the code of this program (as well as its derivative works) to * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any * Game MODs that run on software by the Valve Corporation. You must * obey the GNU General Public License in all respects for all other * code used. Additionally, AlliedModders LLC grants this exception * to all derivative works. AlliedModders LLC defines further * exceptions, found in LICENSE.txt (as of this writing, version * JULY-31-2007), or . * * Version: $Id$ */ #include "MyDatabase.h" #include "smsdk_ext.h" #include "MyBasicResults.h" #include "MyStatement.h" DBType GetOurType(enum_field_types type) { switch (type) { case MYSQL_TYPE_DOUBLE: case MYSQL_TYPE_FLOAT: { return DBType_Float; } case MYSQL_TYPE_TINY: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: case MYSQL_TYPE_INT24: case MYSQL_TYPE_YEAR: case MYSQL_TYPE_BIT: { return DBType_Integer; } case MYSQL_TYPE_LONGLONG: case MYSQL_TYPE_DATE: case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_NEWDATE: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_STRING: case MYSQL_TYPE_NEWDECIMAL: case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: { return DBType_String; } case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: { return DBType_Blob; } default: { return DBType_String; } } return DBType_Unknown; } MyDatabase::MyDatabase(MYSQL *mysql, const DatabaseInfo *info, bool persistent) : m_mysql(mysql), m_refcount(1), m_pFullLock(NULL), m_bPersistent(persistent) { m_Host.assign(info->host); m_Database.assign(info->database); m_User.assign(info->user); m_Pass.assign(info->pass); m_Info.database = m_Database.c_str(); m_Info.host = m_Host.c_str(); m_Info.user = m_User.c_str(); m_Info.pass = m_Pass.c_str(); m_Info.driver = NULL; m_Info.maxTimeout = info->maxTimeout; m_Info.port = info->port; m_pRefLock = threader->MakeMutex(); } MyDatabase::~MyDatabase() { mysql_close(m_mysql); m_mysql = NULL; m_pRefLock->DestroyThis(); if (m_pFullLock) { m_pFullLock->DestroyThis(); } } void MyDatabase::IncReferenceCount() { m_pRefLock->Lock(); m_refcount++; m_pRefLock->Unlock(); } bool MyDatabase::Close() { m_pRefLock->Lock(); if (m_refcount > 1) { m_refcount--; m_pRefLock->Unlock(); return false; } m_pRefLock->Unlock(); /* Remove us from the search list */ if (m_bPersistent) { g_MyDriver.RemoveFromList(this, true); } /* Finally, free our resource(s) */ delete this; return true; } const DatabaseInfo &MyDatabase::GetInfo() { return m_Info; } unsigned int MyDatabase::GetInsertID() { return (unsigned int)mysql_insert_id(m_mysql); } unsigned int MyDatabase::GetAffectedRows() { return (unsigned int)mysql_affected_rows(m_mysql); } const char *MyDatabase::GetError(int *errCode) { if (errCode) { *errCode = mysql_errno(m_mysql); } return mysql_error(m_mysql); } bool MyDatabase::QuoteString(const char *str, char buffer[], size_t maxlength, size_t *newSize) { unsigned long size = static_cast(strlen(str)); unsigned long needed = size * 2 + 1; if (maxlength < needed) { if (newSize) { *newSize = (size_t)needed; } return false; } needed = mysql_real_escape_string(m_mysql, buffer, str, size); if (newSize) { *newSize = (size_t)needed; } return true; } bool MyDatabase::DoSimpleQuery(const char *query) { IQuery *pQuery = DoQuery(query); if (!pQuery) { return false; } pQuery->Destroy(); return true; } IQuery *MyDatabase::DoQuery(const char *query) { if (mysql_real_query(m_mysql, query, strlen(query)) != 0) { return NULL; } MYSQL_RES *res = NULL; if (mysql_field_count(m_mysql)) { res = mysql_store_result(m_mysql); if (!res) { return NULL; } } return new MyQuery(this, res); } IPreparedQuery *MyDatabase::PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode) { MYSQL_STMT *stmt = mysql_stmt_init(m_mysql); if (!stmt) { if (error) { strncopy(error, GetError(errCode), maxlength); } else if (errCode) { *errCode = mysql_errno(m_mysql); } return NULL; } if (mysql_stmt_prepare(stmt, query, strlen(query)) != 0) { if (error) { strncopy(error, mysql_stmt_error(stmt), maxlength); } if (errCode) { *errCode = mysql_stmt_errno(stmt); } mysql_stmt_close(stmt); return NULL; } return new MyStatement(this, stmt); } bool MyDatabase::LockForFullAtomicOperation() { if (!m_pFullLock) { m_pFullLock = threader->MakeMutex(); if (!m_pFullLock) { return false; } } m_pFullLock->Lock(); return true; } void MyDatabase::UnlockFromFullAtomicOperation() { if (m_pFullLock) { m_pFullLock->Unlock(); } } IDBDriver *MyDatabase::GetDriver() { return &g_MyDriver; }