diff options
| author | nwrl <n/a> | 2025-08-07 14:37:26 -0500 |
|---|---|---|
| committer | nwrl <n/a> | 2025-08-07 14:37:26 -0500 |
| commit | 5fd1519b8d7ee69c9decb7d076d2072af2fc4978 (patch) | |
| tree | 56676423525864a766d0ee2d6d995c85aa3a524a | |
| parent | 6b6ead7eee9a97b467f927d4336fac2aa6ff99a7 (diff) | |
Create prepared statements, implement loadFromDatabase()
| -rw-r--r-- | nameblocker.sp | 176 |
1 files changed, 117 insertions, 59 deletions
diff --git a/nameblocker.sp b/nameblocker.sp index b9f1e7a..9e16b97 100644 --- a/nameblocker.sp +++ b/nameblocker.sp | |||
| @@ -64,8 +64,12 @@ enum OperatingMode { | |||
| 64 | ArrayList regexlist; | 64 | ArrayList regexlist; |
| 65 | ArrayList patternlist; | 65 | ArrayList patternlist; |
| 66 | 66 | ||
| 67 | Database db; | 67 | Database db; static const char DBTABLENAME[] = "163687013_SMNameBlocker"; |
| 68 | static const char TABLENAME[] = "163687013_SMNameBlocker"; | 68 | DBStatement dbInsert; static const char DBINSERTSTATEMENT[] = "INSERT OR IGNORE INTO ? (regexstr, steamid64) VALUES (?, ?);"; |
| 69 | DBStatement dbDelete; static const char DBDELETESTATEMENT[] = "DELETE FROM ? WHERE regexstr=?;"; | ||
| 70 | DBStatement dbReplace; static const char DBREPLACESTATEMENT[] = "UPDATE OR IGNORE ? SET regexstr=?, steamid64=? WHERE regexstr=?;"; | ||
| 71 | DBStatement dbPopulate; static const char DBPOPULATESTATEMENT[] = "SELECT regexstr FROM ?"; | ||
| 72 | |||
| 69 | 73 | ||
| 70 | ConVar gcvarOperMode; static const char OPERMODENAME[] = "nameblock_OperatingMode"; const OperatingMode DEFAULTOPERMODE = OP_KICK; | 74 | ConVar gcvarOperMode; static const char OPERMODENAME[] = "nameblock_OperatingMode"; const OperatingMode DEFAULTOPERMODE = OP_KICK; |
| 71 | ConVar gcvarAdmCmdFlag; static const char ADMCMDFLAGNAME[] = "nameblock_AdminCommandFlag"; const int DEFAULTADMCMDFLAG = ADMFLAG_BAN; | 75 | ConVar gcvarAdmCmdFlag; static const char ADMCMDFLAGNAME[] = "nameblock_AdminCommandFlag"; const int DEFAULTADMCMDFLAG = ADMFLAG_BAN; |
| @@ -118,8 +122,92 @@ void xRegisterIntConVar(ConVar& cv, int defaultVal, const char[] name, const cha | |||
| 118 | 122 | ||
| 119 | 123 | ||
| 120 | 124 | ||
| 125 | int initPrepStatements() { | ||
| 126 | char sqlerr[256 + 1]; | ||
| 127 | if((dbInsert = SQL_PrepareQuery(db, DBINSERTSTATEMENT, sqlerr, sizeof(sqlerr))) == null) | ||
| 128 | logAndFail("Could not prepare insert statement: %s", sqlerr); | ||
| 129 | if((dbDelete = SQL_PrepareQuery(db, DBDELETESTATEMENT, sqlerr, sizeof(sqlerr))) == null) | ||
| 130 | logAndFail("Could not prepare delete statement: %s", sqlerr); | ||
| 131 | if((dbReplace = SQL_PrepareQuery(db, DBREPLACESTATEMENT, sqlerr, sizeof(sqlerr))) == null) | ||
| 132 | logAndFail("Could not prepare replace statement: %s", sqlerr); | ||
| 133 | if((dbPopulate = SQL_PrepareQuery(db, DBPOPULATESTATEMENT, sqlerr, sizeof(sqlerr))) == null) | ||
| 134 | logAndFail("Could not prepare populate statement: %s", sqlerr); | ||
| 135 | |||
| 136 | // This might not work / I might have to use Format() instead of binding. We will see | ||
| 137 | if(SQL_BindParamString(dbInsert, 0, DBTABLENAME, true)) { | ||
| 138 | SQL_GetError(dbInsert, sqlerr, sizeof(sqlerr)); | ||
| 139 | logAndFail("Could not bind tablename to insert statement: %s", sqlerr); | ||
| 140 | } | ||
| 141 | if(SQL_BindParamString(dbDelete, 0, DBTABLENAME, true)) { | ||
| 142 | SQL_GetError(dbDelete, sqlerr, sizeof(sqlerr)); | ||
| 143 | logAndFail("Could not bind tablename to delete statement: %s", sqlerr); | ||
| 144 | } | ||
| 145 | if( SQL_BindParamString(dbReplace, 0, DBTABLENAME, true)) { | ||
| 146 | SQL_GetError(dbReplace, sqlerr, sizeof(sqlerr)); | ||
| 147 | logAndFail("Could not bind tablename to replace statement: %s", sqlerr); | ||
| 148 | } | ||
| 149 | if(SQL_BindParamString(dbPopulate, 0, DBTABLENAME, true)) { | ||
| 150 | SQL_GetError(dbPopulate, sqlerr, sizeof(sqlerr)); | ||
| 151 | logAndFail("Could not bind tablename to populate statement: %s", sqlerr); | ||
| 152 | } | ||
| 153 | |||
| 154 | // If I knew how to do macros this would be much nicer | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | int loadFromDatabase() { | ||
| 160 | // Get database handle | ||
| 161 | char sqlerr[256 + 1]; | ||
| 162 | db = SQLite_UseDatabase("sourcemod-local", sqlerr, sizeof(sqlerr)); | ||
| 163 | if(db == null) logAndFail("Could not connect to sql database: %s", sqlerr); | ||
| 164 | |||
| 165 | // Initialize table if it doesn't exist | ||
| 166 | // I could make this a prepared statement, but I don't believe it's entirely necessary | ||
| 167 | char sqlcbuf[256 + 1]; | ||
| 168 | Format(sqlcbuf, sizeof(sqlcbuf), "CREATE TABLE IF NOT EXISTS \"%s\" (id INTEGER NOT NULL, regexstr TEXT NOT NULL ON CONFLICT IGNORE, steamid64 TEXT NOT NULL ON CONFLICT IGNORE, dateof TEXT DEFAULT CURRENT_DATE, timeof TEXT DEFAULT CURRENT_TIME, PRIMARY KEY (id), UNIQUE (regexstr));", DBTABLENAME); | ||
| 169 | if(!SQL_FastQuery(db, sqlcbuf)) { | ||
| 170 | SQL_GetError(db, sqlerr, sizeof(sqlerr)); | ||
| 171 | logAndFail("Could not initialize nameblocker table: %s", sqlerr); | ||
| 172 | } | ||
| 173 | |||
| 174 | // Initialize and populate datatypes | ||
| 175 | regexlist = new ArrayList(ByteCountToCells(HANDLE_SIZE)); | ||
| 176 | if(regexlist == null) logAndFail("Could not initialize regexlist ArrayList"); | ||
| 177 | |||
| 178 | patternlist = new ArrayList(ByteCountToCells(PATTERN_MAX_LEN)); | ||
| 179 | if(patternlist == null) logAndFail("Could not initialize patternlist ArrayList"); | ||
| 180 | |||
| 181 | // select patterns from nameblock table/database | ||
| 182 | if(SQL_Execute(dbPopulate)) { | ||
| 183 | SQL_GetError(dbPopulate, sqlerr, sizeof(sqlerr)); | ||
| 184 | logAndFail("Population query failed"); | ||
| 185 | } | ||
| 186 | |||
| 187 | // compile each pattern & insert | ||
| 188 | Regex cur; char reerr[256]; RegexError reenum; | ||
| 189 | for(char pattern[PATTERN_MAX_LEN]; SQL_FetchRow(dbPopulate);) { | ||
| 190 | SQL_FetchString(dbPopulate, 1, pattern, sizeof(pattern)); | ||
| 191 | cur = CompileRegex(pattern, gcvarRegexCompFlags, reerr, sizeof(reerr), reenum); | ||
| 192 | if(cur == null) { | ||
| 193 | LogError("Could not compile regex pattern \"%s\": %s (%d)", pattern, reerr, reenum); | ||
| 194 | continue; | ||
| 195 | } | ||
| 196 | |||
| 197 | if(aInsertPattern(pattern, cur, patternlist.Length)) { | ||
| 198 | LogError("Couldn't add regex \"%s\" to arraylists, continuing", pattern); | ||
| 199 | CloseHandle(cur); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | |||
| 121 | public void OnAllPluginsLoaded() { | 208 | public void OnAllPluginsLoaded() { |
| 122 | if(loadFromDatabase()) logAndFail(DATABASE_FAIL_MSG); | 209 | initPrepStatements(); |
| 210 | loadFromDatabase(); | ||
| 123 | 211 | ||
| 124 | // Register convars | 212 | // Register convars |
| 125 | xRegisterIntConVar(gcvarOperMode, view_as<int>(DEFAULTOPERMODE), OPERMODENAME, "Operating mode (disabled, kick, ban, etc.)"); | 213 | xRegisterIntConVar(gcvarOperMode, view_as<int>(DEFAULTOPERMODE), OPERMODENAME, "Operating mode (disabled, kick, ban, etc.)"); |
| @@ -206,8 +294,8 @@ public Action cmdReplacePattern(int client, int args) { | |||
| 206 | return Plugin_Handled; | 294 | return Plugin_Handled; |
| 207 | } | 295 | } |
| 208 | 296 | ||
| 209 | if(modPattern(DBM_INSERT | DBM_DELETE, index, pattern)) { | 297 | if(modPattern(DBM_REPLACE, index, pattern)) { |
| 210 | ReplyToCommand(client, "Error: could not remove pattern from list"); | 298 | ReplyToCommand(client, "Error: could not replace pattern in list"); |
| 211 | return Plugin_Handled; | 299 | return Plugin_Handled; |
| 212 | } | 300 | } |
| 213 | 301 | ||
| @@ -224,37 +312,11 @@ public Action cmdListPatterns(int client, int args) { | |||
| 224 | 312 | ||
| 225 | 313 | ||
| 226 | 314 | ||
| 227 | int aInsertPattern(char pattern[PATTERN_MAX_LEN], Regex res, int index) { | ||
| 228 | if(IsNullString(pattern) || index < 0 || index > regexlist.Length) return -1; | ||
| 229 | |||
| 230 | if(index == regexlist.Length) { | ||
| 231 | regexlist.Push(res); | ||
| 232 | patternlist.Push(pattern); | ||
| 233 | |||
| 234 | } else { | ||
| 235 | regexlist.ShiftUp(index); | ||
| 236 | patternlist.ShiftUp(index); | ||
| 237 | regexlist.Set(index, res); | ||
| 238 | patternlist.Set(index, pattern); | ||
| 239 | |||
| 240 | } | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | int aRemovePattern(int index) { | ||
| 246 | if(index < 0 || index >= regexlist.Length) return -1; | ||
| 247 | |||
| 248 | regexlist.Erase(index); | ||
| 249 | patternlist.Erase(index); | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | enum DBMOD_MODE { | 315 | enum DBMOD_MODE { |
| 255 | DBM_UNDEF, | 316 | DBM_UNDEF, |
| 256 | DBM_INSERT = (1<<0), | 317 | DBM_INSERT, |
| 257 | DBM_DELETE = (1<<1), | 318 | DBM_DELETE, |
| 319 | DBM_REPLACE, | ||
| 258 | DBM_TOOBIG | 320 | DBM_TOOBIG |
| 259 | }; | 321 | }; |
| 260 | 322 | ||
| @@ -262,8 +324,10 @@ int modPattern(DBMOD_MODE mode, int index, char[] pattern="") { | |||
| 262 | if(index < 0 || index > regexlist.Length) return -1; | 324 | if(index < 0 || index > regexlist.Length) return -1; |
| 263 | if(mode <= DBM_UNDEF || mode >= DBM_TOOBIG) return -1; | 325 | if(mode <= DBM_UNDEF || mode >= DBM_TOOBIG) return -1; |
| 264 | 326 | ||
| 265 | Transaction modification = SQL_CreateTransaction(); | 327 | Transaction dbmod = SQL_CreateTransaction(); |
| 266 | if(modification == null) return -1; | 328 | if(dbmod == null) return -1; |
| 329 | |||
| 330 | // Update transaction | ||
| 267 | 331 | ||
| 268 | // char errstr[512]; RegexError reerr; | 332 | // char errstr[512]; RegexError reerr; |
| 269 | // Regex res = CompileRegex(pattern, gcvarRegexCompFlags.IntValue, errstr, sizeof(errstr), reerr); | 333 | // Regex res = CompileRegex(pattern, gcvarRegexCompFlags.IntValue, errstr, sizeof(errstr), reerr); |
| @@ -272,41 +336,35 @@ int modPattern(DBMOD_MODE mode, int index, char[] pattern="") { | |||
| 272 | // return -1; | 336 | // return -1; |
| 273 | // } | 337 | // } |
| 274 | 338 | ||
| 275 | // Update transaction | ||
| 276 | // Update lists | 339 | // Update lists |
| 277 | // Try to delete before inserting | 340 | // Try to delete before inserting |
| 278 | 341 | ||
| 279 | return 0; | 342 | return 0; |
| 280 | } | 343 | } |
| 281 | 344 | ||
| 282 | int loadFromDatabase() { | 345 | int aInsertPattern(char pattern[PATTERN_MAX_LEN], Regex res, int index) { |
| 283 | logAndFail("function \"loadFromDatabase\" not implemented"); | 346 | if(IsNullString(pattern) || res == null || index < 0 || index > regexlist.Length) return -1; |
| 284 | |||
| 285 | // Get database handle | ||
| 286 | char sqlerr[256 + 1]; | ||
| 287 | db = SQLite_UseDatabase("sourcemod-local", sqlerr, sizeof(sqlerr)); | ||
| 288 | if(db == null) logAndFail("Could not connect to sql database: %s", sqlerr); | ||
| 289 | 347 | ||
| 290 | // Initialize table if it doesn't exist | 348 | if(index == regexlist.Length) { |
| 291 | char sqlcbuf[256 + 1]; | 349 | regexlist.Push(res); |
| 292 | Format(sqlcbuf, sizeof(sqlcbuf), "CREATE TABLE IF NOT EXISTS \"%s\" (id INTEGER NOT NULL, regexstr TEXT NOT NULL ON CONFLICT IGNORE, steamid64 TEXT NOT NULL ON CONFLICT IGNORE, dateof TEXT DEFAULT CURRENT_DATE, timeof TEXT DEFAULT CURRENT_TIME, PRIMARY KEY (id), UNIQUE (regexstr));", TABLENAME); | 350 | patternlist.Push(pattern); |
| 293 | if(!SQL_FastQuery(db, sqlcbuf)) { | ||
| 294 | SQL_GetError(db, sqlerr, sizeof(sqlerr)); | ||
| 295 | logAndFail("Could not initialize nameblocker table: %s", sqlerr); | ||
| 296 | } | ||
| 297 | 351 | ||
| 298 | // Initialize and populate datatypes | 352 | } else { |
| 299 | regexlist = new ArrayList(ByteCountToCells(HANDLE_SIZE)); | 353 | regexlist.ShiftUp(index); |
| 300 | if(regexlist == null) logAndFail("Could not initialize regexlist ArrayList"); | 354 | patternlist.ShiftUp(index); |
| 355 | regexlist.Set(index, res); | ||
| 356 | patternlist.Set(index, pattern); | ||
| 301 | 357 | ||
| 302 | patternlist = new ArrayList(ByteCountToCells(PATTERN_MAX_LEN)); | 358 | } |
| 303 | if(patternlist == null) logAndFail("Could not initialize patternlist ArrayList"); | ||
| 304 | 359 | ||
| 305 | // select patterns from nameblock table/database | 360 | return 0; |
| 361 | } | ||
| 306 | 362 | ||
| 363 | int aRemovePattern(int index) { | ||
| 364 | if(index < 0 || index >= regexlist.Length) return -1; | ||
| 307 | 365 | ||
| 308 | // compile each pattern | 366 | regexlist.Erase(index); |
| 309 | // insert pattern & regex into respective lists | 367 | patternlist.Erase(index); |
| 310 | 368 | ||
| 311 | return 0; | 369 | return 0; |
| 312 | } | 370 | } |
