GQL Essentials Procedures
PDF ↗

Catalogs, Sessions, and Procedures

Chapter 18Procedures

This chapter treats procedures as callable abstractions and formalizes named procedure descriptors, inline GQL procedure bodies, resolution, and calls. Functions are value-expression operators covered by the expression semantics; they are not primary catalog objects in the core catalog modeled here.

18.1 Procedure Signatures and Body Typing

Named procedure descriptors. For the lookup-oriented model used in this chapter, we use the following compact, lookup-augmented representation of a named procedure catalog entry. It adds the catalog object name p to the standard descriptor components and retains the components needed below:

PDesc = ⟨p,xj : τj¯,xm′ : τ m′ = d m¯,τres,kind⟩,

where p is its catalog object name, xj : τj¯ is the ordered list of mandatory parameters, xm′ : τ m′ = d m¯ is the trailing list of optional parameters with default values, τres is the procedure result type, and kind ∈{catalog,data,query} records the permitted kind of side effects. Parameter names are unique. Optional parameters form only a suffix; supplying one requires supplying every optional parameter before it.

The core signature of the declaration is

sig(PDesc) = p(xj : τj¯,xm′ : τ m′ = d m¯)→τres.

If τres is a binding-table type, its record type supplies the names and types available to a YIELD clause. Write BT⟨zi : υi¯⟩ for the material binding-table type whose record has the named fields zi : υi¯. In a CALL-statement, the declared type of the procedure call is required to be either a material binding-table type or the empty type. The effect abstraction used later is obtained from kind: a query procedure has no side effects, a data procedure may have data-modifying effects only, and a catalog procedure may have catalog-modifying effects, possibly together with data- modifying effects.

In the catalog, procedure names are unique and procedure overloading is not modeled: the Procs component maps each qualified procedure identifier to at most one declaration,

Procs : ℚ ⇀ PDesc.

Consequently, a qualified procedure name uniquely determines its core signature whenever it is present in the catalog.

Procedure bodies and their scope. In this edition, a named procedure is an external procedure; the standard does not specify a GQL statement that defines its implementation. Accordingly, PDesc contains no GQL body. An inline procedure is instead a nested procedure specification with a GQL procedure body. Its statements determine whether it is catalog-modifying, data-modifying, or a query procedure, and its declared result type is computed from that body. Body typing uses the incoming working record/table types and the statement-block rules; it is not an undeclared Bp attached to a named catalog descriptor.

18.2 Calls and Scoping

Static environment. Typing judgments use a resolution environment ℜ = ⟨X,Loc⟩, where X = ⟨C,WSR,WG⟩ is the active context (catalog, working schema, working graph site) and Loc is a finite map of parameters and binding variables used when typing argument expressions. A catalog procedure reference is resolved by its own grammar and is not shadowed by a binding variable of the same spelling.

Resolution order. For a named procedure call, the procedure reference identifies its explicit catalog parent or uses the implicit parent ./ (the current working schema), then identifies a named procedure in that parent. Absolute and relative catalog paths follow Chapter 17. Alternatively, a procedure reference may be supplied by a substituted reference parameter; its substitution is resolved as the corresponding catalog procedure parent and name. This is reference resolution, not an ordered search through local variables and catalog names.

Syntactic form of procedure calls. At statement level, a procedure call may be optional and may invoke either an inline or a named procedure. The named form is:

BNF
call-proc-stmt ::= [ "OPTIONAL" ] "CALL" procedure-call
procedure-call ::= inline-procedure-call | named-procedure-call
named-procedure-call ::= procedure-reference "(" [ arg-list ] ")"
                         [ "YIELD" yield-list ]

arg-list   ::= expr { "," expr }

yield-list ::= yield-item { "," yield-item }

yield-item ::= field-name [ "AS" binding-variable ]

expr      ::= ...  /* value expression */

Here procedure-reference identifies a cataloged procedure, arg-list supplies actual arguments as value expressions in call-position order, and yield-list specifies which output columns of the procedure are made visible to the enclosing statement, with AS providing an explicit alias for the corresponding column name when required by the context. The named form requires optional Feature GP04, Named procedure calls. A graph argument additionally requires GP15, and a binding-table argument additionally requires GP14.

Example: a named library procedure. Let pfees = recomputeFees be a procedure object name and let qfees ∈ ℚ be its globally resolved reference in the current working schema. In the descriptor abstraction used here, an illustrative external data procedure may be represented by

PDescfees = ⟨pfees,⟨asOf : DATE⟩,⟨⟩, BT⟨updatedCount : INTEGER⟩,data⟩ .

If it is registered through an implementation-defined mechanism, the derived catalog projection satisfies

Procs(qfees) = PDescfees.

The relative name in the following call resolves to qfees:

GQL
CALL recomputeFees(DATE '2025-12-31')
YIELD updatedCount AS cnt

The procedure name and implementation are illustrative; the library DDL in Section 4.2 does not declare this external procedure.

Example: procedure-call resolution environment. In the static-resolution abstraction used here, one possible environment for a call typed inside the library context is

Loclib = {loanVar↦NodeRef,feeVar↦FLOAT}, ℜlib = ⟨Xlib,Loclib⟩.

The local map records types used to type argument expressions; the reference recomputeFees is resolved through Xlib.

Procedure call in statements. A CALL-statement that invokes a named procedure and yields selected columns has the form CALLp(e¯)YIELDzkASyk¯. Let Ξ be the applicable static type context and let Θ be the incoming binding-name-to-type environment; Θ′ is its extension by yielded columns. For a descriptor with j mandatory and m optional parameters, define nmin ⁡ = j and nmax ⁡ = j + m. For a binding-table result BT⟨zi : υi¯⟩, let υ(zi) = υi. Finally, 𝜀kind is empty for a query procedure and is the applicable abstract data- or catalog-modifying effect for the other procedure kinds. The yielding form below therefore assumes a material binding-table result. If the procedure result type is the empty type, YIELD is not permitted and the call statement uses the material unit record type for its output contribution. For a permitted number of actual arguments, write e¯assignableTo(τ¯,τ′¯) when the statically derived type of each supplied argument passes the GQL store-assignment check against the corresponding mandatory or optional parameter type; omitted optional arguments use their descriptor defaults. A schematic typing rule is:

                     -------′----′------
resolveProc(X,p) = ⟨p,xj : τj,xm : τm = dm,
            BT  ⟨zi-: υi⟩,kind⟩
         -          -             ---′
  nmin ≤ |e| ≤ nmax e assignableTo (τ,τ )
---{zk}k ⊆-{zi}i-Θ-′ =-Θ-∪-{yk :-υ(zk)}k--
  ;Θ; ℜ ⊢ CALL   p(e) YIELD   z-AS--y--  CallProc
               ′              k      k
          ⇒  Θ ;𝜀kind

Here resolveProc is the procedure-specific instance of the catalog resolution function from Chapter 17. A YIELD clause is permitted only for a binding-table procedure result, selects existing result columns, and produces the aliases shown in Θ′. The incoming and yielded record types must be field-name-disjoint. The effect 𝜀kind is determined by the descriptor’s procedure kind, and is empty exactly for a query procedure.

Operationally, the procedure is called once for each incoming working-table record in a child execution context containing its argument record. If its execution result is a binding table, each result record is combined with that incoming record. If its result is omitted (the empty-type case), the call statement uses a unit binding table containing one unit record, so the incoming record is preserved once. For OPTIONAL CALL, an empty binding-table result instead contributes one record whose yielded fields are null; a non-optional empty binding-table result contributes no record.

GQL Essentials · Dominik Tomaszuk

Search chapters, definitions and examples.