# SDQL2 And You Or: how to not break the server [ToC] {%hackmd @ZeWaka/dark-theme %} ## How SDQL works Gonna preface this with the warning that SDQL is VERY easy to break the server with. Be careful and ask someone who knows SDQL before running a query if unsure. SDQL is an SQL query-type system that allows for mass selection, modification, and deletion of types across the server. Anything with the (CM13) label is exclusive to Colonial Marines. ## Individual Parts of SDQL ### Actions * SELECT * This will produce a list of the selected type in the world. * EX: SELECT /obj/item/gun (will grab a list of every /obj/item/gun subtype in the world) * DELETE * This will delete all of a certain type in the world. * EX: DELETE /obj (will delete every /obj subtype in the world) * UPDATE * This can be used to edit variables on a certain type in cohesion with SET. * EX: UPDATE /mob/living/carbon/human SET health = 0 (will set all human's health to 0) * SET * This can be used to edit variables on a certain type in cohesion with UPDATE. * EX: UPDATE /mob/living/carbon/human SET health = 0 (will set all human's health to 0) * CALL * This is able to call a proc on a type in cohesion with ON. * EX: CALL death() ON /mob/living (will call death() on all /mob/living) * ON * This is used with CALL to specify a type to call the proc on. * EX: CALL death() ON /mob/living (will call death() on all /mob/living) * WHERE * This is used as a way to cut down on what you're acting on, can check any var on the type. * EX: DELETE /mob/living/carbon/human WHERE z == 3 (will delete all humans on z3) * Any WHERE specification slows down the speed of an SDQL query massively. * IN * Used to change the list that SDQL operates on. Defaults to `world`. * EX: SELECT /mob/living/carbon/human IN living_mob_list (will select all humans in living_mob_list, a global list) * MAP * Advanced CALL/UPDATE mix, allows you to run code and use the result. * EX: SELECT /obj/machinery/power/smes MAP [charge / capacity * 100, RCon_tag, src] (will give a list of all APCs, their charge, and RCON) * USING * Specify options that will affect how the SDQL query is ran. You can chain together multiple options by adding `,` between them. * See **Options** for options and what they do. * EX: USING SELECTPRINT = NO_OUTPUT, LISTSOURCE = OPTIMIZED SELECT /obj/item * EXPLAIN * A keyword used before a query to print some extra debug info. Not useful unless you're messing with SDQL's code itself. * EX: EXPLAIN SELECT /obj/item * SINGLECALL (CM13) * A query used for calling a single proc without iterating over anything. Ignores any IN or ON operators. * EX: SINGLECALL global._sin(45) ### Options * PROCCALL * BLOCKING * Forces all procs called via `CALL` to be blocking, each one halting the query until it's finished. Slows down the query massively, but is good for reducing lag or for something that needs procs done in an expected fashion. * SELECT * FORCE_NULLS * Prints any `null`s picked up by a `SELECT` query in the output normally given. Normally, `null`s are ignored instead. * PRIORITY * HIGH * Gives the query higher priority than most other functions. This can cause a lot of lag, but can get the query done faster. * SEQUENTIAL * TRUE * When chaining together multiple queries with `;`, the queries will go in order instead of asyncronously with eachother. Useful for when you want a series of things done in a specific order. * LISTSOURCE (CM13) * OPTIMIZED * When performing actions on certain types (such as `/mob`) without a designated list using `in`, the query will automatically use a `GLOB` list that contains the data being looked for instead of iterating over `world`. It's recommended to not turn this on if you're using SDQL as a debugging tool, but can make queries faster when operating under expected behavior. * SELECTPRINT (CM13) * NO_OUTPUT * Stops the output of a list of all objects found using a `SELECT` query. This is useful when simply checking for the amount of objects using `SELECT`, as the string creation takes a considerable amount of time, especially with >1000 objects being selected. ### Other bits * \* * \* is used as a "select all" option * EX: SELECT * IN living_mob_list (will select anything in the living_mob_list) * Holy shit don't use this for anything without IN * @[] * Can be used to generate a new list on the fly when [] won't be usable * EX: SELECT /mob/living IN (@[/area/service/bar MAP contents])[1] (will select all living mobs in the bar area) * src * The currently focused thing * marked * You can mark an atom with the "mark object" thingy in the right click/VV menu, marked will reference that * Base-BYOND procs and macros can't be used in SDQL, so wrapper procs need to be used instead, add a "_" before the proc to do so. * EX: CALL global._step(src, 1) ON /mob/living/carbon/human (will make the focused person step to the north) * ; * Allows you to call sequential queries * EX: CALL emote("scream") ON /mob/living/carbon/human; CALL gib() ON /mob/living/carbon/human (will make all humans scream then gib, second will only happen after the first finishes) * = vs. == * = is an assignment, foo = 4 will make foo equal 4 * == is a check, foo == 4 will not make foo equal 4, but will return TRUE if foo does equal 4, when used as logic instead of assignment * Verify, verify, verify * If you're doing a query that could fuck things up, run it with SELECT first, so you simply get a harmless list to confirm you did the WHERE or similar correctly ### Advice and Warnings * Deletion's expensive. Try not to delete over a thousand objects at a time if you're using a WHERE modifer on the query as well * WHERE is expensive and slow. If you can avoid using it, do so * Remember inheritence, types go * /datum * /atom * /atom/movable * /obj * /mob * /turf * /area * For global (not owned by any object) procs, preceed them with `global.` ### Handy SDQL Queries * Casing Deletion * DELETE /obj/item/ammo_casing WHERE loaded_projectile == null * Bloodstain Deletion * DELETE /obj/effect/decal/cleanable/blood * Finding Antag Amounts * SELECT /datum/preferences WHERE global._list_find(be_special, "INSERT ANTAG NAME") * Finding Antag Amounts Of Living (Returns mobs) * SELECT /datum/preferences WHERE global._list_find(be_special, "INSERT ANTAG NAME") && global._istype(parent.mob, /mob/living/carbon/human) MAP [parent.mob] * Forceful SS Recovery (may result in data loss) * CALL Recover() ON /datum/controller/subsystem * Forcefully outfit-equip a marked person * DELETE /obj/item IN marked.contents WHERE src.item_flags & 2; CALL marked.equipOutfit(/datum/outfit/contractor/upgraded) * Turn on all lights * CALL set_lights(TRUE) ON /obj/machinery/light_switch * Check who has a certain job set to high priority (CM13) * SELECT /datum/preferences WHERE global._list_get(job_preference_list, "Weapons Specialist") == 1 ### """Handy""" SDQL Queries * Death * CALL death() ON /mob/living/carbon/human * Death, but messier * CALL gib() ON /mob/living/carbon/human * Make everyone think they're sick * CALL emote("cough") ON /mob/living/carbon/human * Move all humans to one tile * CALL forceMove(marked) ON /mob/living/carbon/human (marked must be a turf in this case) * Make every object scream * CALL say("AAHHHHHH") ON /obj * Commend everyone pre-round (TG) * CALL receive_heart(marked, INSERT DECISECONDS, 1) ON /mob/dead (set marked to your mob and /mob/dead to /mob/living/carbon/human if not pre-round) * Chestburst a target instantly (CM13) * USING SEQUENTIAL = TRUE CALL global._new(/mob/living/carbon/xenomorph/larva, marked) ON /mob/living/carbon/human WHERE src == marked; CALL forceMove(marked) ON /mob/living/carbon/xenomorph/larva WHERE loc == null && !gc_destroyed; CALL chest_burst(marked) ON /mob/living/carbon/xenomorph/larva WHERE loc == marked; UPDATE /mob/living/carbon/xenomorph/larva WHERE loc == marked SET ckey = marked.ckey * Get rid of a player's chat and info window (CM13) * USING SEQUENTIAL = TRUE SINGLECALL global._winset(marked, "mainwindow.split", "splitter=1000"); SINGLECALL global._winset(marked, "infowindow", "is-visible=false"); SINGLECALL global._winset(marked, "outputwindow", "is-visible=false") ## Technical Notes - `SELECT` is incredibly expensive when called on a large amount of objects because it needs to assemble a string for every object found under `SELECT`. Due to how BYOND handles string interning and rebalancing, the cost (and associated lag) cannot be fixed. When `SELECT`ing a lot of objects, use of `USING LISTSOURCE = OPTIMIZED, SELECTPRINT = NO_OUTPUT` is recommended.