aboutsummaryrefslogblamecommitdiffstats
path: root/docs/icl.org
blob: c2258bfb75d375927a54b846fc14e4c2276577a5 (plain) (tree)











































































































                                                                                                                 
#+TITLE: ICL — Integrity Control Language

ICL registers integrity constraints on relations. A constraint is a
membership check: before any tuple is inserted, Sakura verifies that
the tuple belongs to every constraint-relation attached to the target
relation.

Constraints are expressed as S-expressions and sent over the wire like
any other command.

* Syntax

#+begin_src
(RegisterConstraint
  (constraint_name "<name>")
  (relation_name   "<target-relation>")
  (body            <constraint-body>))
#+end_src

A ~<constraint-body>~ is one of:

| Form                                            | Meaning                        |
|-------------------------------------------------+--------------------------------|
| ~(MemberOf (target R) (binding (...)))~         | Tuple must be in relation R    |
| ~(Not (body B) (universe R))~                   | Negation (closed-world over R) |
| ~(And (B1 B2 ...))~                             | All must hold                  |
| ~(Or  (B1 B2 ...))~                             | At least one must hold         |
| ~(Exists (variable v) (quantifier R) (body B))~ | ∃ v ∈ R such that B holds      |
| ~(Forall (variable v) (quantifier R) (body B))~ | ∀ v ∈ R, B holds               |

Bindings map target-relation attribute names to values drawn from the
tuple being checked:

| Binding expr        | Meaning                        |
|---------------------+--------------------------------|
| ~(Var "attr")~      | Value of ~attr~ from the tuple |
| ~(Const (Int N))~   | Literal integer N              |
| ~(Const (Str "s"))~ | Literal string s               |
| ~(Const (Float f))~ | Literal float f                |

* Examples

** Foreign key

#+begin_src sexp
(CreateRelation (name "Department") (schema ((dept_id "integer") (dept_name "string"))))
(CreateRelation (name "Employee")   (schema ((emp_id "integer") (emp_name "string") (dept_id "integer"))))

(RegisterConstraint
  (constraint_name "fk_employee_dept")
  (relation_name   "Employee")
  (body (MemberOf
    (target "Department")
    (binding ((dept_id (Var "dept_id")))))))
#+end_src

** Range check

#+begin_src sexp
(CreateRelation (name "Result") (schema ((student_id "integer") (score "integer"))))

(RegisterConstraint
  (constraint_name "score_range")
  (relation_name   "Result")
  (body (And
    ((MemberOf (target "greater_than_or_equal_natural")
               (binding ((left (Var "score")) (right (Const (Int 0))))))
     (MemberOf (target "less_than_or_equal_natural")
               (binding ((left (Var "score")) (right (Const (Int 100))))))))))
#+end_src

** Existential (FK through a join)

A ~Suite~ is only valid if its room belongs to a building with more
than 3 floors:

#+begin_src sexp
(CreateRelation (name "Building") (schema ((building_id "integer") (building_name "string") (floors "integer"))))
(CreateRelation (name "Room")     (schema ((room_id "integer") (building_id "integer") (floor "integer"))))
(CreateRelation (name "Suite")    (schema ((suite_id "integer") (room_id "integer") (suite_name "string"))))

(RegisterConstraint
  (constraint_name "suite_in_tall_building")
  (relation_name   "Suite")
  (body
    (Exists (variable "r") (quantifier "Room")
      (body
        (Exists (variable "b") (quantifier "Building")
          (body
            (And
              ((MemberOf (target "Room")
                         (binding ((room_id (Var "room_id")))))
               (MemberOf (target "Building")
                         (binding ((building_id (Var "r.building_id")))))
               (MemberOf (target "greater_than_natural")
                         (binding ((left (Var "b.floors"))
                                   (right (Const (Int 3))))))))))))))
#+end_src

Note: quantifier variables are namespaced — attributes from variable
~r~ are accessed as ~r.attr_name~ inside nested scopes.

* See also

- ~lib/icl/~ — AST, parser, executor
- ~lib/constraint.ml~ — runtime constraint representation and evaluator
- ~docs/icl-quantification.org~ — full runtime model for ~Exists~/~Forall~
- ~docs/constraints.org~ — conceptual background