| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866 |
- /*
- SQLite Improved v0.9.7 by Slice
-
- Changelog:
- 2015-07-13:
- * Update for 0.3.7 R2.
- * All crash issues should be solved now, including the previous one that happened only on some servers.
- 2014-10-08:
- * Fix crash when using stmt_fetch_row on an empty result (only affects Linux servers).
- 2013-10-07:
- * Display errors from db_query. Works only on Windows.
-
- 2012-07-23:
- * Fix problem with persistent databases (hopefully).
-
- 2012-07-21:
- * Fix crash happening on Linux related to NULL values in db_free_result.
-
- 2012-07-15:
- * Improvements to persistent databases.
-
- 2012-06-15:
- * Fix compiler crash when db_query isn't used.
-
- 2012-05-27:
- * Always throw warnings when invalid results are given to SQLitei functions.
- * Even more improvements to stability!
- * GetAmxBase is now updated with a JIT compatible version (all credits to Zeex).
- * All the default DB functions (which are hooked by SQLitei) are now compatible with the JIT plugin.
- * Fixed a bug in SA-MP's SQLite implementation where strings would contain signed characters instead of unsigned.
- Most functions work just fine with both types of strings but strcmp, for one, does not.
- * stmt_bind_value now deals with packed strings properly.
-
- 2012-03-22:
- * db_query now accept extra parameters similar to those in stmt_bind_value, allowing
- a very quick way to format and run queries!
-
- 2012-03-21:
- * Fixed a rare crash that would occur if you closed a DB while having autofreed results open.
- * The deprecated db_query_autofree is now removed. Simply use db_query instead.
- * Fixed a problem where a certain integer would cause an invalid value.
- * Added DB::TYPE_UINT, which inserts an unsigned integer.
- An unsigned integer have values between 0 and 4294967295 as opposed to -2147483648 and 2147483647.
- * Added helper function db_print_query.
- * Added db_dump_table!
-
- 2012-03-01:
- * db_free_result will now completely ignore invalid results (0).
-
- 2012-02-12:
- * Added db_attach_memory_db and db_detach_memory_db.
-
- 2012-02-11:
- * Added DB::TYPE_ARRAY, which allows you to insert and read arrays with statements!
- * Improved error handling and increased some buffer sizes.
- * Added db_begin_transaction, db_end_transaction, and db_set_asynchronous.
- * Minor improvements here and there.
-
- 2012-02-10:
- * A few bug fixes.
- * Added db_field_is_null, which returns true if the field is a true NULL value (not just an empty string).
- * Deprecated db_query_autofree.
-
- 2012-02-09:
- * Defining WP_Hash prior to inclusion is no longer needed.
- * db_query now has an optional third argument - enable autorelease, which is
- true by default.
- * Improved stability on freeing results:
- - Freeing results twice will not crash the server anymore - it will just generate
- a warning.
- - Freeing a result that will be autoreleased will remove it from the autorelease pool.
- * The compiler will no longer wrongfully detect recursion inside this include.
- * Added db_query_int and db_query_float.
- * Added db_get_struct_info and db_set_struct_info; used mainly internally.
- * Added db_exec and db_insert.
- * Performance improvements!
-
- 2012-02-08:
- * db_print_result will no longer go to the end of the result.
- * Added db_get_row_index, db_set_row_index, and db_rewind.
-
- 2012-02-07:
- * db_get_field/db_get_field_assoc will not crash anymore with NULL values!
-
- 2011-12-21:
- * Added two new types for stmt_bind_value:
- - DB::TYPE_WP_HASH: Puts a BLOB value of a whirlpool hash from the given string into the query (ex. x'FFAA4411...').
- - DB::TYPE_PLAYER_NAME: Puts a player name from the ID passed.
- Note that DB_USE_WHIRLPOOL must be defined as true in order for DB::TYPE_WP_HASH to work.
- * Made some optimizations and minor bug fixes.
- * stmt_execute will now autofree the result unless the 3rd argument is false.
- * Added the preprocessor options DE_DEBUG (logs debug info) and DB_LOG_TO_CHAT (prints log messages to chat).
- * Improved the way results are dealt with internally to avoid crashes at all costs.
- * Added debug messages pretty much everywhere.
-
- 2011-12-16:
- * Added db_open_persistent, db_is_persistent, db_is_valid_persistent, and db_free_persistent.
- * Added db_query_autofree.
- * Added db_get_field_int and db_get_field_float.
- * Corrected a few SQLite natives.
-
- 2011-12-15:
- * Added stmt_autoclose.
- * Memory usage decreased significantly.
- * All functions now accept both packed and unpacked strings.
- * Minor bug fixes and optimizations.
-
- 2011-12-14:
- * Initial release.
- */
- #if !defined _samp_included
- #error Please include a_samp before sqlitei.
- #endif
- #if defined __fmt_funcinc && defined FormatSpecifier
- #error Please include sqlitei before formatex.
- #endif
- #if !defined HTTP
- #tryinclude <a_http>
- #endif
- #if !defined DB_MAX_PARAMS
- #define DB_MAX_PARAMS 32
- #endif
- #if !defined DB_MAX_STATEMENTS
- #define DB_MAX_STATEMENTS 16
- #endif
- #if !defined DB_MAX_STATEMENT_SIZE
- #define DB_MAX_STATEMENT_SIZE 1024
- #endif
- #if !defined DB_MAX_FIELDS
- #define DB_MAX_FIELDS 64
- #endif
- #if !defined DB_MAX_PERSISTENT_DATABASES
- #define DB_MAX_PERSISTENT_DATABASES 4
- #endif
- #if !defined DB_USE_WHIRLPOOL
- #define DB_USE_WHIRLPOOL false
- #endif
- #if !defined DB_DEBUG
- #define DB_DEBUG false
- #endif
- #if !defined DB_DEBUG_BACKTRACE_NOTICE
- #define DB_DEBUG_BACKTRACE_NOTICE false
- #endif
- #if !defined DB_DEBUG_BACKTRACE_WARNING
- #define DB_DEBUG_BACKTRACE_WARNING false
- #endif
- #if !defined DB_DEBUG_BACKTRACE_ERROR
- #define DB_DEBUG_BACKTRACE_ERROR false
- #endif
- #if !defined DB_DEBUG_BACKTRACE_DEBUG
- #define DB_DEBUG_BACKTRACE_DEBUG false
- #endif
- #if !defined DB_LOG_TO_CHAT
- #define DB_LOG_TO_CHAT false
- #endif
- // "Namespace"
- #define DB:: DB_
- // Fix some natives ("const" keyword was missing)
- native DB:db_open@(const szName[]) = db_open;
- native DBResult:db_query@(DB:db, const szQuery[]) = db_query;
- native db_get_field@(DBResult:dbresult, field, result[], maxlength) = db_get_field;
- native db_get_field_assoc@(DBResult:dbresult, const field[], result[], maxlength) = db_get_field_assoc;
- native db_close@(DB:db) = db_close;
- native db_free_result@(DBResult:dbrResult) = db_free_result;
- #define db_open db_open@
- #define db_query%1( db_query_hook(_,
- #define db_close db_close_hook
- #define db_free_result db_free_result_hook
- #if DB::USE_WHIRLPOOL
- native DB::WP_Hash(buffer[], len, const str[]) = WP_Hash;
- #endif
- enum DB::e_SYNCHRONOUS_MODE {
- DB::SYNCHRONOUS_OFF,
- DB::SYNCHRONOUS_NORMAL,
- DB::SYNCHRONOUS_FULL
- };
- enum DBDataType: {
- DB::TYPE_NONE,
- DB::TYPE_NULL,
- DB::TYPE_INT,
- DB::TYPE_INTEGER = DB::TYPE_INT,
- DB::TYPE_UINT,
- DB::TYPE_UINTEGER = DB::TYPE_UINT,
- DB::TYPE_FLOAT,
- DB::TYPE_STRING,
- DB::TYPE_RAW_STRING,
- DB::TYPE_IDENTIFIER,
-
- // Special types
-
- #if DB::USE_WHIRLPOOL
- DB::TYPE_WP_HASH,
- #endif
-
- DB::TYPE_PLAYER_NAME,
- DB::TYPE_PLAYER_IP,
- DB::TYPE_ARRAY
- };
- #define INT: DB::TYPE_INT,QQPA:
- #define INTEGER: DB::TYPE_INT,QQPA:
- #define UINT: DB::TYPE_UINT,QQPA:
- #define UINTEGER: DB::TYPE_UINT,QQPA:
- #define FLOAT: DB::TYPE_FLOAT,QQPA:
- #define STRING: DB::TYPE_STRING,QQPA:
- #define RAW_STRING: DB::TYPE_RAW_STRING,QQPA:
- #define IDENTIFIER: DB::TYPE_IDENTIFIER,QQPA:
- #if DB::USE_WHIRLPOOL
- #define WP_HASH: DB::TYPE_WP_HASH,QQPA:
- #endif
- #define PLAYER_NAME: DB::TYPE_PLAYER_NAME,QQPA:
- #define PLAYER_IP: DB::TYPE_PLAYER_IP,QQPA:
- enum DB::E_STATEMENT {
- // The ready-to-run query.
- e_szQuery[DB::MAX_STATEMENT_SIZE + 1],
-
- // Parameter count
- e_iParams,
-
- // The parameter types.
- DBDataType:e_aiParamTypes[DB::MAX_PARAMS],
-
- // Position of parameters in the query string.
- e_aiParamPositions[DB::MAX_PARAMS],
-
- // Length of parameters in the query string.
- e_aiParamLengths[DB::MAX_PARAMS],
-
- // Types of bound return fields
- DBDataType:e_aiFieldTypes[DB::MAX_FIELDS],
-
- // Sizes of bound result fields (used only for strings currently)
- e_aiFieldSizes[DB::MAX_FIELDS],
-
- // Addresses of bound result fields
- e_aiFieldAddresses[DB::MAX_FIELDS],
-
- // The database it was created for
- DB:e_dbDatabase,
-
- // The result (after executing)
- DBResult:e_dbrResult,
-
- // How many rows were fetched from the most recent result
- e_iFetchedRows,
-
- // Whether or not any leftover results should be automatically freed
- // Note that whenever a new result is put into e_dbrResult, the previous one is freed.
- bool:e_bAutoFreeResult
- };
- enum {
- SQLITE_LIMIT_LENGTH,
- SQLITE_LIMIT_SQL_LENGTH,
- SQLITE_LIMIT_COLUMN,
- SQLITE_LIMIT_EXPR_DEPTH,
- SQLITE_LIMIT_COMPOUND_SELECT,
- SQLITE_LIMIT_VDBE_OP,
- SQLITE_LIMIT_FUNCTION_ARG,
- SQLITE_LIMIT_ATTACHED,
- SQLITE_LIMIT_LIKE_PATTERN_LEN,
- SQLITE_LIMIT_VARIABLE_NUMBER,
- SQLITE_LIMIT_TRIGGER_DEPTH
- };
- // SQLite 3 C-struct offsets
- enum e_SQLITE3 {
- sqlite3_pVfs [4],
- sqlite3_iBackends [4],
- sqlite3_pBackends [4],
- sqlite3_iFlags [4],
- sqlite3_iOpenFlags [4],
-
- sqlite3_iErrorCode [4],
- sqlite3_iErrorMask [4],
- bool:sqlite3_bAutoCommit [1],
- sqlite3_iTempStore [1],
- bool:sqlite3_bMallocFailed [1],
-
- sqlite3_iDefaultLockMode [1],
- sqlite3_iNextAutovac [1],
- bool:sqlite3_bSuppressErrors [1],
- sqlite3_iPad [2],
-
- sqlite3_iNextPagesize [4],
- sqlite3_iNumTables [4],
- sqlite3_pDefaultCollation [4],
- sqlite3_iLastRowid [4],
- sqlite3_iLastRowidUpperBytes[4],
- sqlite3_iMagic [4],
- sqlite3_iNumChanges [4],
- sqlite3_iNumTotalChanges [4],
-
- sqlite3_aiLimits [SQLITE_LIMIT_TRIGGER_DEPTH * 4],
-
- sqlite3_aInitInfo [12],
- sqlite3_iNumExtensions [4],
- sqlite3_pExtensions [4],
- sqlite3_pVdbe [4],
- sqlite3_iActiveVdbeCount [4],
- sqlite3_iWritingVdbeCount [4],
-
- sqlite3_pTraceFunc [4],
- sqlite3_pTraceArg [4],
- sqlite3_pProfilingFunc [4],
- sqlite3_pProfilingArg [4],
- sqlite3_pCommitArg [4],
- sqlite3_pCommitCallback [4],
- sqlite3_pRollbackArg [4],
- sqlite3_pRollbackCallback [4],
- sqlite3_pUpdateArg [4],
- sqlite3_pUpdateCallback [4],
- sqlite3_pWalCallback [4],
- sqlite3_pWalArg [4],
- sqlite3_pCollNeeded [4],
- sqlite3_pCollNeeded16 [4],
- sqlite3_pCollNeededArg [4],
- sqlite3_pError [4],
- sqlite3_pErrorMsg [4],
- sqlite3_pErrorMsg16 [4]
- };
- enum DB::E_PERSISTENT_DB {
- e_szName[128 char],
- bool:e_bIsUsed,
- DB:e_dbDatabase
- };
- static stock
- gs_szBuffer[8192],
- gs_aiCompressBuffer[3072],
- gs_Statements[DBStatement:DB::MAX_STATEMENTS][DB::E_STATEMENT],
- gs_iAutoFreeTimer = -1,
- gs_iAutoFreeResultsIndex = 0,
- DBResult:gs_adbrAutoFreeResults[1024],
- gs_iAutoCloseStatementsIndex = 0,
- DBStatement:gs_astAutoCloseStatements[1024],
- gs_PersistentDatabases[DB::MAX_PERSISTENT_DATABASES][DB::E_PERSISTENT_DB],
- gs_iClosePersistentTimer = -1,
- gs_iFreeStatementResultsTimer = -1,
- gs_szNull[1] = {0}
- ;
- const
- DBStatement:DB::INVALID_STATEMENT = DBStatement:-1,
- DBResult:DB::INVALID_RESULT = DBResult:0
- ;
- #if !DB_DEBUG
- #define DB_Debug(%1)%0;
- #endif
- #if !DB_LOG_TO_CHAT
- #if DB_DEBUG_BACKTRACE_NOTICE
- #define DB_Notice(%1) print(!"SQLitei Notice: " %1),PrintAmxBacktrace()
- #define DB_Noticef(%1) printf("SQLitei Notice: " %1),PrintAmxBacktrace()
- #else
- #define DB_Notice(%1) print(!"SQLitei Notice: " %1)
- #define DB_Noticef(%1) printf("SQLitei Notice: " %1)
- #endif
- #if DB_DEBUG_BACKTRACE_WARNING
- #define DB_Warning(%1) print(!"SQLitei Warning: " %1),PrintAmxBacktrace()
- #define DB_Warningf(%1) printf("SQLitei Warning: " %1),PrintAmxBacktrace()
- #else
- #define DB_Warning(%1) print(!"SQLitei Warning: " %1)
- #define DB_Warningf(%1) printf("SQLitei Warning: " %1)
- #endif
- #if DB_DEBUG_BACKTRACE_ERROR
- #define DB_Error(%1) print(!"SQLitei Error: " %1),PrintAmxBacktrace()
- #define DB_Errorf(%1) printf("SQLitei Error: " %1),PrintAmxBacktrace()
- #else
- #define DB_Error(%1) print(!"SQLitei Error: " %1)
- #define DB_Errorf(%1) printf("SQLitei Error: " %1)
- #endif
-
- #if DB_DEBUG
- #if DB_DEBUG_BACKTRACE_DEBUG
- #define DB_Debug(%1) printf("SQLitei Debug: " %1),PrintAmxBacktrace()
- #else
- #define DB_Debug(%1) printf("SQLitei Debug: " %1)
- #endif
- #endif
- #else
- new
- gs_szLogMessageBuffer[256]
- ;
-
- #define DB_Notice(%1) SendClientMessageToAll(0xFFFFFFFF, "SQLitei Notice: " %1), print(!"SQLitei Notice: " %1)
- #define DB_Warning(%1) SendClientMessageToAll(0xEBBD17FF, "SQLitei Warning: " %1), print(!"SQLitei Warning: " %1)
- #define DB_Error(%1) SendClientMessageToAll(0xCC0000FF, "SQLitei Error: " %1), print(!"SQLitei Error: " %1)
- #define DB_Noticef(%1) format(gs_szLogMessageBuffer, sizeof(gs_szLogMessageBuffer), "SQLitei Notice: " %1), print(gs_szLogMessageBuffer), SendClientMessageToAll(0xDDDDDDFF, gs_szLogMessageBuffer)
- #define DB_Warningf(%1) format(gs_szLogMessageBuffer, sizeof(gs_szLogMessageBuffer), "SQLitei Warning: " %1), print(gs_szLogMessageBuffer), SendClientMessageToAll(0xEBBD17FF, gs_szLogMessageBuffer)
- #define DB_Errorf(%1) format(gs_szLogMessageBuffer, sizeof(gs_szLogMessageBuffer), "SQLitei Error: " %1), print(gs_szLogMessageBuffer), SendClientMessageToAll(0xCC0000FF, gs_szLogMessageBuffer)
-
- #if DB_DEBUG
- #define DB_Debug(%1) format(gs_szLogMessageBuffer, sizeof(gs_szLogMessageBuffer), "SQLitei Debug: " %1), print(gs_szLogMessageBuffer), SendClientMessageToAll(0xFFFFFFFF, gs_szLogMessageBuffer)
- #endif
- #endif
- // Has to be defined after statement functions.
- forward DBResult:db_query_hook(iTagOf3 = tagof(_bAutoRelease), DB:db, const szQuery[], {bool, DBDataType}:_bAutoRelease = true, {DBDataType, QQPA}:...);
- // forward's
- forward bool:db_set_row_index(DBResult:dbrResult, iRow);
- forward bool:db_free_result_hook(DBResult:dbrResult);
- forward bool:db_set_synchronous(DB:db, DB::e_SYNCHRONOUS_MODE:iValue);
- forward DB::funcinc();
- public DB::funcinc() {
- strcat(gs_szBuffer, "");
- strpack(gs_szBuffer, "");
- ispacked(gs_szBuffer);
- db_get_field(DBResult:0, 0, gs_szBuffer, 0);
- db_query(DB:0,"");
- }
- static stock DB::CompressArray(const aiArray[], iSize = sizeof(aiArray), aiOutput[]) {
- new
- iOutputIndex = 4,
- iValue,
- iMSB,
- iShift
- ;
-
- // * 0b11000000 = Single byte, negative
- // * 0b10000000 = Single byte
- // * 0b01000000 = Multi-byte
- // - 0b01000000 = More bytes
- // - 0b11000000 = Last byte
- // - 0b10000000 = Unused
-
- for (new i = 0; i < iSize; i++) {
- // Will the value fit in one byte?
-
- iValue = aiArray[i];
-
- if (-0b00111111 <= iValue <= 0b00111111) {
- // Is the value negative?
-
- if (iValue & 0x80000000) {
- // Set the "single byte, negative" bits on and put the value without its sign
-
- aiOutput{iOutputIndex++} = 0b11000000 | -iValue;
- } else {
- // Just put the value in with the "single byte" bit
-
- aiOutput{iOutputIndex++} = 0b10000000 | iValue;
- }
- } else {
- // Figure out how many bits we'll have to write
- iMSB = DB::FindMSB(iValue) + 1;
-
- // Make iShift a multiple of 6 (if it isn't already)
- if ((iShift = iMSB % 6))
- aiOutput{iOutputIndex++} = 0b01000000 | (iValue >>> (iMSB - iShift) & ~(0xFFFFFFFF << iShift));
-
- iShift = iMSB - iShift;
-
- // Write bits out left-right
- while ((iShift -= 6) >= 0)
- aiOutput{iOutputIndex++} = 0b01000000 | (iValue >>> iShift & 0b00111111);
-
- // Change the "more bytes" bits into "last byte"
- aiOutput{iOutputIndex - 1} |= 0b11000000;
- }
- }
-
- // Put the number of bytes we just wrote into the first cell of the output
- aiOutput[0] = 0x80808080 | ((iOutputIndex & 0x1FE00000) << 3) | ((iOutputIndex & 0x3FC000) << 2) | ((iOutputIndex & 0x7F80) << 1) | (iOutputIndex & 0x7F);
-
- // Make sure the bytes in the last cell are 0
- aiOutput{iOutputIndex} = 0;
-
- iValue = iOutputIndex;
-
- while (++iOutputIndex % 4)
- aiOutput{iOutputIndex} = 0;
-
- // Return the number of bytes written (not counting the first 4)
- return iValue;
- }
- static stock DB::DecompressArray(const aiCompressedArray[], aiOutput[], iOutputSize = sizeof(aiOutput)) {
- new
- iBytes,
- iOutputIndex = 0
- ;
-
- // Get the number of bytes to parse
- iBytes = aiCompressedArray[0];
- iBytes = ((iBytes & 0x7F000000) >>> 3) | ((iBytes & 0x7F0000) >>> 2) | ((iBytes & 0x7F00) >>> 1) | (iBytes & 0x7F);
-
- for (new i = 4; i < iBytes; i++) {
- // Out of slots?
- if (iOutputIndex >= iOutputSize) {
- DB::Error("(DB::DecompressArray) Compressed array is larger than decompress buffer.");
-
- break;
- }
-
- // Single byte?
- if ((aiCompressedArray{i} & 0b10000000)) {
- // Negative?
- if ((aiCompressedArray{i} & 0b01000000))
- aiOutput[iOutputIndex++] = -(aiCompressedArray{i} & 0b00111111);
- else
- aiOutput[iOutputIndex++] = (aiCompressedArray{i} & 0b00111111);
- } else {
- // Multi byte; read the last bits
- aiOutput[iOutputIndex] = aiCompressedArray{i} & 0b00111111;
-
- // Keep reading bits while shifting the value to the left
- do {
- aiOutput[iOutputIndex] <<= 6;
- aiOutput[iOutputIndex] |= aiCompressedArray{++i} & 0b00111111;
- } while ((aiCompressedArray{i} & 0b10000000) == 0);
-
- iOutputIndex++;
- }
- }
-
- return iOutputIndex;
- }
- static stock DB::memset(aArray[], iValue, iSize = sizeof(aArray)) {
- new
- iAddress
- ;
-
- // Store the address of the array
- #emit LOAD.S.pri 12
- #emit STOR.S.pri iAddress
-
- // Convert the size from cells to bytes
- iSize *= 4;
-
- // Loop until there is nothing more to fill
- while (iSize > 0) {
- // I have to do this because the FILL instruction doesn't accept a dynamic number.
- if (iSize >= 4096) {
- #emit LOAD.S.alt iAddress
- #emit LOAD.S.pri iValue
- #emit FILL 4096
-
- iSize -= 4096;
- iAddress += 4096;
- } else if (iSize >= 1024) {
- #emit LOAD.S.alt iAddress
- #emit LOAD.S.pri iValue
- #emit FILL 1024
- iSize -= 1024;
- iAddress += 1024;
- } else if (iSize >= 256) {
- #emit LOAD.S.alt iAddress
- #emit LOAD.S.pri iValue
- #emit FILL 256
- iSize -= 256;
- iAddress += 256;
- } else if (iSize >= 64) {
- #emit LOAD.S.alt iAddress
- #emit LOAD.S.pri iValue
- #emit FILL 64
- iSize -= 64;
- iAddress += 64;
- } else if (iSize >= 16) {
- #emit LOAD.S.alt iAddress
- #emit LOAD.S.pri iValue
- #emit FILL 16
- iSize -= 16;
- iAddress += 16;
- } else {
- #emit LOAD.S.alt iAddress
- #emit LOAD.S.pri iValue
- #emit FILL 4
- iSize -= 4;
- iAddress += 4;
- }
- }
-
- // aArray is used, just not by its symbol name
- #pragma unused aArray
-
- return 1;
- }
- stock DB::LazyInitialize() {
- static
- bool:bIsInitialized = false
- ;
-
- if (bIsInitialized)
- return;
-
- bIsInitialized = true;
-
- #if defined HTTP
- HTTP(0x7FEDCBA0, HTTP_GET, !"spelsajten.net/sqlitei_version.php?version=097", "", !"DB_VersionCheckReponse");
- #endif
- }
- #if defined HTTP
- forward DB::VersionCheckReponse(iIndex, iResponseCode, const szResponse[]);
- public DB::VersionCheckReponse(iIndex, iResponseCode, const szResponse[]) {
- if (iResponseCode == 200) {
- if (strval(szResponse) != 1) {
- print(!"\n\n\n *******************************************************************");
- print( !" * There's a new version version of SQLite Improved available! *");
- print( !" * Please visit the topic at the SA-MP forums for the latest copy. *");
- print( !" * Alternatively, get it here: http://spelsajten.net/sqlitei.inc *");
- print( !" *******************************************************************\n\n\n");
- }
- }
- }
- #endif
- stock db_escape_string(szString[], const szEnclosing[] = "'", iSize = sizeof(szString)) {
- DB::LazyInitialize();
-
- new
- iPos
- ;
-
- while (-1 != (iPos = strfind(szString, szEnclosing, _, iPos))) {
- strins(szString, szEnclosing, iPos, iSize);
-
- iPos += 2;
- }
- }
- stock bool:db_is_persistent(DB:db) {
- return !!(_:db & 0x80000000);
- }
- stock bool:db_is_valid_persistent(DB:db) {
- new
- iIndex = (_:db & 0x7FFFFFFF)
- ;
-
- if ((0 <= iIndex < sizeof(gs_PersistentDatabases)) && gs_PersistentDatabases[iIndex][e_bIsUsed])
- return true;
-
- return false;
- }
- stock bool:db_is_table_exists(DB:db, const szTable[])
- {
- new
- DBResult:dbrResult
- ;
-
- format(gs_szBuffer, sizeof(gs_szBuffer), "SELECT name FROM sqlite_master WHERE type = 'table' AND tbl_name = '%s'", szTable);
-
- dbrResult = db_query(db, gs_szBuffer, false);
-
- if (db_num_fields(dbrResult)) {
- db_free_result(dbrResult);
-
- return true;
- }
-
- db_free_result(dbrResult);
-
- return false;
- }
- stock bool:db_rewind(DBResult:dbrResult) {
- if (dbrResult == DB::INVALID_RESULT) {
- DB::Notice("(db_rewind) Invalid result given.");
-
- return false;
- }
-
- return db_set_row_index(dbrResult, 0);
- }
- stock bool:db_exec(DB:db, const szQuery[]) {
- new
- DBResult:dbrResult = db_query(db, szQuery, false)
- ;
-
- if (dbrResult) {
- db_free_result(dbrResult);
-
- return true;
- }
-
- return false;
- }
- stock db_insert(DB:db, const szQuery[]) {
- new
- DBResult:dbrResult = db_query(db, szQuery, false)
- ;
-
- if (dbrResult) {
- db_free_result(dbrResult);
-
- return db_last_insert_rowid(db);
- }
-
- return 0;
- }
- stock db_get_struct_info(DB:db, {_, e_SQLITE3}:iOffset) {
- if (db_is_persistent(db)) {
- if (!db_is_valid_persistent(db)) {
- DB::Errorf("(db_get_struct_info) Invalid persistent database given (%04x%04x).", _:db >>> 16, _:db & 0xFFFF);
-
- return 0;
- }
-
- new iIndex = (_:db & 0x7FFFFFFF);
-
- db = gs_PersistentDatabases[iIndex][e_dbDatabase];
-
- if (!db) {
- DB::Errorf("(db_get_struct_info) Closed persistent database given (%04x%04x).", _:db >>> 16, _:db & 0xFFFF);
-
- return 0;
- }
- }
-
- new
- iAddress = db_get_mem_handle(db & DB:0x7FFFFFFF) - DB::GetAmxBaseRelative() + iOffset,
- iValue
- ;
-
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iValue
-
- return iValue;
- }
- stock db_set_struct_info(DB:db, {_, e_SQLITE3}:iOffset, iValue) {
- if (db_is_persistent(db)) {
- if (!db_is_valid_persistent(db)) {
- DB::Errorf("(db_set_struct_info) Invalid persistent database given (%04x%04x).", _:db >>> 16, _:db & 0xFFFF);
-
- return 0;
- }
-
- new iIndex = (_:db & 0x7FFFFFFF);
-
- db = gs_PersistentDatabases[iIndex][e_dbDatabase];
-
- if (!db) {
- DB::Errorf("(db_set_struct_info) Closed persistent database given (%04x%04x).", _:db >>> 16, _:db & 0xFFFF);
-
- return 0;
- }
- }
-
- new
- iAddress = db_get_mem_handle(db & DB:0x7FFFFFFF) - DB::GetAmxBaseRelative() + iOffset
- ;
-
- #emit LOAD.S.pri iValue
- #emit SREF.S.pri iAddress
- }
- stock bool:db_set_row_index(DBResult:dbrResult, iRow) {
- if (dbrResult == DB::INVALID_RESULT) {
- DB::Notice("(db_set_row_index) Invalid result given.");
-
- return false;
- }
-
- if (iRow < 0 || iRow >= db_num_rows(dbrResult))
- return false;
-
- new
- iAddress = db_get_result_mem_handle(dbrResult) - DB::GetAmxBaseRelative() + 16
- ;
-
- #emit LOAD.S.pri iRow
- #emit SREF.S.pri iAddress
-
- return true;
- }
- stock db_get_row_index(DBResult:dbrResult) {
- if (dbrResult == DB::INVALID_RESULT) {
- DB::Notice("(db_get_row_index) Invalid result given.");
-
- return 0;
- }
-
- new
- iAddress = db_get_result_mem_handle(dbrResult) - DB::GetAmxBaseRelative() + 16
- ;
-
- #emit LREF.S.pri iAddress
- #emit STACK 4
- #emit RETN
-
- return 0;
- }
- stock DB:db_open_persistent(const szName[]) {
- new
- DB:db,
- iIndex = -1
- ;
-
- for (new i = 0; i < sizeof(gs_PersistentDatabases); i++) {
- if (!gs_PersistentDatabases[i][e_bIsUsed]) {
- iIndex = i;
-
- break;
- }
- }
-
- if (iIndex == -1) {
- DB::Error("(db_open_persistent) Unable to find a free slot.");
-
- return DB:-1;
- }
-
- if (!(db = db_open(szName))) {
- DB::Error("(db_open_persistent) Unable to open the database.");
-
- return DB:-1;
- }
-
- gs_PersistentDatabases[iIndex][e_bIsUsed] = true;
- gs_PersistentDatabases[iIndex][e_dbDatabase] = db;
- gs_PersistentDatabases[iIndex][e_szName][0] = 0;
-
- if (gs_iClosePersistentTimer == -1)
- gs_iClosePersistentTimer = SetTimer("db_close_persistent", 0, false);
-
- strpack(gs_PersistentDatabases[iIndex][e_szName], szName, _:e_bIsUsed);
-
- DB::Debug("(db_open_persistent=%d) Opened new persistent DB.", iIndex);
-
- return DB:(iIndex | 0x80000000);
- }
- stock db_close_hook(DB:db) {
- new
- iIndex
- ;
-
- if (db_is_persistent(db)) {
- if (!db_is_valid_persistent(db)) {
- DB::Errorf("(db_close) Invalid persistent database given (%04x%04x).", _:db >>> 16, _:db & 0xFFFF);
-
- return;
- }
-
- iIndex = (_:db & 0x7FFFFFFF);
-
- if (gs_PersistentDatabases[iIndex][e_dbDatabase]) {
- db_close@(gs_PersistentDatabases[iIndex][e_dbDatabase]);
-
- gs_PersistentDatabases[iIndex][e_dbDatabase] = DB:0;
-
- DB::Debug("(db_close) Closed the DB for the persistent DB with index %d.", iIndex);
- } else {
- DB::Debug("(db_close) Would close the DB for the persistent DB with index %d, but it already is.", iIndex);
- }
- } else {
- db_close@(db);
- }
- }
- stock db_query_int(DB:db, const szQuery[], iField = 0) {
- new
- DBResult:dbrResult = db_query(db, szQuery, false)
- ;
- if (!dbrResult) {
- strunpack(gs_szBuffer, szQuery);
-
- DB::Warningf("(db_query_int) Query failed: \"%s\".", gs_szBuffer);
-
- return 0;
- }
- db_get_field(dbrResult, iField, gs_szBuffer, sizeof(gs_szBuffer) - 1);
- db_free_result(dbrResult);
- return strval(gs_szBuffer);
- }
- stock Float:db_query_float(DB:db, const szQuery[], iField = 0) {
- new
- DBResult:dbrResult = db_query(db, szQuery, false)
- ;
- if (!dbrResult) {
- strunpack(gs_szBuffer, szQuery);
-
- DB::Warningf("(db_query_float) Query failed: \"%s\".", gs_szBuffer);
-
- return 0.0;
- }
- db_get_field(dbrResult, iField, gs_szBuffer, sizeof(gs_szBuffer) - 1);
- db_free_result(dbrResult);
- return floatstr(gs_szBuffer);
- }
- stock db_is_result_freed(DBResult:dbrResult) {
- if (dbrResult == DB::INVALID_RESULT) {
- DB::Notice("(db_is_result_freed) Invalid result given.");
-
- return true;
- }
- return db_get_result_mem_handle(dbrResult) == 0;
- }
- stock bool:db_free_result_hook(DBResult:dbrResult) {
- if (dbrResult == DB::INVALID_RESULT) {
- DB::Notice("(db_free_result_hook) Invalid result given.");
-
- return false;
- }
-
- DB::Debug("(db_free_result) Freeing 0x%04x%04x.", _:dbrResult >>> 16, _:dbrResult & 0xFFFF);
-
- for (new i = gs_iAutoFreeResultsIndex; i--; ) {
- if (gs_adbrAutoFreeResults[i] == dbrResult) {
- gs_adbrAutoFreeResults[i] = DBResult:0;
-
- DB::Debug("(db_free_result) The result being freed was inside the autorelease pool.");
- }
- }
- new
- iFreeTestAddress = db_get_result_mem_handle(dbrResult) - DB::GetAmxBaseRelative() + 16,
- iData
- ;
-
- #emit LREF.S.pri iFreeTestAddress
- #emit STOR.S.pri iData
-
- if (iData != 0xFFFFFFFF) {
- new
- iResultAddress = db_get_result_mem_handle(dbrResult) - DB::GetAmxBaseRelative(),
- iAddress,
- iRows,
- iCols,
- iDataAddress,
- iOffset,
- iNullAddress
- ;
- #emit CONST.pri gs_szNull
- #emit STOR.S.pri iNullAddress
-
- iNullAddress += DB::GetAmxBaseRelative();
-
- iAddress = iResultAddress;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iRows
-
- iAddress += 4;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iCols
-
- iAddress += 4;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iDataAddress
-
- iDataAddress -= DB::GetAmxBaseRelative();
-
- iOffset = (iCols + iRows * iCols) * 4 - 4;
-
- while (iOffset >= 0) {
- iAddress = iDataAddress + iOffset;
-
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iAddress
-
- if (iAddress == iNullAddress) {
- iAddress = iDataAddress + iOffset;
-
- #emit CONST.pri 0
- #emit SREF.S.pri iAddress
- }
-
- iOffset -= 4;
- }
-
- db_free_result@(dbrResult);
-
- #emit CONST.pri 0xFFFFFFFF
- #emit SREF.S.pri iFreeTestAddress
-
- return true;
- } else {
- DB::Warning("(db_free_result) Attempted to free an already freed result; crash prevented.");
- }
-
- return false;
- }
- stock db_free_persistent(DB:db) {
- new
- iIndex
- ;
-
- if (!db_is_valid_persistent(db)) {
- DB::Errorf("(db_free_persistent) Invalid persistent database given (%04x%04x).", _:db >>> 16, _:db & 0xFFFF);
-
- return;
- }
-
- iIndex = (_:db & 0x7FFFFFFF);
-
- if (gs_PersistentDatabases[iIndex][e_dbDatabase]) {
- db_close@(gs_PersistentDatabases[iIndex][e_dbDatabase]);
-
- gs_PersistentDatabases[iIndex][e_dbDatabase] = DB:0;
-
- DB::Debug("(db_free_persistent:%d) Closed and freed the persistent DB.", iIndex);
- } else {
- DB::Debug("(db_free_persistent:%d) Freed the already closed persistent DB.", iIndex);
- }
-
- gs_PersistentDatabases[iIndex][e_bIsUsed] = false;
- }
- stock db_changes(DB:db) {
- DB::LazyInitialize();
-
- if (!db) {
- DB::Error("(db_changes) Invalid database handle given.");
-
- return 0;
- }
-
- return db_get_struct_info(db, sqlite3_iNumChanges);
- }
- stock db_begin_transaction(DB:db)
- return db_exec(db, !"BEGIN");
- stock db_end_transaction(DB:db)
- return db_exec(db, !"COMMIT");
- stock db_set_asynchronous(DB:db, bool:bSet = true) {
- db_set_synchronous(DB:db, bSet ? DB::SYNCHRONOUS_OFF : DB::SYNCHRONOUS_FULL);
- }
- stock bool:db_set_synchronous(DB:db, DB::e_SYNCHRONOUS_MODE:iValue) {
- if (0 <= _:iValue <= 2) {
- format(gs_szBuffer, sizeof(gs_szBuffer), "PRAGMA synchronous = %d", _:iValue);
-
- return db_exec(db, gs_szBuffer);
- } else
- return false;
- }
- stock bool:db_attach_memory_db(DB:db, const szName[]) {
- strunpack(gs_szBuffer, szName);
-
- db_escape_string(gs_szBuffer, "\"");
-
- format(gs_szBuffer, sizeof(gs_szBuffer), "ATTACH DATABASE ':memory:' AS \"%s\"", gs_szBuffer);
-
- return db_exec(db, gs_szBuffer);
- }
- stock bool:db_detach_memory_db(DB:db, const szName[]) {
- strunpack(gs_szBuffer, szName);
-
- db_escape_string(gs_szBuffer, "\"");
-
- format(gs_szBuffer, sizeof(gs_szBuffer), "DETACH DATABASE \"%s\"", gs_szBuffer);
-
- return db_exec(db, gs_szBuffer);
- }
- stock db_total_changes(DB:db) {
- DB::LazyInitialize();
- if (!db) {
- DB::Error("(db_changes) Invalid database handle given.");
- return 0;
- }
- return db_get_struct_info(db, sqlite3_iNumTotalChanges);
- }
- stock db_last_insert_rowid(DB:db) {
- DB::LazyInitialize();
-
- if (!db) {
- DB::Error("(db_last_insert_rowid) Invalid database handle given.");
-
- return 0;
- }
-
- return db_get_struct_info(db, sqlite3_iLastRowid);
- }
- stock db_field_is_null(DBResult:dbrResult, iField) {
- if (dbrResult == DB::INVALID_RESULT) {
- DB::Notice("(db_field_is_null) Invalid result given.");
-
- return false;
- }
-
- new
- iAddress = db_get_result_mem_handle(dbrResult) - DB::GetAmxBaseRelative(),
- iCols,
- iCurrentRow
- ;
-
- iAddress += 4;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iCols
-
- if (iField >= iCols)
- return true;
-
- iAddress += 8;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iCurrentRow
-
- iAddress -= 4;
-
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iAddress
-
- iAddress -= DB::GetAmxBaseRelative();
- iAddress += (iCols + iCols * iCurrentRow + iField) * 4;
-
- #emit LREF.S.pri iAddress
- #emit CONST.alt gs_szNull
- #emit SUB
- #emit STOR.S.pri iAddress
-
- iAddress -= DB::GetAmxBaseRelative();
-
- return !iAddress;
- }
- stock db_autofree_result(DBResult:dbrResult) {
- DB::LazyInitialize();
-
- if (dbrResult == DB::INVALID_RESULT) {
- DB::Notice("(db_autofree_result) Invalid result given.");
-
- return;
- }
-
- if (gs_iAutoFreeTimer == -1)
- gs_iAutoFreeTimer = SetTimer("db_drain_autofree_pool", 0, false);
-
- if (gs_iAutoFreeResultsIndex + 1 >= sizeof(gs_adbrAutoFreeResults)) {
- DB::Warning("(db_autofree_result) The autofree pool is full!");
-
- return;
- }
-
- gs_adbrAutoFreeResults[gs_iAutoFreeResultsIndex] = dbrResult;
-
- DB::Debug("(db_autofree_result) Will autofree 0x%04x%04x.", _:dbrResult >>> 16, _:dbrResult & 0xFFFF);
-
- gs_iAutoFreeResultsIndex++;
- }
- stock DBStatement:db_prepare(DB:db, const szQuery[]) {
- DB::LazyInitialize();
-
- new
- DBStatement:stStatement = DB::INVALID_STATEMENT,
- iPos,
- i,
- iLength
- ;
-
- if (!db) {
- DB::Error("(db_prepare) Invalid database handle given.");
-
- return DB::INVALID_STATEMENT;
- }
-
- // Pretty useless to prepare empty queries.
- if (!(iLength = strlen(szQuery))) {
- DB::Error("(db_prepare) Empty query.");
-
- return DB::INVALID_STATEMENT;
- }
-
- if (iLength char > DB::MAX_STATEMENT_SIZE) {
- DB::Error("(db_prepare) The query is too long. Increase DB_MAX_STATEMENT_SIZE.");
-
- return DB::INVALID_STATEMENT;
- }
-
- // Find an empty slot in gs_Statements.
- for (i = 0; i < sizeof(gs_Statements); i++) {
- if (!gs_Statements[DBStatement:i][e_dbDatabase]) {
- stStatement = DBStatement:i;
-
- break;
- }
- }
-
- if (stStatement == DB::INVALID_STATEMENT) {
- DB::Error("(db_prepare) Unable to find an empty slot for the statement. Increase DB_MAX_STATEMENTS.");
-
- return DB::INVALID_STATEMENT;
- }
-
- gs_Statements[stStatement][e_dbDatabase] = db;
- gs_Statements[stStatement][e_dbrResult] = DB::INVALID_RESULT;
- gs_Statements[stStatement][e_iFetchedRows] = 0;
-
- // Make sure no parameters are initialized.
- for (i = 0; i < DB::MAX_PARAMS; i++)
- gs_Statements[stStatement][e_aiParamTypes][i] = DB::TYPE_NONE;
-
- // Make sure no return fields are initialized.
- for (i = 0; i < DB::MAX_FIELDS; i++)
- gs_Statements[stStatement][e_aiFieldTypes][i] = DB::TYPE_NONE;
-
- iPos = -1;
- i = 0;
-
- // Find all parameters
- while (-1 != (iPos = strfind(szQuery, !"?", _, ++iPos))) {
- gs_Statements[stStatement][e_aiParamPositions][i] = iPos;
- gs_Statements[stStatement][e_aiParamLengths][i] = 1;
-
- if (++i >= DB::MAX_PARAMS) {
- DB::Error("(db_prepare) Parameter limit exceeded. Increase DB_MAX_PARAMS.");
-
- return DB::INVALID_STATEMENT;
- }
- }
-
- gs_Statements[stStatement][e_iParams] = i;
-
- gs_Statements[stStatement][e_szQuery][0] = 0;
-
- if (ispacked(szQuery)) {
- #if DB_DEBUG
- strunpack(gs_szBuffer, szQuery);
-
- DB::Debug("(db_prepare=%d) Preparing statement with %d params: %s", _:stStatement, i, gs_szBuffer);
- #endif
-
- strcat(gs_Statements[stStatement][e_szQuery], szQuery, DB::MAX_STATEMENT_SIZE);
- } else {
- DB::Debug("(db_prepare=%d) Preparing statement with %d params: %s", _:stStatement, i, szQuery);
-
- strpack(gs_Statements[stStatement][e_szQuery], szQuery, DB::MAX_STATEMENT_SIZE);
- }
-
- return stStatement;
- }
- stock bool:stmt_bind_value(&DBStatement:stStatement, iParam, DBDataType:iType, {Float, _}:...) {
- DB::LazyInitialize();
-
- new
- iLengthDiff,
- iLength,
- bool:bIsPacked,
- iNumArgs
- ;
-
- #emit LOAD.S.pri 8
- #emit SHR.C.pri 2
- #emit STOR.S.pri iNumArgs
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Warningf("(stmt_bind_value) Invalid statement passed (%d).", _:stStatement);
-
- return false;
- }
-
- if (iParam >= gs_Statements[stStatement][e_iParams]) {
- DB::Warningf("(stmt_bind_value) Parameter index larger than number of parameters (%d > %d).", iParam, gs_Statements[stStatement][e_iParams]);
-
- return false;
- }
-
- // Fill gs_szBuffer with the new contents.
- gs_szBuffer[0] = 0;
-
- switch (iType) {
- case DB::TYPE_NULL:
- goto default_case;
-
- case DB::TYPE_INT: {
- new
- iArgValue = getarg(3)
- ;
-
- if (iArgValue == cellmin)
- gs_szBuffer = !"-2147483648";
- else
- format(gs_szBuffer, sizeof(gs_szBuffer), "%d", getarg(3));
- }
-
- case DB::TYPE_UINT: {
- new
- iArgValue = getarg(3)
- ;
-
- if (!iArgValue) {
- gs_szBuffer = !"0";
- } else {
- new
- j = 11
- ;
-
- gs_szBuffer = "00000000000";
-
- while (iArgValue) {
- // gs_szBuffer[--j]
- #emit CONST.alt gs_szBuffer // alt = *gs_szBuffer
- #emit LOAD.S.pri j // pri = j
- #emit DEC.pri // pri -= 1
- #emit STOR.S.pri j // j = pri
- #emit IDXADDR // pri = alt + j * 4
- #emit PUSH.pri // Store for later
- // Now do an unsigned divide on iArgValue then use both the quotient and remainder!
- #emit LOAD.S.pri iArgValue // pri = iArgValue
- #emit CONST.alt 10
- #emit UDIV // pri = iArgValue / 10; alt = iArgValue % 10
- #emit STOR.S.pri iArgValue // iArgValue = pri
- #emit CONST.pri '0'
- #emit ADD // pri = '0' + (iArgValue % 10)
- #emit POP.alt // alt = gs_szBuffer[j]
- #emit STOR.I // gs_szBuffer[j] = pri
- }
-
- strpack(gs_szBuffer, gs_szBuffer[j]);
- }
- }
-
- case DB::TYPE_FLOAT:
- format(gs_szBuffer, sizeof(gs_szBuffer), "%f", getarg(3));
-
- case DB::TYPE_STRING: {
- new iSize = sizeof(gs_szBuffer) - 3;
-
- //strpack(dest[], const source[], maxlength = sizeof dest)
- #emit PUSH.S iSize
- #emit PUSH.S 24 // arg 3
- #emit PUSH.C gs_szBuffer
- #emit PUSH.C 12
- #emit SYSREQ.C strpack
- #emit STACK 16
-
- db_escape_string(gs_szBuffer, "'", sizeof(gs_szBuffer) - 1);
-
- strins(gs_szBuffer, !"'", 0);
- strcat(gs_szBuffer, !"'");
- }
-
- #if DB::USE_WHIRLPOOL
- case DB::TYPE_WP_HASH: {
- strcat(gs_szBuffer, "x'");
-
- DB::getstringarg(gs_szBuffer[2], 3, sizeof(gs_szBuffer) - 2);
-
- DB::WP_Hash(gs_szBuffer[2], sizeof(gs_szBuffer) - 2, gs_szBuffer[2]);
-
- strcat(gs_szBuffer, "'");
- }
- #endif
-
- case DB::TYPE_PLAYER_NAME: {
- new
- iPlayer = getarg(3)
- ;
-
- if (!(0 <= iPlayer < MAX_PLAYERS) || !IsPlayerConnected(iPlayer)) {
- DB::Warningf("(stmt_bind_value) Invalid player ID passed for DB::TYPE_PLAYER_NAME (%d).", iPlayer);
-
- strcat(gs_szBuffer, !"''");
- } else {
- gs_szBuffer[0] = '\'';
-
- GetPlayerName(iPlayer, gs_szBuffer[1], sizeof(gs_szBuffer) - 1);
-
- db_escape_string(gs_szBuffer[1], "'", sizeof(gs_szBuffer) - 1);
-
- strcat(gs_szBuffer, "'");
- }
- }
-
- case DB::TYPE_PLAYER_IP: {
- new
- iPlayer = getarg(3)
- ;
-
- if (!(0 <= iPlayer < MAX_PLAYERS) || !IsPlayerConnected(iPlayer)) {
- DB::Warningf("(stmt_bind_value) Invalid player ID passed for DB::TYPE_PLAYER_IP (%d).", iPlayer);
-
- strcat(gs_szBuffer, !"''");
- } else {
- gs_szBuffer[0] = '\'';
-
- GetPlayerIp(iPlayer, gs_szBuffer[1], sizeof(gs_szBuffer) - 1);
-
- db_escape_string(gs_szBuffer[1], "'", sizeof(gs_szBuffer) - 1);
-
- strcat(gs_szBuffer, "'");
- }
- }
-
- // http://www.sqlite.org/lang_keywords.html
- case DB::TYPE_IDENTIFIER: {
- bIsPacked = !!DB::isargpacked(3);
-
- if (!bIsPacked)
- gs_szBuffer[0] = '"';
-
- DB::getstringarg(gs_szBuffer[bIsPacked ? 0 : 1], 3, sizeof(gs_szBuffer) - 3);
-
- db_escape_string(gs_szBuffer[bIsPacked ? 0 : 1], "\"", sizeof(gs_szBuffer) - 1);
-
- if (bIsPacked)
- strins(gs_szBuffer, "\"", 0);
-
- strcat(gs_szBuffer, "\"");
- }
-
- case DB::TYPE_RAW_STRING:
- DB::getstringarg(gs_szBuffer, 3);
-
- case DB::TYPE_ARRAY: {
- // DB::CompressArray(const aiArray[], iSize = sizeof(aiArray), aiOutput[])
-
- if (iNumArgs != 5) {
- DB::Error("(stmt_bind_value) Invalid argument count. DB::TYPE_ARRAY requires an additional argument containing the array's length.");
-
- return false;
- }
-
- new
- iCompressedSize,
- i
- ;
-
- // Push the output array
- #emit PUSH.C gs_aiCompressBuffer
-
- // Push the size
- #emit LREF.S.pri 28 // 12 + 4 cells
- #emit PUSH.pri
-
- // Push the input array
- #emit PUSH.S 24
-
- // Push the argument count
- #emit PUSH.C 12
-
- // Push the return address
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
-
- // Call DB::CompressArray
- #emit CONST.pri DB_CompressArray
- #emit SCTRL 6
-
- // Store the return value
- #emit STOR.S.pri iCompressedSize
-
- iCompressedSize = (iCompressedSize + 3) / 4;
-
- gs_szBuffer[0] = 'x';
- gs_szBuffer[1] = '\'';
-
- if ((iCompressedSize << 3) + 1 < sizeof(gs_szBuffer)) {
- for (i = 0; i < iCompressedSize; i++)
- format(gs_szBuffer[2 + (i << 3)], sizeof(gs_szBuffer) - (2 + (i << 3)), "%01x%07x", gs_aiCompressBuffer[i] >>> 28, gs_aiCompressBuffer[i] & 0x0FFFFFFF);
- } else {
- strcat(gs_szBuffer, "00");
-
- DB::Errorf("(stmt_bind_value) Unable to compress the array; out of buffer size (has %d, needs %d).", sizeof(gs_szBuffer), (iCompressedSize << 3) + 2);
-
- return false;
- }
-
- strcat(gs_szBuffer, "'");
- }
-
- default: {
- default_case:
-
- strcat(gs_szBuffer, "NULL");
- }
- }
-
- iLength = strlen(gs_szBuffer);
-
- iLengthDiff = iLength - gs_Statements[stStatement][e_aiParamLengths][iParam];
-
- // Adjust the position of any params after the one being modified.
- for (new i = iParam + 1; i < gs_Statements[stStatement][e_iParams]; i++)
- gs_Statements[stStatement][e_aiParamPositions][i] += iLengthDiff;
-
- // Delete the old parameter from the query.
- strdel(gs_Statements[stStatement][e_szQuery], gs_Statements[stStatement][e_aiParamPositions][iParam], gs_Statements[stStatement][e_aiParamPositions][iParam] + gs_Statements[stStatement][e_aiParamLengths][iParam]);
-
- // Make sure we have enough space.
- if ((strlen(gs_Statements[stStatement][e_szQuery]) + iLength) char > DB::MAX_STATEMENT_SIZE) {
- DB::Error("(stmt_bind_value) Buffer overflow. Increase DB_MAX_STATEMENT_SIZE.");
-
- stmt_close(stStatement);
-
- return false;
- }
-
- // Insert the new parameter.
- strins(gs_Statements[stStatement][e_szQuery], gs_szBuffer, gs_Statements[stStatement][e_aiParamPositions][iParam], DB::MAX_STATEMENT_SIZE);
-
- #if DB_DEBUG
- if (ispacked(gs_szBuffer))
- strunpack(gs_szBuffer, gs_szBuffer);
-
- DB::Debug("(stmt_bind_value:%d) Inserted new value for parameter %d at %d: %s", _:stStatement, iParam, gs_Statements[stStatement][e_aiParamPositions][iParam], gs_szBuffer);
- #endif
-
- gs_Statements[stStatement][e_aiParamLengths][iParam] = iLength;
- gs_Statements[stStatement][e_aiParamTypes][iParam] = iType;
-
- return true;
- }
- stock stmt_bind_result_field(&DBStatement:stStatement, iField, DBDataType:iType, {Float, _}:...) {
- DB::LazyInitialize();
-
- new
- iAddress,
- iSize,
- iNumArgs
- ;
-
- #emit LOAD.S.pri 8
- #emit SHR.C.pri 2
- #emit STOR.S.pri iNumArgs
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Warningf("(stmt_bind_result_field) Invalid statement passed (%d).", _:stStatement);
- return;
- }
- if (iField < 0) {
- DB::Errorf("(stmt_bind_result_field) Negative field index (%d).", iField);
- return;
- }
-
- switch (iType) {
- case DB::TYPE_STRING,
- DB::TYPE_RAW_STRING,
- DB::TYPE_IDENTIFIER,
- DB::TYPE_ARRAY: {
- if (iNumArgs != 5) {
- DB::Error("(stmt_bind_result_field) Invalid number of arguments passed. Strings and arrays require an additional argument containing the string size.");
- return;
- }
-
- iSize = getarg(4);
- }
-
- case DB::TYPE_NONE: {
- gs_Statements[stStatement][e_aiFieldTypes][iField] = DB::TYPE_NONE;
-
- return;
- }
-
- default: {
- if (iNumArgs != 4) {
- DB::Error("(stmt_bind_result_field) Invalid number of arguments passed.");
- return;
- }
-
- iSize = 1;
- }
- }
-
- if (iField >= DB::MAX_FIELDS) {
- DB::Warningf("(stmt_bind_result_field) Field index larger than max number of fields (%d > %d). Increase DB_MAX_FIELDS.", iField, DB::MAX_FIELDS);
-
- return;
- }
-
- // Without this, STOR.S.pri doesn't seem to do what it should.
- iAddress = 0;
-
- #emit LOAD.S.pri 24
- #emit STOR.S.pri iAddress
-
- gs_Statements[stStatement][e_aiFieldTypes][iField] = iType;
- gs_Statements[stStatement][e_aiFieldAddresses][iField] = iAddress;
- gs_Statements[stStatement][e_aiFieldSizes][iField] = iSize;
-
- DB::Debug("(stmt_bind_result_field:%d) Bound result field %d (type %d) to variable 0x%04x%04x.", _:stStatement, iField, _:iType, iAddress >>> 16, iAddress & 0xFFFF);
- }
- stock bool:stmt_skip_row(&DBStatement:stStatement) {
- DB::LazyInitialize();
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Errorf("(stmt_skip_row) Invalid statement passed (%d).", _:stStatement);
-
- return false;
- }
-
- if (gs_Statements[stStatement][e_dbrResult] == DB::INVALID_RESULT) {
- if (!gs_Statements[stStatement][e_iFetchedRows])
- DB::Warning("(stmt_skip_row) Statement has no result.");
-
- return false;
- }
-
- gs_Statements[stStatement][e_iFetchedRows]++;
-
- if (!db_next_row(gs_Statements[stStatement][e_dbrResult])) {
- db_free_result(gs_Statements[stStatement][e_dbrResult]);
-
- gs_Statements[stStatement][e_dbrResult] = DB::INVALID_RESULT;
-
- DB::Debug("(stmt_skip_row:%d) Skipped row and freed result.", _:stStatement);
- } else {
- DB::Debug("(stmt_skip_row:%d) Skipped row.", _:stStatement);
- }
-
- return true;
- }
- stock bool:stmt_fetch_row(&DBStatement:stStatement) {
- DB::LazyInitialize();
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Errorf("(stmt_fetch_row) Invalid statement passed (%d).", _:stStatement);
-
- return false;
- }
-
- if (gs_Statements[stStatement][e_dbrResult] == DB::INVALID_RESULT) {
- if (!gs_Statements[stStatement][e_iFetchedRows])
- DB::Warning("(stmt_fetch_row) Statement has no result.");
-
- return false;
- }
- if (!stmt_rows_left(stStatement)) {
- DB::Debug("(stmt_fetch_row) No rows left.");
- return false;
- }
-
- if (!db_num_rows(gs_Statements[stStatement][e_dbrResult])) {
- DB::Debug("(stmt_fetch_row) Freed previous result.");
-
- db_free_result(gs_Statements[stStatement][e_dbrResult]);
-
- gs_Statements[stStatement][e_dbrResult] = DB::INVALID_RESULT;
-
- return false;
- }
-
- new
- iFields = db_num_fields(gs_Statements[stStatement][e_dbrResult]),
- iAddress,
- xValue,
- iCount
- ;
-
- if (iFields > DB::MAX_FIELDS) {
- DB::Warning("(stmt_bind_result_field) There are more fields returned than DB_MAX_FIELDS.");
-
- iFields = DB::MAX_FIELDS;
- }
-
- gs_Statements[stStatement][e_iFetchedRows]++;
-
- for (new iField = 0; iField < iFields; iField++) {
- if (gs_Statements[stStatement][e_aiFieldTypes][iField] == DB::TYPE_NONE)
- continue;
-
- iCount++;
-
- switch (gs_Statements[stStatement][e_aiFieldTypes][iField]) {
- case DB::TYPE_NONE,
- DB::TYPE_NULL:
- continue;
-
- case DB::TYPE_INT,
- DB::TYPE_UINT,
- DB::TYPE_FLOAT: {
- db_get_field(gs_Statements[stStatement][e_dbrResult], iField, gs_szBuffer, sizeof(gs_szBuffer) - 1);
-
- iAddress = gs_Statements[stStatement][e_aiFieldAddresses][iField];
- xValue = (gs_Statements[stStatement][e_aiFieldTypes][iField] != DB::TYPE_FLOAT) ? strval(gs_szBuffer) : _:floatstr(gs_szBuffer);
- #emit LOAD.S.pri xValue
- #emit SREF.S.pri iAddress
- }
-
- // Assumes the field is a string containing a player name.
- // Gives the ID of a connected play with that name, otherwise INVALID_PLAYER_ID.
- case DB::TYPE_PLAYER_NAME: {
- static
- s_szName[MAX_PLAYER_NAME]
- ;
-
- xValue = INVALID_PLAYER_ID;
-
- for (new i = 0, l = GetMaxPlayers(); i < l; i++) {
- if (!IsPlayerConnected(i))
- continue;
-
- GetPlayerName(i, s_szName, sizeof(s_szName));
- db_get_field(gs_Statements[stStatement][e_dbrResult], iField, gs_szBuffer, sizeof(gs_szBuffer) - 1);
-
- if (!strcmp(gs_szBuffer, s_szName, true)) {
- xValue = i;
-
- break;
- }
- }
-
- iAddress = gs_Statements[stStatement][e_aiFieldAddresses][iField];
- #emit LOAD.S.pri xValue
- #emit SREF.S.pri iAddress
- }
-
- case DB::TYPE_STRING,
- DB::TYPE_RAW_STRING,
- DB::TYPE_IDENTIFIER: {
- new
- DBResult:dbrResult,
- iSize
- ;
-
- static const
- sc_szFormatString[] = "%s"
- ;
-
- iAddress = gs_Statements[stStatement][e_aiFieldAddresses][iField];
- dbrResult = gs_Statements[stStatement][e_dbrResult];
- iSize = gs_Statements[stStatement][e_aiFieldSizes][iField];
-
- #emit PUSH.S iSize
- #emit PUSH.S iAddress
- #emit PUSH.S iField
- #emit PUSH.S dbrResult
- #emit PUSH.C 16
- #emit SYSREQ.C db_get_field
- #emit STACK 20
-
- // Fix a bug with UTF-8 characters
- // For example, 'ö' would become 0xFFFFFFC3 instead of 0xC3
- #emit PUSH.S iAddress
- #emit PUSH.C sc_szFormatString
- #emit PUSH.S iSize
- #emit PUSH.S iAddress
- #emit PUSH.C 16
- #emit SYSREQ.C format
- #emit STACK 20
- }
-
- case DB::TYPE_ARRAY: {
- // DecompressArray(const aiCompressedArray[], aiOutput[], iOutputSize = sizeof(aiOutput))
-
- db_get_field(gs_Statements[stStatement][e_dbrResult], iField, gs_szBuffer, sizeof(gs_szBuffer) - 1);
-
- format(gs_szBuffer, sizeof(gs_szBuffer), "%s", gs_szBuffer);
- strpack(gs_szBuffer, gs_szBuffer);
-
- new
- iOutputSize = gs_Statements[stStatement][e_aiFieldSizes][iField],
- iDecompressedCells
- ;
-
- iAddress = gs_Statements[stStatement][e_aiFieldAddresses][iField];
-
- // Push the output array size
- #emit PUSH.S iOutputSize
- // Push the output array
- #emit PUSH.S iAddress
- // Push the input array
- #emit PUSH.C gs_szBuffer
- // Push the argument count
- #emit PUSH.C 12
- // Push the return address
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
- // Call DB::DecompressArray
- #emit CONST.pri DB_DecompressArray
- #emit SCTRL 6
-
- // Store the return address
- #emit STOR.S.pri iDecompressedCells
-
- // If there are more cells in the array, fill them with 0
- if (iOutputSize > iDecompressedCells) {
- DB::Noticef("(stmt_fetch_row:%d) The array fetched from the DB is smaller than the destination array (%d > %d); the remaining slots with will be filled with 0.", _:stStatement, iOutputSize, iDecompressedCells);
-
- iAddress += iDecompressedCells * 4-4;
- iOutputSize = iOutputSize - iDecompressedCells;
-
- // DB::memset(aArray[], iValue, iSize = sizeof(aArray))
- #emit PUSH.S iOutputSize
- #emit PUSH.C 0
- #emit PUSH.S iAddress
- #emit PUSH.C 12
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
- #emit CONST.pri DB_memset
- #emit SCTRL 6
- }
-
-
- }
- }
- }
-
- if (!db_next_row(gs_Statements[stStatement][e_dbrResult])) {
- db_free_result(gs_Statements[stStatement][e_dbrResult]);
-
- gs_Statements[stStatement][e_dbrResult] = DB::INVALID_RESULT;
-
- DB::Debug("(stmt_fetch_row:%d) Fetched %d fields and freed the result.", _:stStatement, iCount);
- } else {
- DB::Debug("(stmt_fetch_row:%d) Fetched %d fields.", _:stStatement, iCount);
- }
-
- return true;
- }
- stock stmt_rows_left(&DBStatement:stStatement) {
- DB::LazyInitialize();
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Errorf("(stmt_rows_left) Invalid statement passed (%d).", _:stStatement);
-
- return 0;
- }
-
- if (gs_Statements[stStatement][e_dbrResult] == DB::INVALID_RESULT) {
- if (!gs_Statements[stStatement][e_iFetchedRows])
- DB::Warning("(stmt_rows_left) Statement has no result.");
-
- return 0;
- }
-
- return max(0, db_num_rows(gs_Statements[stStatement][e_dbrResult]) - gs_Statements[stStatement][e_iFetchedRows]);
- }
- stock bool:stmt_execute(&DBStatement:stStatement, bool:bStoreResult = true, bool:bAutoFreeResult = true) {
- DB::LazyInitialize();
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Errorf("(stmt_execute) Invalid statement passed (%d).", _:stStatement);
-
- return false;
- }
-
- if (!gs_Statements[stStatement][e_dbDatabase]) {
- DB::Errorf("(stmt_execute) Uninitialized statement passed (%d).", _:stStatement);
-
- return false;
- }
-
- // Make sure all parameters have been set.
- for (new i = 0; i < gs_Statements[stStatement][e_iParams]; i++) {
- if (gs_Statements[stStatement][e_aiParamTypes][i] == DB::TYPE_NONE) {
- DB::Errorf("(stmt_execute) Uninitialized parameter in statement (%d).", i);
-
- return false;
- }
- }
-
- // If old results are left, free them.
- if (gs_Statements[stStatement][e_dbrResult] != DB::INVALID_RESULT) {
- db_free_result(gs_Statements[stStatement][e_dbrResult]);
-
- gs_Statements[stStatement][e_dbrResult] = DB::INVALID_RESULT;
- }
-
- DB::Debug("(stmt_execute:%d) Executing statement.", _:stStatement);
-
- new
- DBResult:dbrResult = db_query(gs_Statements[stStatement][e_dbDatabase], gs_Statements[stStatement][e_szQuery], false)
- ;
-
- gs_Statements[stStatement][e_iFetchedRows] = 0;
- gs_Statements[stStatement][e_bAutoFreeResult] = bAutoFreeResult;
-
- if (dbrResult == DB::INVALID_RESULT)
- return false;
-
- if (!bStoreResult)
- db_free_result(dbrResult);
- else {
- gs_Statements[stStatement][e_dbrResult] = dbrResult;
-
- if (bAutoFreeResult && gs_iFreeStatementResultsTimer == -1)
- gs_iFreeStatementResultsTimer = SetTimer("db_free_stmt_results", 1, false);
- }
-
- return true;
- }
- stock stmt_free_result(&DBStatement:stStatement) {
- DB::LazyInitialize();
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Noticef("(stmt_free_result) Invalid statement passed (%d).", _:stStatement);
-
- return;
- }
-
- gs_Statements[stStatement][e_iFetchedRows] = 0;
-
- if (gs_Statements[stStatement][e_dbrResult] != DB::INVALID_RESULT) {
- db_free_result(gs_Statements[stStatement][e_dbrResult]);
-
- gs_Statements[stStatement][e_dbrResult] = DB::INVALID_RESULT;
-
- DB::Debug("(stmt_free_result:%d) Freed result.", _:stStatement);
- } else {
- DB::Debug("(stmt_free_result:%d) Nothing to free.", _:stStatement);
- }
- }
- stock stmt_close(&DBStatement:stStatement) {
- DB::LazyInitialize();
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Noticef("(stmt_close) Invalid statement passed (%d).", _:stStatement);
-
- return;
- }
-
- if (gs_Statements[stStatement][e_dbrResult] != DB::INVALID_RESULT)
- db_free_result(gs_Statements[stStatement][e_dbrResult]);
-
- gs_Statements[stStatement][e_dbDatabase] = DB:0;
-
- DB::Debug("(stmt_close:%d) Closed statement.", _:stStatement);
-
- stStatement = DB::INVALID_STATEMENT;
- }
- stock stmt_autoclose(&DBStatement:stStatement) {
- DB::LazyInitialize();
-
- if (stStatement == DB::INVALID_STATEMENT || !(0 <= _:stStatement < sizeof(gs_Statements))) {
- DB::Noticef("(stmt_autoclose) Invalid statement passed (%d).", _:stStatement);
-
- return;
- }
-
- if (gs_iAutoFreeTimer == -1)
- gs_iAutoFreeTimer = SetTimer("db_drain_autofree_pool", 0, false);
-
- if (gs_iAutoCloseStatementsIndex + 1 >= sizeof(gs_astAutoCloseStatements)) {
- DB::Warning("(stmt_autoclose) The autoclose pool is full!");
-
- return;
- }
-
- gs_astAutoCloseStatements[gs_iAutoCloseStatementsIndex] = stStatement;
-
- gs_iAutoCloseStatementsIndex++;
-
- DB::Debug("(stmt_autoclose:%d) Will autoclose statement.", _:stStatement);
- }
- stock DBResult:db_query_hook(iTagOf3 = tagof(_bAutoRelease), DB:db, const szQuery[], {bool, DBDataType}:_bAutoRelease = true, {DBDataType, QQPA}:...) {
- new
- iIndex,
- iNumArgs,
- iStaticArgs = 4,
- bool:bAutoRelease = true
- ;
-
- #emit LOAD.S.pri 8
- #emit SHR.C.pri 2
- #emit STOR.S.pri iNumArgs
-
- DB::LazyInitialize();
-
- if (iTagOf3 == tagof(DBDataType:)) {
- iStaticArgs = 3;
- } else {
- bAutoRelease = _bAutoRelease;
- }
-
- if (db_is_persistent(db)) {
- if (!db_is_valid_persistent(db)) {
- DB::Errorf("(db_query) Invalid persistent database given (%04x%04x).", _:db >>> 16, _:db & 0xFFFF);
-
- return DB::INVALID_RESULT;
- }
-
- iIndex = _:db & 0x7FFFFFFF;
-
- if (!gs_PersistentDatabases[iIndex][e_dbDatabase]) {
- if (!(gs_PersistentDatabases[iIndex][e_dbDatabase] = db_open(gs_PersistentDatabases[iIndex][e_szName]))) {
- DB::Errorf("(db_query) Failed to lazily open the database.");
-
- return DB::INVALID_RESULT;
- }
-
- if (gs_iClosePersistentTimer == -1)
- gs_iClosePersistentTimer = SetTimer("db_close_persistent", 0, false);
- }
-
- db = gs_PersistentDatabases[iIndex][e_dbDatabase];
- }
-
- #if DB_DEBUG
- if (ispacked(szQuery)) {
- strunpack(gs_szBuffer, szQuery);
-
- DB::Debug("(db_query) Running query: %s", gs_szBuffer);
- } else {
- DB::Debug("(db_query) Running query: %s", szQuery);
- }
- #endif
-
- new
- DBResult:dbrResult
- ;
-
- if (iNumArgs > iStaticArgs) {
- if ((iNumArgs - iStaticArgs) & 0b1) {
- DB::Error("(db_query) Invalid argument count. Did you forget to use the correct prefix on the arguments (e.g. STRING:somestring)?");
-
- return DB::INVALID_RESULT;
- }
-
- new DBStatement:stmt = db_prepare(db, szQuery);
-
- for (new i = iStaticArgs + 1; i < iNumArgs; i += 2) {
- // Load the address of argument <i>
- #emit LCTRL 5
- #emit LOAD.S.alt i
- #emit SHL.C.alt 2
- #emit ADD
- #emit ADD.C 12
- #emit MOVE.alt
- #emit LOAD.I
- #emit PUSH.pri
- #emit PUSH.alt
-
- if (i == 4) {
- // Load the address of argument <i - 1>
- #emit POP.pri
- #emit ADD.C 0xFFFFFFFC
- #emit LOAD.I
- #emit PUSH.pri
- } else {
- // Load the address of argument <i - 1>
- #emit POP.pri
- #emit ADD.C 0xFFFFFFFC
- #emit LOAD.I
- #emit LOAD.I
- #emit PUSH.pri
- }
-
- // Push the param index: (i - iStaticArgs) / 2
- #emit LOAD.S.pri i
- #emit LOAD.S.alt iStaticArgs
- #emit SUB
- #emit SHR.C.pri 1
- #emit PUSH.pri
- #emit PUSH.ADR stmt
-
- // Push the argument count
- #emit PUSH.C 16
-
- // Push the return address
- #emit LCTRL 6
- #emit ADD.C 28
- #emit PUSH.pri
-
- // Call stmt_bind_value
- #emit CONST.pri stmt_bind_value
- #emit SCTRL 6
- }
-
- dbrResult = db_query@(db, gs_Statements[stmt][e_szQuery]);
-
- stmt_close(stmt);
- } else {
- dbrResult = db_query@(db, szQuery);
- }
-
- if (dbrResult) {
- if (bAutoRelease)
- db_autofree_result(dbrResult);
-
- new
- iResultAddress = db_get_result_mem_handle(dbrResult) - DB::GetAmxBaseRelative(),
- iAddress,
- iRows,
- iCols,
- iDataAddress,
- iOffset
- ;
-
- iAddress = iResultAddress;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iRows
-
- iAddress += 4;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iCols
-
- iAddress += 4;
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iDataAddress
-
- iDataAddress -= DB::GetAmxBaseRelative();
-
- iOffset = (iCols + iRows * iCols) * 4 - 4;
-
- while (iOffset >= 0) {
- iAddress = iDataAddress + iOffset;
-
- #emit LREF.S.pri iAddress
- #emit STOR.S.pri iAddress
-
- if (!iAddress) {
- new
- iAmxBaseRelative = DB::GetAmxBaseRelative()
- ;
-
- iAddress = iDataAddress + iOffset;
-
- #emit CONST.pri gs_szNull
- #emit LOAD.S.alt iAmxBaseRelative
- #emit ADD
- #emit SREF.S.pri iAddress
- }
-
- iOffset -= 4;
- }
- }
-
- return dbrResult;
- }
- stock db_get_field_hook(DBResult:dbresult, field, result[], maxlength = sizeof(result)) {
- new retval = db_get_field(dbresult, field, result, maxlength);
-
- format(result, maxlength, "%s", result);
-
- return retval;
- }
- stock db_get_field_assoc_hook(DBResult:dbresult, const field[], result[], maxlength = sizeof(result)) {
- new retval = db_get_field_assoc(dbresult, field, result, maxlength);
-
- format(result, maxlength, "%s", result);
-
- return retval;
- }
- stock bool:db_dump_table(DB:db, const szTable[], const szFilename[]) {
- static
- s_szColumnName[256]
- ;
- new
- DBResult:dbrResult,
- File:fp
- ;
-
- if (strfind(szTable, "\"") != -1 || strfind(szTable, "'") != -1) {
- DB::Error("(db_dump_table) Invalid table name given.");
-
- return false;
- }
-
- if (!(fp = fopen(szFilename, io_write))) {
- DB::Error("(db_dump_table) Failed to open the file.");
-
- return false;
- }
-
- format(gs_szBuffer, sizeof(gs_szBuffer), "SELECT sql FROM sqlite_master WHERE tbl_name = '%s'", szTable);
-
- dbrResult = db_query(db, gs_szBuffer);
-
- if (!dbrResult) {
- DB::Error("(db_dump_table) Failed to get the table sql.");
-
- return false;
- }
-
- db_get_field(dbrResult, 0, gs_szBuffer, sizeof(gs_szBuffer) - 1);
-
- if (strlen(gs_szBuffer) >= sizeof(gs_szBuffer) - 2) {
- DB::Error("(db_dump_table) Buffer overflow.");
-
- fwrite(fp, "\nBUFFER OVERFLOW");
- fclose(fp);
-
- db_free_result(dbrResult);
-
- return false;
- }
-
- fwrite(fp, gs_szBuffer);
- fwrite(fp, ";\n\n\n");
-
- db_free_result(dbrResult);
-
- format(gs_szBuffer, sizeof(gs_szBuffer), "PRAGMA table_info(%s)", szTable);
-
- dbrResult = db_query(db, gs_szBuffer, false);
-
- if (!dbrResult) {
- DB::Error("(db_dump_table) Failed to get table info.");
-
- return false;
- }
-
- gs_szBuffer = "SELECT 'INSERT INTO ";
- strcat(gs_szBuffer, szTable);
- strcat(gs_szBuffer, " VALUES('");
-
- if (db_num_rows(dbrResult)) do {
- db_get_field(dbrResult, 1, s_szColumnName, sizeof(s_szColumnName) - 1);
-
- if (db_get_row_index(dbrResult) > 0)
- strcat(gs_szBuffer, " || ', '");
-
- strcat(gs_szBuffer, " || quote(");
- strcat(gs_szBuffer, s_szColumnName);
- strcat(gs_szBuffer, ")");
- } while (db_next_row(dbrResult));
-
- strcat(gs_szBuffer, " || ');' FROM ");
- strcat(gs_szBuffer, szTable);
-
- db_free_result(dbrResult);
-
- dbrResult = db_query(db, gs_szBuffer);
-
- fwrite(fp, "BEGIN;\n\n");
-
- if (db_num_rows(dbrResult)) do {
- db_get_field(dbrResult, 0, gs_szBuffer, sizeof(gs_szBuffer) - 1);
-
- if (strlen(gs_szBuffer) >= sizeof(gs_szBuffer) - 2) {
- DB::Error("(db_dump_table) Buffer overflow.");
-
- fwrite(fp, "\nBUFFER OVERFLOW");
- fclose(fp);
-
- db_free_result(dbrResult);
-
- return false;
- }
-
- fwrite(fp, gs_szBuffer);
- fwrite(fp, "\n");
- } while (db_next_row(dbrResult));
-
- fwrite(fp, "\nCOMMIT;\n");
-
- db_free_result(dbrResult);
-
- fclose(fp);
-
- return true;
- }
- stock DBResult:db_print_result(DBResult:dbrResult, iMaxFieldLength = 40) {
- DB::LazyInitialize();
-
- const
- MAX_ROWS = 100,
- MAX_FIELDS = 20,
- MAX_FIELD_LENGTH = 88
- ;
-
- static
- s_aaszFields[MAX_ROWS + 1][MAX_FIELDS][MAX_FIELD_LENGTH char],
- s_aiFieldMaxLength[MAX_FIELDS]
- ;
-
- static const
- szcSpacePadding[MAX_FIELD_LENGTH] = {' ', ...},
- szcDashPadding[MAX_FIELD_LENGTH] = {'-', ...}
- ;
-
- if (iMaxFieldLength == -1)
- iMaxFieldLength = MAX_FIELD_LENGTH;
-
- print(!" ");
- print(!"Query result:");
-
- if (!dbrResult)
- print(!"\t- Invalid result.");
- else if (!db_num_rows(dbrResult))
- print(!"\t- No rows.");
- else {
- new
- iRow = 0,
- iRows,
- iFields = db_num_fields(dbrResult),
- iField,
- iLength,
- bool:bHasMoreLines,
- iPos,
- iNextPos,
- iRowIndex = db_get_row_index(dbrResult)
- ;
-
- db_set_row_index(dbrResult, 0);
-
- if (iMaxFieldLength > MAX_FIELD_LENGTH) {
- printf("\t- The longest possible field length is %d. Change MAX_FIELD_LENGTH for larger values.", MAX_FIELD_LENGTH);
-
- iMaxFieldLength = MAX_FIELD_LENGTH;
- }
-
- if (iFields > MAX_FIELDS) {
- printf("\t- There are %d, but only %d of them will be visible.", iFields, MAX_FIELDS);
- print(!"\t- Increase MAX_FIELDS if you want to see all fields.");
-
- iFields = MAX_FIELDS;
- }
-
- for (iField = 0; iField < iFields; iField++) {
- db_field_name(dbrResult, iField, gs_szBuffer, iMaxFieldLength - 1);
-
- iPos = 0;
-
- while (-1 != (iPos = strfind(gs_szBuffer, "\r", _, iPos)))
- gs_szBuffer[iPos] = ' ';
-
- iPos = 0;
-
- while (-1 != (iPos = strfind(gs_szBuffer, "\t", _, iPos))) {
- gs_szBuffer[iPos] = ' ';
-
- strins(gs_szBuffer, " ", iPos, iMaxFieldLength);
-
- iPos += 4;
- }
-
- iPos = 0;
- do {
- iNextPos = strfind(gs_szBuffer, "\n", _, iPos) + 1;
- if (!iNextPos)
- iLength = strlen(gs_szBuffer[iPos]);
- else
- iLength = iNextPos - iPos - 1;
- s_aiFieldMaxLength[iField] = min(iMaxFieldLength, max(iLength, s_aiFieldMaxLength[iField]));
- } while ((iPos = iNextPos));
-
- strpack(s_aaszFields[0][iField], gs_szBuffer, iMaxFieldLength char);
- }
-
- do {
- for (iField = 0; iField < iFields; iField++) {
- if (db_field_is_null(dbrResult, iField))
- gs_szBuffer = "NULL";
- else
- db_get_field(dbrResult, iField, gs_szBuffer, iMaxFieldLength - 1);
-
- iPos = 0;
-
- while (-1 != (iPos = strfind(gs_szBuffer, "\r", _, iPos)))
- gs_szBuffer[iPos] = ' ';
-
- iPos = 0;
-
- while (-1 != (iPos = strfind(gs_szBuffer, "\t", _, iPos))) {
- gs_szBuffer[iPos] = ' ';
-
- strins(gs_szBuffer, " ", iPos, iMaxFieldLength);
-
- iPos += 4;
- }
-
- iPos = 0;
- do {
- iNextPos = strfind(gs_szBuffer, "\n", _, iPos) + 1;
- if (!iNextPos)
- iLength = strlen(gs_szBuffer[iPos]);
- else
- iLength = iNextPos - iPos - 1;
- s_aiFieldMaxLength[iField] = min(iMaxFieldLength, max(iLength, s_aiFieldMaxLength[iField]));
- } while ((iPos = iNextPos));
- strpack(s_aaszFields[iRow + 1][iField], gs_szBuffer, iMaxFieldLength char);
- }
-
- if (++iRow >= MAX_ROWS) {
- iRows = iRow;
-
- while (db_next_row(dbrResult))
- iRows++;
-
- printf("\t- Only the first %d rows are displayed; there are %d remaining.", MAX_ROWS, iRows);
-
- break;
- }
- } while (db_next_row(dbrResult));
-
- print(!" ");
-
- for (iRows = iRow, iRow = 0; iRow <= iRows; iRow++) {
- do {
- bHasMoreLines = false;
-
- gs_szBuffer[0] = 0;
-
- for (iField = 0; iField < iFields; iField++) {
- if (iField)
- strcat(gs_szBuffer, " | ");
-
- iLength = strlen(gs_szBuffer);
-
- if (-1 != (iPos = strfind(s_aaszFields[iRow][iField], "\n"))) {
- strunpack(gs_szBuffer[iLength], s_aaszFields[iRow][iField], strlen(gs_szBuffer[iLength]) + iPos + 1);
-
- strdel(s_aaszFields[iRow][iField], 0, iPos + 1);
-
- bHasMoreLines = true;
- } else {
- if (s_aaszFields[iRow][iField]{0}) {
- strunpack(gs_szBuffer[iLength], s_aaszFields[iRow][iField], sizeof(gs_szBuffer) - iLength);
-
- s_aaszFields[iRow][iField]{0} = 0;
- }
- }
-
- iLength = strlen(gs_szBuffer[iLength]);
-
- strcat(gs_szBuffer, szcSpacePadding, strlen(gs_szBuffer) + (s_aiFieldMaxLength[iField] - iLength + 1));
- }
-
- if (bHasMoreLines)
- printf("\t| %s |", gs_szBuffer);
-
- } while (bHasMoreLines);
-
- if (iRow == 0) {
- printf("\t/ %s \\", gs_szBuffer);
- } else {
- printf("\t| %s |", gs_szBuffer);
- }
-
- if (iRow == iRows) {
- gs_szBuffer[0] = 0;
-
- for (iField = 0; iField < iFields; iField++) {
- if (iField)
- strcat(gs_szBuffer, "---");
-
- strcat(gs_szBuffer, szcDashPadding, strlen(gs_szBuffer) + s_aiFieldMaxLength[iField] + 1);
- }
- printf("\t\\-%s-/", gs_szBuffer);
- } else {
- gs_szBuffer[0] = 0;
-
- for (iField = 0; iField < iFields; iField++) {
- if (iField)
- strcat(gs_szBuffer, "-|-");
-
- strcat(gs_szBuffer, szcDashPadding, strlen(gs_szBuffer) + s_aiFieldMaxLength[iField] + 1);
- }
-
- printf("\t|-%s-|", gs_szBuffer);
- }
- }
-
- db_set_row_index(dbrResult, iRowIndex);
- }
-
- print(!" ");
-
- return dbrResult;
- }
- stock db_print_query(DB:db, const szQuery[], iMaxFieldLength = 40) {
- new
- DBResult:dbrResult = db_query(db, szQuery, false)
- ;
-
- db_print_result(dbrResult, iMaxFieldLength);
-
- db_free_result(dbrResult);
- }
- forward db_drain_autofree_pool();
- public db_drain_autofree_pool() {
- DB::LazyInitialize();
-
- gs_iAutoFreeTimer = -1;
-
- for (new i = gs_iAutoFreeResultsIndex; i--; ) {
- if (gs_adbrAutoFreeResults[i]) {
- new DBResult:result = gs_adbrAutoFreeResults[i];
-
- gs_adbrAutoFreeResults[i] = DB::INVALID_RESULT;
-
- DB::Debug("(db_drain_autofree_pool) Autofreeing 0x%04x%04x", _:result >>> 16, _:result & 0xFFFF);
-
- db_free_result_hook(result);
- }
- }
-
- gs_iAutoFreeResultsIndex = 0;
- for (new i = gs_iAutoCloseStatementsIndex; i--; ) {
- if (gs_astAutoCloseStatements[i]) {
- DB::Debug("(db_drain_autofree_pool) Autoclosing statement %d.", _:gs_astAutoCloseStatements[i]);
-
- stmt_close(gs_astAutoCloseStatements[i]);
- }
- }
-
- gs_iAutoCloseStatementsIndex = 0;
- }
- forward db_free_stmt_results();
- public db_free_stmt_results() {
- gs_iFreeStatementResultsTimer = -1;
-
- for (new DBStatement:i = DBStatement:0; _:i < sizeof(gs_Statements); i++) {
- if (gs_Statements[i][e_dbDatabase]
- && gs_Statements[i][e_bAutoFreeResult]
- && gs_Statements[i][e_dbrResult] != DB::INVALID_RESULT) {
- new DBResult:result = gs_Statements[i][e_dbrResult];
-
- gs_Statements[i][e_dbrResult] = DB::INVALID_RESULT;
-
- DB::Debug("(db_free_stmt_results) Freeing 0x%04x%04x for %d.", _:result >>> 16, _:result & 0xFFFF, _:i);
-
- db_free_result_hook(result);
- }
- }
- }
- forward db_close_persistent();
- public db_close_persistent() {
- gs_iClosePersistentTimer = -1;
-
- for (new i = 0; i < sizeof(gs_PersistentDatabases); i++) {
- if (gs_PersistentDatabases[i][e_bIsUsed] && gs_PersistentDatabases[i][e_dbDatabase]) {
- db_close@(gs_PersistentDatabases[i][e_dbDatabase]);
-
- gs_PersistentDatabases[i][e_dbDatabase] = DB:0;
- }
- }
- }
- static stock DB::FindMSB(iInput) {
- // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
-
- static const
- s_aiDeBruijnBitPositionsPacked[32 char] = {
- 0x0A010900,
- 0x1D02150D,
- 0x12100E0B,
- 0x1E031916,
- 0x1C140C08,
- 0x0718110F,
- 0x06171B13,
- 0x1F04051A
- }
- ;
-
- if (iInput) {
- #emit LOAD.S.pri iInput
- #emit MOVE.alt
- #emit SHR.C.alt 1
- #emit OR
- #emit MOVE.alt
- #emit SHR.C.alt 2
- #emit OR
- #emit MOVE.alt
- #emit SHR.C.alt 4
- #emit OR
- #emit MOVE.alt
- #emit SHR.C.alt 8
- #emit OR
- #emit MOVE.alt
- #emit SHR.C.alt 16
- #emit OR
- #emit CONST.alt 0x07C4ACDD
- #emit UMUL
- #emit SHR.C.pri 27
- #emit ADD.C s_aiDeBruijnBitPositionsPacked
- #emit LODB.I 1
- #emit RETN
- }
-
- return -1;
- }
- static stock DB::getstringarg(dest[], arg, len = sizeof (dest)) {
- // Get the address of the previous function's stack. First get the index of
- // the argument required.
- #emit LOAD.S.pri arg
- // Then convert that number to bytes from cells.
- #emit SMUL.C 4
- // Get the previous function's frame. Stored in variable 0 (in the current
- // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
- // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
- // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
- // count (in C pointer speak).
- #emit LOAD.S.alt 0
- // Add the frame pointer to the argument offset in bytes.
- #emit ADD
- // Add 12 to skip over the function header.
- #emit ADD.C 12
- // Load the address stored in the specified address.
- #emit LOAD.I
- // Push the length for "strcat".
- #emit PUSH.S len
- // Push the address we just determined was the source.
- #emit PUSH.pri
- // Load the address of the destination.
- #emit LOAD.S.alt dest
- // Blank the first cell so "strcat" behaves like "strcpy".
- #emit CONST.pri 0
- // Store the loaded number 0 to the loaded address.
- #emit STOR.I
- // Push the loaded address.
- #emit PUSH.alt
- // Push the number of parameters passed (in bytes) to the function.
- #emit PUSH.C 12
- // Call the function.
- #emit SYSREQ.C strcat
- // Restore the stack to its level before we called this native.
- #emit STACK 16
- }
- static stock DB::setstringarg(iArg, const szValue[], iLength = sizeof(szValue)) {
- new
- iAddress
- ;
- // Get the address of the previous function's stack. First get the index of
- // the argument required.
- #emit LOAD.S.pri iArg
- // Then convert that number to bytes from cells.
- #emit SMUL.C 4
- // Get the previous function's frame.
- #emit LOAD.S.alt 0
- // Add the frame pointer to the argument offset in bytes.
- #emit ADD
- // Add 12 to skip over the function header.
- #emit ADD.C 12
- // Load the address stored in the specified address.
- #emit LOAD.I
- #emit STOR.S.PRI iAddress
- // Push the length (last argument first)
- #emit PUSH.S iLength
- // Push the new value (source) szValue
- #emit PUSH.S szValue
- // Blank out the first cell of the argument
- #emit CONST.pri 0
- #emit SREF.S.pri iAddress
-
- // Push the destination
- #emit PUSH.S iAddress
- // Push the number of parameters passed (in bytes) to the function.
- #emit PUSH.C 12
-
- // Call the function.
- #emit SYSREQ.C strcat
-
- // Restore the stack to its level before we called this native.
- #emit STACK 16
- }
- // Pretty much Y_Less's va_strlen function
- static stock DB::isargpacked(iArg) {
- // Get the length of the string at the given position on the previous
- // function's stack (convenience function).
- // Get the address of the previous function's stack. First get the index of
- // the argument required.
- #emit LOAD.S.pri iArg
- // Then convert that number to bytes from cells.
- #emit SMUL.C 4
- // Get the previous function's frame. Stored in variable 0 (in the current
- // frame). Parameters are FRM+n+12, locals are FRM-n, previous frame is
- // FRM+0, return address is FRM+4, parameter count is FRM+8. We could add
- // checks that "arg * 4 < *(*(FRM + 0) + 8)", for the previous frame parameter
- // count (in C pointer speak).
- #emit LOAD.S.alt 0
- // Add the frame pointer to the argument offset in bytes.
- #emit ADD
- // Add 12 to skip over the function header.
- #emit ADD.C 12
- // Load the address stored in the specified address.
- #emit LOAD.I
- // Push the address we just determined was the source.
- #emit PUSH.pri
- // Push the number of parameters passed (in bytes) to the function.
- #emit PUSH.C 4
- // Call the function.
- #emit SYSREQ.C ispacked
- // Restore the stack to its level before we called this native.
- #emit STACK 8
- #emit RETN
- // Never called.
- return 0;
- }
- stock DB::GetAmxBaseRelative() {
- static
- s_iAmxBaseRelative = 0
- ;
-
- if (!s_iAmxBaseRelative) {
- s_iAmxBaseRelative = DB::GetAmxBase();
- #emit LCTRL 1
- #emit LOAD.alt s_iAmxBaseRelative
- #emit ADD
- #emit STOR.pri s_iAmxBaseRelative
- }
-
- return s_iAmxBaseRelative;
- }
- // By Zeex!
- // Returns the AMX base address i.e. amx->base.
- static stock DB::dummy() {
- return 0;
- }
- stock DB::GetAmxBase() {
- static amx_base = 0; // cached
- if (amx_base == 0) {
- new cod, dat;
- #emit lctrl 0
- #emit stor.s.pri cod
- #emit lctrl 1
- #emit stor.s.pri dat
- // Get code section start address relative to data.
- new code_start = cod - dat;
- // Get address of DB::dummy().
- new fn_addr;
- #emit const.pri DB_dummy
- #emit stor.s.pri fn_addr
- // Get absolute address from the CALL instruction.
- new fn_addr_reloc, call_addr;
- DB_dummy();
- #emit lctrl 6
- #emit stor.s.pri call_addr
- call_addr = call_addr - 12 + code_start;
- #emit lref.s.pri call_addr
- #emit stor.s.pri fn_addr_reloc
- amx_base = fn_addr_reloc - fn_addr - cod;
- }
- return amx_base;
- }
- // phys_memory.inc
- static stock AbsToRel(addr) {
- new dat;
- #emit lctrl 1
- #emit stor.s.pri dat
- return addr - (GetAmxBaseAddress() + dat);
- }
- // This function has a bug in older amx_assembly versions
- static stock WritePhysMemoryCell_(addr, what) {
- new rel_addr = AbsToRel(addr);
- #emit load.s.pri what
- #emit sref.s.pri rel_addr
- #emit stack 4
- #emit retn
- return 0; // make compiler happy
- }
- // Hook db_get_field
- // This is done lastly because the fixed function isn't needed within SQLitei
- #define db_get_field db_get_field_hook
- #define db_get_field_assoc db_get_field_assoc_hook
|