---
# System prepended metadata

title: SDQL2 And You

---

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