# 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.