12.4.11 Calling Prolog from C
AllApplicationManualNameSummaryHelp

  • Documentation
    • Reference manual
      • Foreign Language Interface
        • The Foreign Include File
          • Calling Prolog from C
            • Predicate references
            • Initiating a query from C
              • PL_open_query()
              • PL_next_solution()
              • PL_cut_query()
              • PL_close_query()
              • PL_current_query()
              • PL_query_engine()
              • PL_call_predicate()
              • PL_call()
    • Packages

12.4.11.2 Initiating a query from C

This section discusses the functions for creating and manipulating queries from C. Note that a foreign context can have at most one active query. This implies that it is allowed to make strictly nested calls between C and Prolog (Prolog calls C, calls Prolog, calls C, etc.), but it is not allowed to open multiple queries and start generating solutions for each of them by calling PL_next_solution(). Be sure to call PL_cut_query() or PL_close_query() on any query you opened before opening the next or returning control back to Prolog.

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 p argument specifies the predicate, and should be the result of a call to PL_pred() or PL_predicate(). Note that it is allowed to store this handle as global data and reuse it for future queries. 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.

The flags arguments provides some additional options concerning debugging and exception handling. It is a bitwise or of the following values:

PL_Q_NORMAL
Normal operation. The debugger inherits its settings from the environment. If an exception occurs that is not handled in Prolog, a message is printed and the tracer is started to debug the error.218Do not pass the integer 0 for normal operation, as this is interpreted as PL_Q_NODEBUG for backward compatibility reasons.
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.
PL_Q_CATCH_EXCEPTION
If an exception is raised while executing the goal, do not report it, but make it available for PL_exception().
PL_Q_PASS_EXCEPTION
As PL_Q_CATCH_EXCEPTION, but do not invalidate the exception-term while calling PL_close_query(). This option is experimental.
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_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_EXCEPTIONFALSEException available through PL_exception()
PL_S_FALSEFALSEQuery failed
PL_S_TRUETRUEQuery succeeded with choicepoint
PL_S_LASTTRUEQuery succeeded without choicepoint

PL_open_query() can return the query identifier‘0' if there is not enough space on the environment stack. This function succeeds, even if the referenced predicate is not defined. In this case, running the query using PL_next_solution() will 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 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_NORMAL, p, a0);
  ...
}
int PL_next_solution(qid_t qid)
Generate the first (next) solution for the given query. The return value is TRUE if a solution was found, or FALSE to indicate the query could not be proven. This function may be called repeatedly until it fails to generate all solutions to the query.
int PL_cut_query(qid_t qid)
Discards the query, but does not delete any of the data created by the query. It just invalidates qid, allowing for a new call to PL_open_query() in this context. PL_cut_query() may invoke cleanup handlers (see setup_call_cleanup/3) and therefore may experience exceptions. If an exception occurs the return value is FALSE and the exception is accessible through PL_exception(0).
int PL_close_query(qid_t qid)
As PL_cut_query(), but all data and bindings created by the query are destroyed.
qid_t PL_current_query(void)
Returns the query id of of the current query or 0 if the current thread is not executing any queries.
PL_engine_t PL_query_engine(qid_t qid)
Return the engine to which qid belongs. Note that interacting with a query or the Prolog terms associated with a query requires the engine to be current. See PL_set_engine().
int PL_call_predicate(module_t m, int flags, predicate_t pred, term_t +t0)
Shorthand for PL_open_query(), PL_next_solution(), PL_cut_query(), generating a single solution. The arguments are the same as for PL_open_query(), the return value is the same as PL_next_solution().
int PL_call(term_t t, module_t m)
Call term t just like the Prolog predicate once/1. t is called in the module m, or in the context module if m == NULL. Returns TRUE if the call succeeds, FALSE otherwise. Figure 7 shows an example to obtain the number of defined atoms. All checks are omitted to improve readability.