12.4.12.2 Initiating a query from C
All Application Manual Name SummaryHelp

  • Documentation
    • Reference manual
      • Foreign Language Interface
        • The Foreign Include File
          • Calling Prolog from C
            • Initiating a query from C
              • PL_open_query()
              • PL_next_solution()
              • PL_cut_query()
              • PL_close_query()
              • PL_current_query()
              • PL_query_engine()
              • PL_query_arguments()
              • PL_set_query_data()
              • PL_query_data()
              • PL_call_predicate()
              • PL_call()
    • Packages
Availability:C-language interface function
qid_t PL_open_query(module_t ctx, int flags, predicate_t p, term_t +t0)

Opens a query and returns an identifier for it. ctx is the context module of the goal. When NULL, the context module of the calling context will be used, or user if there is no calling context (as may happen in embedded systems). Note that the context module only matters for meta-predicates. See meta_predicate/1, context_module/1 and module_transparent/1. The term reference t0 is the first of a vector of term references as returned by PL_new_term_refs(n). Raise a resource exception and returns (qid_t)0 on failure.

Every use of PL_open_query() must have a corresponding call to PL_cut_query() or PL_close_query() before the foreign predicate returns either TRUE or FALSE.

The flags arguments provides some additional options concerning debugging and exception handling. It is a bitwise or of the following values below. Note that exception propagation is defined by the flags PL_Q_NORMAL, PL_Q_CATCH_EXCEPTION and PL_Q_PASS_EXCEPTION. Exactly one of these flags must be specified (if none of them is specified, the behavior is as if PL_Q_NODEBUG is specified)..

PL_Q_NORMAL
Normal operation. It is named "normal" because it makes a call to Prolog behave as it did before exceptions were implemented, i.e., an error (now uncaught exception) triggers the debugger. See also the Prolog flag debug_on_error. This mode is still useful when calling Prolog from C if the C code is not willing to handle exceptions.
PL_Q_NODEBUG
Switch off the debugger while executing the goal. This option is used by many calls to hook-predicates to avoid tracing the hooks. An example is print/1 calling portray/1 from foreign code. This is the default if flags is 0.
PL_Q_CATCH_EXCEPTION
If an exception is raised while executing the goal, make it available by calling PL_exception(qid), where qid is the qid_t returned by PL_open_query(). The exception is implicitly cleared from the environment when the query is closed and the exception term returned from PL_exception(qid) becomes invalid. Use PL_Q_PASS_EXCEPTION if you wish to propagate the exception.
PL_Q_PASS_EXCEPTION
As PL_Q_CATCH_EXCEPTION, making the exception on the inner environment available using PL_exception(0) in the parent environment. If PL_next_solution() returns FALSE, you must call PL_cut_query() or PL_close_query(). After that you may verify whether failure was due to logical failure of the called predicate or an exception by calling PL_exception(0). If the predicate failed due to an exception you should return with FALSE from the foreign predicate or call PL_clear_exception() to clear it. If you wish to process the exception in C, it is advised to use PL_Q_CATCH_EXCEPTION instead, but only if you have no need to raise an exception or re-raise the caught exception.

Note that PL_Q_PASS_EXCEPTION is used by the debugger to decide whether the exception is caught. If there is no matching catch/3 call in the current query and the query was started using PL_Q_PASS_EXCEPTION the debugger searches the parent queries until it either finds a matching catch/3, a query with PL_Q_CATCH_EXCEPTION (in which case it considers the exception handled by C) or the top of the query stack (in which case it considers the exception uncaught). Uncaught exceptions use the library(library(prolog_stack)) to add a backtrace to the exception and start the debugger as soon as possible if the Prolog flag debug_on_error is true.

PL_Q_ALLOW_YIELD
Support the I_YIELD instruction for engine-based coroutining. See $engine_yield/2 in boot/init.pl for details.
PL_Q_TRACE_WITH_YIELD
Allows for implementing a yield based debugger. See section 12.4.1.3
PL_Q_EXT_STATUS
Make PL_next_solution() return extended status. Instead of only TRUE or FALSE extended status as illustrated in the following table:

ExtendedNormal
PL_S_NOT_INNERFALSEPL_next_solution() may only be called on the innermost query
PL_S_EXCEPTIONFALSEException available through PL_exception()
PL_S_FALSEFALSEQuery failed
PL_S_TRUETRUEQuery succeeded with choicepoint
PL_S_LASTTRUEQuery succeeded without choicepoint
PL_S_YIELDn/aQuery was yielded. See section 12.4.1.2
PL_S_YIELD_DEBUGn/aYielded on behalf of the debugger. See section 12.4.1.3

PL_open_query() can return the query identifier 0 if there is not enough space on the environment stack (and makes the exception available through PL_exception(0)). This function succeeds, even if the referenced predicate is not defined. In this case, running the query using PL_next_solution() may return an existence_error. See PL_exception().

The example below opens a query to the predicate is_a/2 to find the ancestor of‘me’. The reference to the predicate is valid for the duration of the process or until PL_cleanup() is called (see PL_predicate() for details) and may be cached by the client.

char *
ancestor(const char *me)
{ term_t a0 = PL_new_term_refs(2);
  static predicate_t p;

  if ( !p )
    p = PL_predicate("is_a", 2, "database");

  PL_put_atom_chars(a0, me);
  PL_open_query(NULL, PL_Q_PASS_EXCEPTION, p, a0);
  ...
}