Did you know ... | Search Documentation: |
Pack swiplite -- DEVELOPMENT.md |
This documents my own development workflow and is probably useless to anyone else.
This example removes the installed pack, re-packs it, and re-installs it, without bumping version numbers and without distributing the source code, from the directory which contains the swiplite directory:
$ rm -rf ~/.local/share/swi-prolog/pack/swiplite $ tar -czf swiplite-0.1.tgz swiplite $ swipl ?- pack_install('swiplite-0.1.tgz', [interactive(false)]). ?- use_module(library(sqlite)).
From inside the swiplite directory:
$ mkdir -p build \ && ( cd build \ && SWIPL_HOME_DIR="$(swipl --home)" cmake -G Ninja .. \ && ninja )
After this, use -p
to set the locations for foreign()
and
library()
, from inside the package home directory:
$ swipl -p foreign=build -p library=prolog ?- use_module(library(sqlite)). ?- use_module(test/test_sqlite). ?- run_tests.
... or alternatively,
$ swipl -p foreign=build -p library=prolog \ -g 'use_module(test/test_sqlite),run_tests' \ -t halt
This has been tested on MacOS and Linux, but of course the SWI_HOME_DIR environment variable depends on where SWI-Prolog is installed.
Yet another option is to have a file debug.pl
that could look
like this:
:- doc_server(4000). :- portray_text(true). :- multifile user:file_search_path/2. user:file_search_path(library, L) :- absolute_file_name(prolog, L). user:file_search_path(foreign, L) :- absolute_file_name(build, L). :- use_module(library(sqlite)). :- use_module(test/test_sqlite).
If you now consult this file:
?- [debug].
you get a documentation server running at `http://localhost:4000/pldoc/` and you can use the exported predicates, or run all tests with
?- run_tests.
SQLite statements are evaluated by calling sqlite3_step()
one
or more times. The return value distinguishes if there is a row
of result data or the statement is done: either SQLITE_ROW or
SQLITE_DONE.
SELECT statements are the only ones that have a result set.
From the docs of sqlite3_column_count()
:
Return the number of columns in the result set returned by the prepared statement. If this routine returns 0, that means the prepared statement returns no data (for example an UPDATE). However, just because this routine returns a positive number does not mean that one or more rows of data will be returned. A SELECT statement will always have a positive sqlite3_column_count()
but depending on the WHERE clause constraints and the table content, it might return no rows.
The interface provides four predicates for evaluating prepared
statements, wrapping the necessary calls to sqlite3_step()
.
sqlite3_step()
fetches them, sqlite_many/4
The predicate sqlite_do(Stmt)
throws an error if the prepared
statement has any columns in its result set. It evaluates the
statement and succeeds if the first sqlite3_step()
invocation
returns SQLITE_DONE. The statement is reset and ready to be
evaluated again.
The predicate sqlite_one(Stmt, Row)
throws an error if the
prepared statement does not have columns in its result set. It
expects exactly one row in the result set, and if there are no
rows or more than one row in the result set, it also throws an
error. When the predicate succeed, the statement is reset and
ready to be evaluated again.
The predicate sqlite_many(Stmt, N, Rows, R0)
can be used to
fetch multiple rows from the result set as a list of Prolog
terms. It reads up to N rows in Rows. If there are no more
rows in the result, R0 == []
. If N is a free variable, all
rows in the result will be fetched at once and N unified with
the total number of rows in the result set.
In addition, sqlite_reset(Stmt)
must be used to reset a
statement after all rows in the result set have been stepped
through. It is not needed for statements evaluated with
sqlite_eval/1 or sqlite_eval/2 (calling it has no effect).
nchars()
`I used the following function to figure out the value of the "length" argument in `PL_get_nchars()`:
foreign_t pl_text_length(term_t t, term_t n) { char *s; size_t s_n; if (!PL_get_nchars(t, &s_n, &s, CVT_ATOM | CVT_STRING | CVT_LIST | CVT_EXCEPTION | BUF_STACK | REP_UTF8) || !PL_unify_uint64(n, s_n)) return false; return true; }
With this, I get:
?- text_length(foo, N). N = 3. ?- text_length('foo\0bar', N). N = 7. ?- text_length('foo\0bar\0', N). N = 8. ?- text_length('ÑеиÑ', N). N = 8.
So, it seems that the number is in bytes, and the terminating null is not included in that count.