Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 0 additions & 110 deletions docs/language/learn-ql/advanced/abstract-classes.rst

This file was deleted.

3 changes: 0 additions & 3 deletions docs/language/learn-ql/advanced/advanced-ql.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ Advanced QL

Topics on advanced uses of QL. These topics assume that you are familiar with QL and the basics of query writing.

- :doc:`Semantics of abstract classes <abstract-classes>`
- :doc:`Choosing appropriate ways to constrain types <constraining-types>`
- :doc:`Determining the most specific types of a variable <determining-specific-types-variables>`
- :doc:`Folding predicates <folding-predicates>`
- :doc:`Understanding the difference between != and not(=) <equivalence>`
- :doc:`Monotonic aggregates in QL <monotonic-aggregates>`
44 changes: 0 additions & 44 deletions docs/language/learn-ql/advanced/equivalence.rst

This file was deleted.

36 changes: 0 additions & 36 deletions docs/language/learn-ql/advanced/folding-predicates.rst

This file was deleted.

42 changes: 42 additions & 0 deletions docs/language/learn-ql/writing-queries/debugging-queries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,48 @@ That is, you should define a *base case* that allows the predicate to *bottom ou
The query optimizer has special data structures for dealing with `transitive closures <https://help.semmle.com/QL/ql-handbook/recursion.html#transitive-closures>`__.
If possible, use a transitive closure over a simple recursive predicate, as it is likely to be computed faster.

Fold predicates
~~~~~~~~~~~~~~~~~~

Sometimes you can assist the query optimizer by "folding" parts of large predicates out into smaller predicates.

The general principle is to split off chunks of work that are:

- **linear**, so that there is not too much branching.
- **tightly bound**, so that the chunks join with each other on as many variables as possible.


In the following example, we explore some lookups on two ``Element``\ s:

.. code-block:: ql

predicate similar(Element e1, Element e2) {
e1.getName() = e2.getName() and
e1.getFile() = e2.getFile() and
e1.getLocation().getStartLine() = e2.getLocation().getStartLine()
}

Going from ``Element -> File`` and ``Element -> Location -> StartLine`` is linear--that is, there is only one ``File``, ``Location``, etc. for each ``Element``.

However, as written it is difficult for the optimizer to pick out the best ordering. Joining first and then doing the linear lookups later would likely result in poor performance. Generally, we want to do the quick, linear parts first, and then join on the resultant larger tables. We can initiate this kind of ordering by splitting the above predicate as follows:

.. code-block:: ql

predicate locInfo(Element e, string name, File f, int startLine) {
name = e.getName() and
f = e.getFile() and
startLine = e.getLocation().getStartLine()
}

predicate sameLoc(Element e1, Element e2) {
exists(string name, File f, int startLine |
locInfo(e1, name, f, startLine) and
locInfo(e2, name, f, startLine)
)
}

Now the structure we want is clearer. We've separated out the easy part into its own predicate ``locInfo``, and the main predicate ``sameLoc`` is just a larger join.

Further information
-------------------

Expand Down
5 changes: 4 additions & 1 deletion docs/language/ql-handbook/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ into the :ref:`namespace <namespaces>` of the current module.
Import statements
=================

Import statements are used for importing modules and are of the form::
Import statements are used for importing modules. They are of the form::

import <module_expression1> as <name>
import <module_expression2>
Expand All @@ -175,3 +175,6 @@ for example ``import javascript as js``.

The ``<module_expression>`` itself can be a module name, a selection, or a qualified
reference. See :ref:`name-resolution` for more details.

For information about how import statements are looked up, see `Module resolution <https://help.semmle.com/QL/ql-spec/language.html#module-resolution>`__
in the QL language specification.
14 changes: 13 additions & 1 deletion docs/language/ql-handbook/types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,9 @@ by declaring them in the ``from`` part.
You can also annotate predicates and fields. See the list of :ref:`annotations <annotations-overview>`
that are available.

Kinds of classes
.. _concrete-classes:

Concrete classes
================

The classes in the above examples are all **concrete** classes. They are defined by
Expand All @@ -218,6 +220,9 @@ values in the intersection of the base types that also satisfy the

.. _abstract-classes:

Abstract classes
================

A class :ref:`annotated <abstract>` with ``abstract``, known as an **abstract** class, is also a restriction of
the values in a larger type. However, an abstract class is defined as the union of its
subclasses. In particular, for a value to be in an abstract class, it must satisfy the
Expand Down Expand Up @@ -247,6 +252,13 @@ The abstract class ``SqlExpr`` refers to all of those different expressions. If
support for another database system later on, you can simply add a new subclass to ``SqlExpr``;
there is no need to update the queries that rely on it.

.. pull-quote:: Important


You must take care when you add a new subclass to an existing abstract class. Adding a subclass
is not an isolated change, it also extends the abstract class since that is a union of its
subclasses.

.. _overriding-member-predicates:

Overriding member predicates
Expand Down
8 changes: 4 additions & 4 deletions docs/language/ql-spec/language.rst
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ Identifiers are used in following syntactic constructs:
simpleId ::= lowerId | upperId
modulename ::= simpleId
classname ::= upperId
dbasetype ::= atlowerId
dbasetype ::= atLowerId
predicateRef ::= (moduleId "::")? literalId
predicateName ::= lowerId
varname ::= simpleId
Expand Down Expand Up @@ -1798,7 +1798,7 @@ The complete grammar for QL is as follows:

::

ql ::= moduleBody ;
ql ::= moduleBody

module ::= annotation* "module" modulename "{" moduleBody "}"

Expand Down Expand Up @@ -1970,11 +1970,11 @@ The complete grammar for QL is as follows:

simpleId ::= lowerId | upperId

modulename :: = simpleId
modulename ::= simpleId

classname ::= upperId

dbasetype ::= atlowerId
dbasetype ::= atLowerId

predicateRef ::= (moduleId "::")? literalId

Expand Down