Skip to main content

Appendix 3: Control Directives

The control directives are those statements that begin with @ and they are distinguished from other statements because they influence the compiler rather than the program logic. Some of these are of great importance and discussed elsewhere.

The complete list (as of this writing) is:


  • These enable or disable more strict semanic checking the sub options are
    • FOREIGN KEY ON UPDATE: all FK's must choose some ON UPDATE strategy
    • FOREIGN KEY ON DELETE: all FK's must choose some ON DELETE strategy
    • PROCEDURE: all procedures must be declared before they are called (eliminating the vanilla C call option)
    • JOIN: all joins must be ANSI style, the form FROM A,B is not allowed (replace with A INNER JOIN B
    • WINDOW FUNC: window functions are disallowed (useful if targeting old versions of SQLite)
    • UPSERT STATEMENT: the upsert form is disallowed (useful if targeting old versions of SQLite)


  • marks a column or variable as 'sensitive' for privacy purposes, this behaves somewhat like nullability (See Chapter 3) in that it is radioactive, contaminating anything it touches
  • the intent of this annotation is to make it clear where sensitive data is being returned or consumed in your procedures
  • this information appears in the JSON output for further codegen or for analysis (See Chapter 13)


  • These directives control the declaration of schema regions and allow you to place things into those regions -- see Chapter 10


  • Allows for the creation of a ad hoc migration step at a given schema version, (See Chapter 10)


  • Emits text into the C output stream, useful for emiting things like function prototypes or preprocessor directives
  • e.g. `echo C, '#define foo bar'


  • used to mark the schema version where an object is created or deleted, or alternatively indicate the the object is always dropped and recreated when it changes (See Chapter 10)


  • used to indicate that the code that follows is part of a migration script for the indicated schema version
  • this has the effect of making the schema appear to be how it existed at the indicated version
  • the idea here is that migration procedures operate on previous versions of the schema where (e.g.) some columns/tables hadn't been deleted yet


  • indicates the start of the previous version of the schema for comparison (See Chapter 11)


  • CQL emits a schema upgrade script as part of its upgrade features, this script declares tables in their final form but also creates the same tables as they existed when they were first created
  • this directive instructs CQL to ignore the incompatible creations, the first declaration controls
  • the idea here is that the upgrade script is in the business of getting you to the finish line in an orderly fashion and some of the interim steps are just not all the way there yet
  • note that the upgrade script recapitulates the version history, it does not take you directly to the finish line, this is so that all instances get to the same place the same way (and this fleshes out any bugs in migration)


  • these control the creation of dummy data for insert and fetch statements (See Chapters 5 and 12)


  • a string literal that corresponds to the current file name with a prefix stripped (to remove build lab junk in the path)


  • the main purpose of @attribute is to appear in the JSON output so that it can control later codegen stages in whatever way you deem appropriate

  • the nested nature of attribute values is sufficiently flexible than you could encode an arbitrary LISP program in an attribute, so really anything you might need to express is possible

  • there are a number of attributes known to the compiler which I list below (complete as of this writing)

  • cql:autodrop=(table1, table2, ...) when present the indicated tables, which must be temp tables, are dropped when the results of the procedure have been fetched into a rowset

  • cql:identity=(column1, column2, ...) the indicated columns are used to create a row comparator for the rowset corresponding to the procedure, this appears in a C macro of the form procedure_name_row_same(rowset1, row1, rowset2, row2)

  • cql:suppress_getters the annotated procedure should not emit its related column getter functions.

    • Useful if you only indend to call the procedure from CQL.
    • Saves code generation and removes the possibility of C code using the getters.
  • cql:suppress_result_set the annotated procedure should not emit its related "fetch results" function.

    • Useful if you only indend to call the procedure from CQL.
    • Saves code generation and removes the possibility of C code using the result set or getters.
    • Implies cql:suppress_getters; since there is no result set, getters would be redundant.
    • Note: an OUT UNION procedure cannot have a suppressed result set since all such a procedure does is produce a result set. This attribute is ignored for out union procedures.
  • cql:private the annotated procedure will be static in the generated C

    • Because the generated function is static it cannot be called from other modules and therefore will not go in any CQL exports file (that would be moot since you couldn't call it).
    • This attribute also implies cql:suppress_result_set since only CQL code in the same translation unit could possibly call it and hence the result set procedure is useless to other C code.
  • cql:generate_copy the code generation for the annotated procedure will produce a [procedure_name]_copy function that can make complete or partial copies of its result set.

  • cql:base_fragment=frag_name used for base fragments (See Chapter 14)

  • cql:extension_fragment=frag_name used for extension fragments (See Chapter 14)

  • cql:assembly_fragment=frag_name used for assembly fragments (See Chapter 14)

  • cql:shared_fragment is used to create shared fragments (See Chapter 14)

  • cql:no_table_scan for query plan processing, indicates that the table in question should never be table scanned in any plan (for better diagnostics)

  • cql:autotest=([many forms]) declares various autotest features (See Chapter 12)

  • cql:query_plan_branch=[integer] is used by the query plan generator to determine which conditional branch to use in query plan analysis when a shared fragment that contains an IF statement is used. (See Chapter 15)

  • cql:alias_of=[c_function_name] are used on function declarations to declare a function or procedure in CQL that calls a function of a different name. This is intended to used for aliasing native (C) functions. Both the aliased function name and the original function name may be declared in CQL at the same time. Note that the compiler does not enforce any consistency in typing between the original and aliased functions.