From 31a745422d935e0cfd21ecff082d2e88587e2b1f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 2 Mar 2008 18:01:49 +0000 Subject: [PATCH] added amb1377 - binary sql functions --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401918 --- core/smn_database.cpp | 16 ++++++- extensions/mysql/mysql/MyDatabase.cpp | 31 +++++++++++++ extensions/mysql/mysql/MyDatabase.h | 2 + extensions/sqlite/driver/SqDatabase.cpp | 61 +++++++++++++++++++++++-- extensions/sqlite/driver/SqDatabase.h | 3 ++ plugins/include/dbi.inc | 10 +++- public/IDBDriver.h | 28 +++++++++++- 7 files changed, 142 insertions(+), 9 deletions(-) diff --git a/core/smn_database.cpp b/core/smn_database.cpp index 34f30f5c..22f4b6a3 100644 --- a/core/smn_database.cpp +++ b/core/smn_database.cpp @@ -644,6 +644,11 @@ static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params) char *query; pContext->LocalToString(params[2], &query); + if (params[0] >= 3 && params[3] != -1) + { + return db->DoSimpleQueryEx(query, params[3]) ? 1 : 0; + } + return db->DoSimpleQuery(query) ? 1 : 0; } @@ -661,7 +666,16 @@ static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params) char *query; pContext->LocalToString(params[2], &query); - IQuery *qr = db->DoQuery(query); + IQuery *qr; + + if (params[0] >= 3 && params[3] != -1) + { + qr = db->DoQueryEx(query, params[3]); + } + else + { + qr = db->DoQuery(query); + } if (!qr) { diff --git a/extensions/mysql/mysql/MyDatabase.cpp b/extensions/mysql/mysql/MyDatabase.cpp index d1c85bd7..b9f797a0 100644 --- a/extensions/mysql/mysql/MyDatabase.cpp +++ b/extensions/mysql/mysql/MyDatabase.cpp @@ -226,6 +226,37 @@ IQuery *MyDatabase::DoQuery(const char *query) return new MyQuery(this, res); } +bool MyDatabase::DoSimpleQueryEx(const char *query, size_t len) +{ + IQuery *pQuery = DoQueryEx(query, len); + if (!pQuery) + { + return false; + } + pQuery->Destroy(); + return true; +} + +IQuery *MyDatabase::DoQueryEx(const char *query, size_t len) +{ + if (mysql_real_query(m_mysql, query, len) != 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); diff --git a/extensions/mysql/mysql/MyDatabase.h b/extensions/mysql/mysql/MyDatabase.h index 57d4b8a0..14ba739e 100644 --- a/extensions/mysql/mysql/MyDatabase.h +++ b/extensions/mysql/mysql/MyDatabase.h @@ -58,6 +58,8 @@ public: //IDatabase void UnlockFromFullAtomicOperation(); void IncReferenceCount(); IDBDriver *GetDriver(); + bool DoSimpleQueryEx(const char *query, size_t len); + IQuery *DoQueryEx(const char *query, size_t len); public: const DatabaseInfo &GetInfo(); private: diff --git a/extensions/sqlite/driver/SqDatabase.cpp b/extensions/sqlite/driver/SqDatabase.cpp index 450eb1b0..a008aca1 100644 --- a/extensions/sqlite/driver/SqDatabase.cpp +++ b/extensions/sqlite/driver/SqDatabase.cpp @@ -160,7 +160,36 @@ IQuery *SqDatabase::DoQuery(const char *query) return pQuery; } -IPreparedQuery *SqDatabase::PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode/* =NULL */) +bool SqDatabase::DoSimpleQueryEx(const char *query, size_t len) +{ + IQuery *pQuery = DoQueryEx(query, len); + if (!pQuery) + { + return false; + } + pQuery->Destroy(); + return true; +} + +IQuery *SqDatabase::DoQueryEx(const char *query, size_t len) +{ + IPreparedQuery *pQuery = PrepareQueryEx(query, len, NULL, 0, NULL); + if (!pQuery) + { + return NULL; + } + if (!pQuery->Execute()) + { + pQuery->Destroy(); + return NULL; + } + return pQuery; +} + +IPreparedQuery *SqDatabase::PrepareQuery(const char *query, + char *error, + size_t maxlength, + int *errCode/* =NULL */) { sqlite3_stmt *stmt = NULL; if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, -1, &stmt, NULL)) != SQLITE_OK @@ -179,12 +208,34 @@ IPreparedQuery *SqDatabase::PrepareQuery(const char *query, char *error, size_t strncopy(error, msg, maxlength); } m_LastError.assign(msg); - #if 0 /* This didn't really seem like a good idea... */ - if (stmt) + return NULL; + } + return new SqQuery(this, stmt); +} + +IPreparedQuery *SqDatabase::PrepareQueryEx(const char *query, + size_t len, + char *error, + size_t maxlength, + int *errCode/* =NULL */) +{ + sqlite3_stmt *stmt = NULL; + if ((m_LastErrorCode = sqlite3_prepare_v2(m_sq3, query, len, &stmt, NULL)) != SQLITE_OK + || !stmt) + { + const char *msg; + if (m_LastErrorCode != SQLITE_OK) { - sqlite3_finalize(stmt); + msg = sqlite3_errmsg(m_sq3); + } else { + msg = "Invalid query string"; + m_LastErrorCode = SQLITE_ERROR; } - #endif + if (error) + { + strncopy(error, msg, maxlength); + } + m_LastError.assign(msg); return NULL; } return new SqQuery(this, stmt); diff --git a/extensions/sqlite/driver/SqDatabase.h b/extensions/sqlite/driver/SqDatabase.h index 63f96e9f..6044a3f0 100644 --- a/extensions/sqlite/driver/SqDatabase.h +++ b/extensions/sqlite/driver/SqDatabase.h @@ -46,6 +46,7 @@ public: bool DoSimpleQuery(const char *query); IQuery *DoQuery(const char *query); IPreparedQuery *PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode=NULL); + IPreparedQuery *PrepareQueryEx(const char *query, size_t len, char *error, size_t maxlength, int *errCode=NULL); bool QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize); unsigned int GetAffectedRows(); unsigned int GetInsertID(); @@ -53,6 +54,8 @@ public: void UnlockFromFullAtomicOperation(); void IncReferenceCount(); IDBDriver *GetDriver(); + bool DoSimpleQueryEx(const char *query, size_t len); + IQuery *DoQueryEx(const char *query, size_t len); public: sqlite3 *GetDb(); private: diff --git a/plugins/include/dbi.inc b/plugins/include/dbi.inc index cba44810..084b6d4e 100644 --- a/plugins/include/dbi.inc +++ b/plugins/include/dbi.inc @@ -277,11 +277,14 @@ stock bool:SQL_QuoteString(Handle:database, * * @param database A database Handle. * @param query Query string. + * @param len Optional parameter to specify the query length, in + * bytes. This can be used to send binary queries that + * have a premature terminator. * @return True if query succeeded, false otherwise. Use * SQL_GetError to find the last error. * @error Invalid database Handle. */ -native bool:SQL_FastQuery(Handle:database, const String:query[]); +native bool:SQL_FastQuery(Handle:database, const String:query[], len=-1); /** * Executes a simple query and returns a new query Handle for @@ -289,11 +292,14 @@ native bool:SQL_FastQuery(Handle:database, const String:query[]); * * @param database A database Handle. * @param query Query string. + * @param len Optional parameter to specify the query length, in + * bytes. This can be used to send binary queries that + * have a premature terminator. * @return A new Query Handle on success, INVALID_HANDLE * otherwise. The Handle must be freed with CloseHandle(). * @error Invalid database Handle. */ -native Handle:SQL_Query(Handle:database, const String:query[]); +native Handle:SQL_Query(Handle:database, const String:query[], len=-1); /** * Creates a new prepared statement query. Prepared statements can diff --git a/public/IDBDriver.h b/public/IDBDriver.h index d4e35268..71d9fe2d 100644 --- a/public/IDBDriver.h +++ b/public/IDBDriver.h @@ -42,7 +42,7 @@ */ #define SMINTERFACE_DBI_NAME "IDBI" -#define SMINTERFACE_DBI_VERSION 5 +#define SMINTERFACE_DBI_VERSION 6 namespace SourceMod { @@ -547,6 +547,32 @@ namespace SourceMod * This function is thread safe. */ virtual IDBDriver *GetDriver() =0; + + /** + * @brief Prepares and executes a binary query in one step, and discards + * any return data. + * + * This function is not thread safe and must be included in any locks. + * + * @param query Query string. + * @param length Length of query string. + * @return True on success, false otherwise. + */ + virtual bool DoSimpleQueryEx(const char *query, size_t len) =0; + + /** + * @brief Prepares and executes a binary query in one step, and returns + * the resultant data set. + * + * Note: If a query contains more than one result set, each + * result set must be processed before a new query is started. + * + * This function is not thread safe and must be included in any locks. + * + * @param query Query string. + * @return IQuery pointer on success, NULL otherwise. + */ + virtual IQuery *DoQueryEx(const char *query, size_t len) =0; }; /**