pax_global_header00006660000000000000000000000064141653424340014520gustar00rootroot0000000000000052 comment=e3e02a4af39d5dfdbd2cc8801696ed9ae2faf569 sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/000077500000000000000000000000001416534243400170345ustar00rootroot00000000000000sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/.gitattributes000066400000000000000000000000141416534243400217220ustar00rootroot00000000000000*.svg -diff sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/.github/000077500000000000000000000000001416534243400203745ustar00rootroot00000000000000sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/.github/workflows/000077500000000000000000000000001416534243400224315ustar00rootroot00000000000000sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/.github/workflows/c-cpp.yml000066400000000000000000000004111416534243400241520ustar00rootroot00000000000000name: C/C++ CI on: push: branches: [ master, dev ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: make run: make - name: make check run: make check sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/.gitignore000066400000000000000000000000571416534243400210260ustar00rootroot00000000000000.idea/ *.so *.swp test/*.phony test/db.sqlite3 sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/Makefile000066400000000000000000000020501416534243400204710ustar00rootroot00000000000000VERSION=0.1.1 CC=cc PLANTUML=plantuml INSTALL=install CFLAGS=$(shell pkg-config --cflags sqlite3) $(shell pcre2-config --cflags) -fPIC LIBS=$(shell pcre2-config --libs8) prefix=/usr .PHONY : doc check install dist clean pcre2.so: pcre2.c ${CC} -shared -o $@ ${CFLAGS} -W -Werror $^ ${LIBS} doc: test/50-run.svg %.svg: %.puml ${PLANTUML} -tsvg $< # Generate the test spec test/db.sqlite3: test/10-init/*.sql cat $^ | sqlite3 test/db.sqlite3 # Run the test execution test/50-run.phony: test/db.sqlite3 test/50-run.sh pcre2.so test/lib.sh # sqlite3 -cmd '.load ./pcre2' test/db.sqlite3 .selftest test/50-run.sh test/db.sqlite3 './pcre2' touch $@ # Run the test report commands check: test/50-run.phony test/70-print-summary.sh test/70-print-summary.sh install: pcre2.so sudo ${INSTALL} -p $^ ${prefix}/lib/sqlite3/pcre2.so dist: clean mkdir sqlite3-pcre2-${VERSION} cp -f pcre2.c Makefile readme.txt sqlite3-pcre2-${VERSION} tar -czf sqlite3-pcre2-${VERSION}.tar.gz sqlite3-pcre2-${VERSION} clean: -rm -f pcre2.so test/db.sqlite3 test/*.phony sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/README.md000066400000000000000000000035001416534243400203110ustar00rootroot00000000000000# Sqlite3-pcre2: Regex Extension This is sqlite3-pcre2, an extension for sqlite3 that uses libpcre2 to provide the REGEXP() function. The original source code was written by Alexey Tourbin and can be found at: [http://git.altlinux.org/people/at/packages/?p=sqlite3-pcre.git](http://git.altlinux.org/people/at/packages/?p=sqlite3-pcre.git) ## Build ### Prerequisite #### Debian ```bash sudo apt-get install \ libsqlite3-dev \ libpcre2-dev ``` ### Installation ```bash git clone https://github.com/christian-proust/sqlite3-pcre2 cd sqlite3-pcre2 make make install ``` ### Development The tests and the documentation can be generated using: ```bash make check make doc ``` See [test](test) documentation. ## Usage ### REGEXP instruction ```sql -- Test if asdf starts with the letter A with the case insensitive flag SELECT 'asdf' REGEXP '(?i)^A' ; -- => 1 -- Test if asdf starts with the letter A SELECT 'asdf' REGEXP '(?i)^A' ; -- => 0 ``` ## PCRE2 library The documentation of the PCRE2 library can be found at: [http://pcre.org/](http://pcre.org/). The regular expression syntax documentation can be found [https://perldoc.perl.org/perlre](here). ## Changelog ### 2021 UPDATE - Rename the lib from pcre.so to pcre2.so. - Use the libpcre2 instead of libpcre. - Handle a NULL value for both pattern and subject. - Handle a NULL character into a string. ### 2020 UPDATE Updated to work with MacOS. Modified the Makefile to compile and install on MacOS, changed C source code to get rid of "no string" error. (credit to @santiagoyepez for a less hacky fix of explicitly checking for nulls) ### 2006-11-02 Initial version The original source code was written by Alexey Tourbin and can be found at: [http://git.altlinux.org/people/at/packages/?p=sqlite3-pcre.git](http://git.altlinux.org/people/at/packages/?p=sqlite3-pcre.git) sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/pcre2.c000066400000000000000000000125131416534243400202150ustar00rootroot00000000000000/* * Initially written by Alexey Tourbin . * * The author has dedicated the code to the public domain. Anyone is free * to copy, modify, publish, use, compile, sell, or distribute the original * code, either in source code form or as a compiled binary, for any purpose, * commercial or non-commercial, and by any means. */ #define PCRE2_CODE_UNIT_WIDTH 8 #include #include #include #include #include SQLITE_EXTENSION_INIT1 typedef struct { char *pattern_str; int pattern_len; pcre2_code *pattern_code; } cache_entry; #ifndef CACHE_SIZE #define CACHE_SIZE 16 #endif static void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv) { const char *pattern_str, *subject_str; int pattern_len, subject_len; pcre2_code *pattern_code; assert(argc == 2); /* check null */ if (sqlite3_value_type(argv[0]) == SQLITE_NULL || sqlite3_value_type(argv[1]) == SQLITE_NULL) { return; } pattern_str = (const char *) sqlite3_value_text(argv[0]); if (!pattern_str) { sqlite3_result_error(ctx, "no pattern", -1); return; } pattern_len = sqlite3_value_bytes(argv[0]); subject_str = (const char *) sqlite3_value_text(argv[1]); if (!subject_str) { sqlite3_result_error(ctx, "no subject", -1); return; } subject_len = sqlite3_value_bytes(argv[1]); /* simple LRU cache */ { int i; int found = 0; cache_entry *cache = sqlite3_user_data(ctx); assert(cache); for (i = 0; i < CACHE_SIZE && cache[i].pattern_str; i++) if ( pattern_len == cache[i].pattern_len && memcmp(pattern_str, cache[i].pattern_str, pattern_len) == 0 ) { found = 1; break; } if (found) { if (i > 0) { cache_entry c = cache[i]; memmove(cache + 1, cache, i * sizeof(cache_entry)); cache[0] = c; } } else { cache_entry c; const char *err; int error_code; PCRE2_SIZE error_position; c.pattern_code = pcre2_compile( pattern_str, /* the pattern */ pattern_len, /* the length of the pattern */ 0, /* default options */ &error_code, /* for error number */ &error_position, /* for error offset */ NULL); /* use default compile context */ if (!c.pattern_code) { PCRE2_UCHAR error_buffer[256]; pcre2_get_error_message(error_code, error_buffer, sizeof(error_buffer)); char *e2 = sqlite3_mprintf( "Cannot compile pattern \"%s\" at offset %d: %s", pattern_str, (int)error_position, error_buffer); sqlite3_result_error(ctx, e2, -1); sqlite3_free(e2); return; } c.pattern_str = malloc(pattern_len); if (!c.pattern_str) { sqlite3_result_error(ctx, "malloc: ENOMEM", -1); pcre2_code_free(c.pattern_code); return; } memcpy(c.pattern_str, pattern_str, pattern_len); c.pattern_len = pattern_len; i = CACHE_SIZE - 1; if (cache[i].pattern_str) { free(cache[i].pattern_str); assert(cache[i].pattern_code); pcre2_code_free(cache[i].pattern_code); } memmove(cache + 1, cache, i * sizeof(cache_entry)); cache[0] = c; } pattern_code = cache[0].pattern_code; } { int rc; pcre2_match_data *match_data; assert(pattern_code); match_data = pcre2_match_data_create_from_pattern(pattern_code, NULL); rc = pcre2_match( pattern_code, /* the compiled pattern */ subject_str, /* the subject string */ subject_len, /* the length of the subject */ 0, /* start at offset 0 in the subject */ 0, /* default options */ match_data, /* block for storing the result */ NULL); /* use default match context */ assert(rc != 0); // because we have not set match_data if(rc >= 0) { // Normal case because we have not set match_data sqlite3_result_int(ctx, 1); } else if(rc == PCRE2_ERROR_NOMATCH) { sqlite3_result_int(ctx, 0); } else { // (rc < 0 and the code is not one of the above) PCRE2_UCHAR error_buffer[256]; pcre2_get_error_message(rc, error_buffer, sizeof(error_buffer)); sqlite3_result_error(ctx, error_buffer, -1); return; } pcre2_match_data_free(match_data); return; } } int sqlite3_extension_init(sqlite3 *db, char **err, const sqlite3_api_routines *api) { SQLITE_EXTENSION_INIT2(api) cache_entry *cache = calloc(CACHE_SIZE, sizeof(cache_entry)); if (!cache) { *err = "calloc: ENOMEM"; return 1; } sqlite3_create_function(db, "REGEXP", 2, SQLITE_UTF8, cache, regexp, NULL, NULL); return 0; } sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/sqlite3-pcre2.spec000066400000000000000000000021631416534243400223070ustar00rootroot00000000000000Name: sqlite3-pcre2 Version: 0.1.1 Release: 0 Summary: Perl-compatible regular expression support for the SQLite License: Public Domain Group: Databases URL: https://github.com/christian-proust/sqlite3-pcre2 Source: %name-%version.tar.gz Requires: libsqlite3 >= 3.3.8-alt2 # Automatically added by buildreq on Thu Nov 02 2006 BuildRequires: libpcre2-devel libsqlite3-devel sqlite3 #%if %{defined suse_version} #Requires: libsqlite3 >= 3.3.8 libpcre2 #BuildRequires: pcre2-devel sqlite3-devel sqlite3 #%endif #%if %{defined fedora} || %{defined mdkversion} #Requires: libsqlite >= 3.3.8 libpcre2 #BuildRequires: pcre2-devel sqlite-devel sqlite #%endif %description This SQLite loadable extension enables the REGEXP operator, which is not implemented by default, to call PCRE routines for regular expression matching. %prep %setup -q %build make #check sqlite3 >out < 0.1-alt1 - initial revision sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/000077500000000000000000000000001416534243400200135ustar00rootroot00000000000000sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/10-init/000077500000000000000000000000001416534243400211745ustar00rootroot00000000000000sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/10-init/10-create-schema.sql000066400000000000000000000043071416534243400246400ustar00rootroot00000000000000DROP TABLE IF EXISTS testcase; CREATE TABLE `testcase` ( `id` INTEGER PRIMARY KEY, -- Contains an SQL pattern expression. -- The SQL pattern uses the printf convention. Literal '%' shall be escaped with '%%'. -- The first occurence of %s is replaced by the ID of the testreport. -- In case of crash test, the expression may crash. -- Returns: a scalar value that will be stored in testreport.report_value. -- Example: -- '%s LIKE ''1%%''' -- return 1 if the testreport ID starts with a 1 `execute_sql` TEXT NOT NULL, -- Contains an SQL pattern expression. -- The SQL pattern uses the printf convention. Literal '%' shall be escaped with '%%'. -- The first occurence of %s is replaced by the ID of the testreport. -- The expression shall not crash. -- Returns: a scalar boolean value that will be stored in testreport.evaluation -- Example: -- '%s LIKE ''1%%''' -- return 1 if the testreport ID starts with a 1 `evaluate_sql` TEXT NOT NULL, -- Name of the table that contains more information about the testcase. `src_table` TEXT, -- ID in the table src_table linking to the row that originates the testcase. `src_id`, `description` TEXT ); DROP TABLE IF EXISTS testcampaign; CREATE TABLE `testcampaign` ( id INTEGER PRIMARY KEY, -- Julian day that identifies the begining of the test campaign. started_at FLOAT, -- Julian day that identifies the end of the test campaign. ended_at FLOAT, -- Text that identify the library that was used for the test. lib TEXT ); DROP TABLE IF EXISTS testreport; CREATE TABLE testreport ( `id` INTEGER PRIMARY KEY, `testcase` INTEGER NOT NULL REFERENCES testcase, `testcampaign` INTEGER NOT NULL REFERENCES testcampaign, -- Standard error that is returned by SQLite after the execution of testcase.execute_sql `stderr`, -- Exit code that is returned by SQLite after the execution of testcase.execute_sql `exit_code` INTEGER, -- Value that is returned by the execution of testcase.execute_sql. `report_value`, -- Value that is returned by the execution of testcase.evaluate_sql. `evaluation` INTEGER, UNIQUE (testcase, testcampaign) ); sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/10-init/20-testregexp.sql000066400000000000000000000054441416534243400243350ustar00rootroot00000000000000DROP TABLE IF EXISTS testregexp; CREATE TABLE testregexp ( `id` INTEGER PRIMARY KEY, `pattern` TEXT NOT NULL, -- SQL representation of the pattern `subject` TEXT NOT NULL, -- SQL representation of the subject `match` TEXT, -- SQL representation of the match value `failmessage` TEXT, -- Pattern of the failmessage, when the match operation shall crash `description` TEXT, CONSTRAINT match_xor_failmessage CHECK ( (`match` IS NULL AND `failmessage` IS NOT NULL) OR (`match` IS NOT NULL AND `failmessage` IS NULL) ) ); -- Insert testregexp for checking the match value based on the function input INSERT INTO testregexp (`pattern`, `subject`, `match`, `description`) VALUES -- pattern | `subject` | match | `description` | ('''(?i)^A''', '''asdf''', 1, NULL), ('''(?i)^A''', '''bsdf''', 0, NULL), ('''^A''', '''asdf''', 0, NULL), ('NULL', '''asdf''', 'NULL', 'NULL pattern shall return NULL'), ('''^A''', 'NULL', 'NULL', 'NULL subject shall return NULL'), ('''''', '''asdf''', 1, 'Blank pattern shall match'), ('''^A''', '''''', 0, 'Blank subject'), ( '''B''', 'x''00''||''B''', 1, 'NULL character in subject'), ( 'x''00''||''B''', '''a''||x''00''||''B''', 1, 'NULL character in pattern') ; -- Insert testregexp for checking the error message when the function crash INSERT INTO testregexp (`pattern`, `subject`, `failmessage`, `description` ) VALUES ('''^(A''', '''asdf''', '%Cannot compile pattern % missing closing parenthesis%', 'Non-compilable regexp' ) ; -- Write the testcase corresponding to the test data DELETE FROM testcase WHERE src_table = 'testregexp'; INSERT INTO `testcase` (`src_table`, `src_id`, `execute_sql`, `evaluate_sql`, `description`) SELECT 'testregexp' AS src_table, id AS src_id, ( 'SELECT '||`subject`||' REGEXP '||`pattern`||' AS `value`' ) AS `execute_sql`, ( CASE WHEN `failmessage` IS NULL THEN '`report_value`'||' IS '||`match` ELSE '`stderr` LIKE ''' || REPLACE(`failmessage`, '%', '%%') || '''' END ) AS `evaluate_sql`, ( CASE WHEN `failmessage` IS NULL THEN `pattern` || ' shall ' || (CASE WHEN `match` THEN 'match' ELSE 'not match' END) || ' ' || `match` || "." ELSE 'The evaluation of `' || `subject` || ' REGEXP ' || `pattern` || '` shall crash with failmessage ' || '''' || `failmessage` || '''' || '.' END ) AS `description` FROM testregexp ; sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/50-run.puml000066400000000000000000000016241416534243400217430ustar00rootroot00000000000000@startuml test-run start group run.sh :Insert into testcampaign (lib, started_at)> while (has next testcase) is (yes) :Select id, execute_sql, evaluate_sql from testcase where id=next< :Insert into testreport> partition "Test Execution" { note The Test Execution is run with a separate and single SQLite connection. -- The process standard output, error and exit code are recorded. end note :.load lib/ :Update testreport set report_value = ((execute_sql))> } :Update testreport set stdout, stderr, exit_code> :Update testreport set evaluation = ((evaluate_sql))> endwhile (no) :update testcampaign set ended_at> end group stop @enduml sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/50-run.sh000077500000000000000000000050201416534243400213750ustar00rootroot00000000000000#!/usr/bin/env sh # This script execute the test. # # The test are based on two input script arguments: # 1) The database. It contains the test specification. # 2) The library to be loaded. # # Note: the library should be provided with a path (`./filename`) and not just # the filename otherwise only an installed library will be searched (see # `man dlopen`). # Preamble of all the shell functions set -e TESTDIR="$( cd "$( dirname "$0" )" && pwd )" . "$TESTDIR/lib.sh" if [ ! -z "$1" ] then DB="$1" fi if [ ! -z "$2" ] then INCLUDE_LIB="$2" fi testcampaign=`sql_call_args ' INSERT INTO testcampaign (started_at, lib) VALUES (julianday(), %s); SELECT last_insert_rowid(); ' "$INCLUDE_LIB"` while true do # Fetch test data into testcase and execute_sql testcase=`sql_call_args ' SELECT testcase.id FROM testcase LEFT JOIN testreport ON testreport.testcase = testcase.id AND testcampaign = %s WHERE testreport.id IS NULL LIMIT 1 ' "$testcampaign"` if [ -z "$testcase" ] then break fi execute_sql=`sql_call_args ' SELECT execute_sql FROM testcase WHERE id = %s ' "$testcase"` # Create testreport record testreport=`sql_call_args " INSERT INTO testreport (testcase, testcampaign) VALUES (%s, %s); SELECT last_insert_rowid(); " "$testcase" "$testcampaign"` # Execute test. Record exit_code and stderr. # logdebug "Update test $testcase with execute_sql='$execute_sql'" set +e stderr=`SQL_LOAD_LIB="$INCLUDE_LIB" NOLOG=1 sql_call_args " UPDATE testreport SET report_value = ( $(sql_printf "$execute_sql" "$testreport" | printf_escape) ) WHERE id = %s; " "$testreport" 2>&1 1>/dev/null` exit_code=$? set -e # logdebug "exit_code: '$exit_code', stderr: '$stderr'" sql_call_args 'UPDATE testreport SET stderr=%s, exit_code=%s WHERE id=%s' \ "$stderr" "$exit_code" "$testreport" evaluate_sql=`sql_call_args 'SELECT evaluate_sql FROM testcase WHERE id=%s' "$testcase"` if [ -z evaluate_sql ] then evaluate_sql='NULL' fi # logdebug "Update test $testcase with evaluate_sql='$evaluate_sql'" sql_call_args " UPDATE testreport SET evaluation = ( $(sql_printf "$evaluate_sql" "$testreport" | printf_escape) ) WHERE id=%s " "$testreport" done sql_call_args 'UPDATE testcampaign SET ended_at=julianday() WHERE id = %s' "$testcampaign" sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/50-run.svg000066400000000000000000000271431416534243400215710ustar00rootroot00000000000000run.shInsert into testcampaign(lib, started_at)Select id, execute_sql, evaluate_sqlfrom testcasewhere id=nextInsert into testreportTest ExecutionThe Test Execution is runwith a separate and singleSQLite connection.--The process standardoutput, error and exitcode are recorded..load libUpdate testreportset report_value = ((execute_sql))Update testreportset stdout, stderr, exit_codeUpdate testreportset evaluation = ((evaluate_sql))yeshas next testcasenoupdate testcampaignset ended_atsqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/70-print-summary.sh000077500000000000000000000022441416534243400234270ustar00rootroot00000000000000#!/usr/bin/env sh set -e TESTDIR="$( cd "$( dirname "$0" )" && pwd )" . "$TESTDIR/lib.sh" testcampaign=`sql_call_args 'SELECT id FROM testcampaign ORDER BY id DESC LIMIT 1'` sql_call_args " SELECT 'Test campaign #' || testcampaign || ' executed in ' || ((ended_at - started_at) * 3600 * 24) || ' seconds' || ' with ' || SUM(NOT evaluation) || ' tests failure' || ', ' || SUM(evaluation IS NULL) || ' tests that cannot be evaluated' || ', and ' || SUM(evaluation) || ' tests successfully passed' FROM testreport JOIN testcampaign ON testcampaign.id = testreport.testcampaign WHERE testreport.testcampaign = %s GROUP BY testreport.testcampaign " "$testcampaign" error_count=`sql_call_args 'SELECT COUNT(*) FROM testreport WHERE testreport.testcampaign = %s AND NOT IFNULL(testreport.evaluation, FALSE)' "$testcampaign"` if [ "$error_count" -ne 0 ] then sql_call_args " .header on SELECT * FROM testreport JOIN testcase ON testcase.id = testreport.testcase WHERE testreport.testcampaign = %s AND NOT IFNULL(testreport.evaluation, FALSE) " "$testcampaign" fi sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/README.md000066400000000000000000000013151416534243400212720ustar00rootroot00000000000000All the test are managed using the database db.sqlite3. The test are run in three steps: 1) Initialisation: create the database schema, and populate the test case table. It defines the tests to be executed. 2) Run: The test case are executed on the base of the schema below. ![](50-run.svg) 3) Report analysis: the table testreport is analysed to show which test are passed or failed. After running the test, the list of test case and test report can be observed by running: ```bash sqlite3 -header -column "db.sqlite3" << SQL SELECT * FROM testreport JOIN testcase ON testreport.testcase = testcase.id WHERE testreport.testcampaign = (SELECT id FROM testcampaign ORDER BY id DESC LIMIT 1) SQL ``` sqlite3-pcre2-0.1.1~git20220105-e3e02a4a/test/lib.sh000066400000000000000000000055541416534243400211260ustar00rootroot00000000000000# Lib that contains the functions used for the test. set -e TESTDIR="$( cd "$( dirname "$0" )" && pwd )" SQLITE=sqlite3 DIR="$(dirname "$TESTDIR")" DB="$TESTDIR/db.sqlite3" # If overriden: the sql_call_stdin and sql_call_args will load this library first. # Note: the library should be provided with a path (`./filename`) and not just # the filename otherwise only an installed library will be searched (see # `man dlopen`). SQL_LOAD_LIB="" sql_escape() { # Escape the string for sqlite # # Example: # # sql_escape "isn't it?" # # => "'isn''t it?'" local sedstr='s/'"'"'/'"''"'/g;1s/^/'"'"'/;$s/$/'"'"'/' if [ "$#" -eq 0 ] then sed "$sedstr" else echo "$1" | sed "$sedstr" fi } sql_printf() { # Like the printf function, but escape the parameter for SQL. # # Example: # # sql_printf "select * from t where col=%s" 1 # # => "select * from t where col='1'" local arg local cmd local lvar local i=1 for arg in "$@" do if [ "$i" -eq 1 ] then cmd="\"\$1\"" else lvar="L$i" eval "local $lvar="'"$(sql_escape "$arg")"' cmd="$cmd \"\$$lvar\"" fi i="$((i+1))" done eval "printf $cmd" } id_escape() { # Escape the string for SQL identifiers. # # Example: # # id_escape "isn`t it?" # # => "`isn``t it?`" local sedstr='s/`/``/g;1s/^/`/;$s/$/`/' if [ "$#" -eq 0 ] then sed "$sedstr" else echo "$1" | sed "$sedstr" fi } printf_escape() { # Escape the string for printf function. # # Example: # # id_escape "10% \ 1" # # => '10%% \\ 1' local sedstr='s/[%\\]/\0\0/g' if [ "$#" -eq 0 ] then sed "$sedstr" else echo "$1" | sed "$sedstr" fi } sql_build_include() { if [ ! -z "$SQL_LOAD_LIB" ] then echo ".load $SQL_LOAD_LIB" fi } sql_call_file() { local "include=$(sql_build_include)" if [ -z "$include" ] then cat "$@" | $SQLITE "$DB" \ || log "based on file $*" else cat "$@" | $SQLITE "$DB" -cmd "$include" \ || log "based on file $*" fi } sql_call_args() { local sql local "include=$(sql_build_include)" local exit_status if [ $# -eq 0 ] then log 'No arguments to sql_call_args' exit 1 elif [ $# -eq 1 ] then sql="$1" else sql=`sql_printf "$@"` fi if [ -z "$include" ] then $SQLITE "$DB" "$sql" \ || log "Based on SQL command: $sql" else $SQLITE "$DB" -cmd "$include" "$sql" \ || log "Based on SQL command: $sql" fi } log() { local "last_return=$?" if [ "$NOLOG" -ne 1 ] then echo "$@" 1>&2 fi return "$last_return" }