| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- MODULE SQLiteAggregate;
- (* Aggregate functions, auxdata and the remaining UDF value/result APIs. *)
- FROM SYSTEM IMPORT ADDRESS, ADR;
- FROM CStr IMPORT CString, Copy;
- FROM SQLite IMPORT
- DbHandle, StmtHandle, ContextHandle, ValueHandle,
- SQLiteOk, SQLiteRow, SQLiteDone, SQLiteNull,
- SQLiteInteger, SQLiteText, SQLiteTooBig, SQLiteNoMem,
- SQLiteOpenReadWrite, SQLiteOpenCreate, SQLiteOpenMemory, SQLiteUtf8,
- sqlite3_open_v2, sqlite3_close, sqlite3_exec,
- sqlite3_prepare_v2, sqlite3_step, sqlite3_column_int,
- sqlite3_column_text, sqlite3_finalize,
- sqlite3_create_function_v2,
- sqlite3_value_type, sqlite3_value_int64, sqlite3_value_numeric_type,
- sqlite3_value_dup, sqlite3_value_free,
- sqlite3_aggregate_context, sqlite3_get_auxdata, sqlite3_set_auxdata,
- sqlite3_result_int, sqlite3_result_int64, sqlite3_result_null,
- sqlite3_result_error, sqlite3_result_value, sqlite3_result_zeroblob,
- sqlite3_result_zeroblob64,
- sqlite3_result_text64, sqlite3_result_blob64,
- sqlite3_result_error_toobig, sqlite3_result_error_nomem,
- sqlite3_free, SQLiteArrayAt, SQLiteTransient;
- TYPE
- SumPtr = POINTER TO LONGINT;
- VAR
- ExitCode : INTEGER;
- db : DbHandle;
- stmt : StmtHandle;
- rc : INTEGER;
- ok : BOOLEAN;
- bin, auxMarker : ARRAY [0..7] OF CHAR;
- PROCEDURE SameText (a, b : ARRAY OF CHAR) : BOOLEAN;
- VAR
- i : INTEGER;
- BEGIN
- i := 0;
- WHILE (a[i] # CHR(0)) AND (a[i] = b[i]) DO i := i + 1 END;
- RETURN (a[i] = CHR(0)) AND (b[i] = CHR(0))
- END SameText;
- PROCEDURE ExecSQL (sql : ARRAY OF CHAR) : BOOLEAN;
- VAR
- errmsg : ADDRESS;
- good : BOOLEAN;
- BEGIN
- errmsg := NIL;
- good := sqlite3_exec(db, sql, NIL, NIL, errmsg) = SQLiteOk;
- IF errmsg # NIL THEN sqlite3_free(errmsg) END;
- RETURN good
- END ExecSQL;
- PROCEDURE QueryInt (sql : ARRAY OF CHAR; want : INTEGER) : BOOLEAN;
- VAR
- s : StmtHandle;
- code, got : INTEGER;
- good : BOOLEAN;
- BEGIN
- s := NIL; got := -777; good := FALSE;
- code := sqlite3_prepare_v2(db, sql, -1, s, NIL);
- IF (code = SQLiteOk) AND (s # NIL) THEN
- IF sqlite3_step(s) = SQLiteRow THEN
- got := sqlite3_column_int(s, 0);
- IF sqlite3_step(s) = SQLiteDone THEN good := TRUE END
- END;
- IF sqlite3_finalize(s) # SQLiteOk THEN good := FALSE END
- END;
- RETURN good AND (got = want)
- END QueryInt;
- PROCEDURE QueryText (sql : ARRAY OF CHAR; want : ARRAY OF CHAR) : BOOLEAN;
- VAR
- s : StmtHandle;
- code : INTEGER;
- p : CString;
- buf : ARRAY [0..63] OF CHAR;
- good : BOOLEAN;
- BEGIN
- s := NIL; good := FALSE;
- code := sqlite3_prepare_v2(db, sql, -1, s, NIL);
- IF (code = SQLiteOk) AND (s # NIL) THEN
- IF sqlite3_step(s) = SQLiteRow THEN
- p := sqlite3_column_text(s, 0);
- IF (p # NIL) AND (Copy(p, buf) > 0) THEN
- good := SameText(buf, want)
- END;
- IF sqlite3_step(s) # SQLiteDone THEN good := FALSE END
- END;
- IF sqlite3_finalize(s) # SQLiteOk THEN good := FALSE END
- END;
- RETURN good
- END QueryText;
- PROCEDURE QueryError (sql : ARRAY OF CHAR; want : INTEGER) : BOOLEAN;
- VAR
- s : StmtHandle;
- code : INTEGER;
- good : BOOLEAN;
- BEGIN
- s := NIL; good := FALSE;
- code := sqlite3_prepare_v2(db, sql, -1, s, NIL);
- IF (code = SQLiteOk) AND (s # NIL) THEN
- good := sqlite3_step(s) = want;
- rc := sqlite3_finalize(s)
- END;
- RETURN good
- END QueryError;
- PROCEDURE Register (name : ARRAY OF CHAR; n : INTEGER;
- xFunc, xStep, xFinal : ADDRESS) : BOOLEAN;
- BEGIN
- RETURN sqlite3_create_function_v2(db, name, n, SQLiteUtf8,
- NIL, xFunc, xStep, xFinal, NIL) = SQLiteOk
- END Register;
- PROCEDURE SumStep (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- VAR
- p : SumPtr;
- v : ValueHandle;
- BEGIN
- p := VAL(SumPtr, sqlite3_aggregate_context(ctx, 8));
- IF p # NIL THEN
- v := SQLiteArrayAt(argv, 0);
- IF sqlite3_value_type(v) # SQLiteNull THEN
- p^ := p^ + sqlite3_value_int64(v)
- END
- END
- END SumStep;
- PROCEDURE SumFinal (ctx : ContextHandle);
- VAR
- p : SumPtr;
- BEGIN
- p := VAL(SumPtr, sqlite3_aggregate_context(ctx, 0));
- IF p = NIL THEN
- sqlite3_result_null(ctx)
- ELSE
- sqlite3_result_int64(ctx, p^)
- END
- END SumFinal;
- PROCEDURE AuxFn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- VAR
- p, q : ADDRESS;
- BEGIN
- p := ADR(auxMarker[0]);
- sqlite3_set_auxdata(ctx, 0, p, NIL);
- q := sqlite3_get_auxdata(ctx, 0);
- IF q = p THEN
- sqlite3_result_int(ctx, 1)
- ELSE
- sqlite3_result_int(ctx, 0)
- END
- END AuxFn;
- PROCEDURE DupFn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- VAR
- v, d : ValueHandle;
- BEGIN
- IF argc = 1 THEN
- v := SQLiteArrayAt(argv, 0);
- d := sqlite3_value_dup(v);
- IF d = NIL THEN
- sqlite3_result_error(ctx, "dup failed", -1)
- ELSE
- sqlite3_result_value(ctx, d);
- sqlite3_value_free(d)
- END
- ELSE
- sqlite3_result_error(ctx, "m2_dup expects 1 argument", -1)
- END
- END DupFn;
- PROCEDURE NumTypeFn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- BEGIN
- IF argc = 1 THEN
- sqlite3_result_int(ctx,
- sqlite3_value_numeric_type(SQLiteArrayAt(argv, 0)))
- ELSE
- sqlite3_result_error(ctx, "m2_numtype expects 1 argument", -1)
- END
- END NumTypeFn;
- PROCEDURE Zero32Fn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- BEGIN
- sqlite3_result_zeroblob(ctx, 4)
- END Zero32Fn;
- PROCEDURE Zero64Fn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- VAR
- code : INTEGER;
- BEGIN
- code := sqlite3_result_zeroblob64(ctx, 4);
- IF code # SQLiteOk THEN
- sqlite3_result_error(ctx, "zeroblob64 failed", -1)
- END
- END Zero64Fn;
- PROCEDURE Text64Fn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- BEGIN
- sqlite3_result_text64(ctx, "hi", 2, SQLiteTransient(), SQLiteUtf8)
- END Text64Fn;
- PROCEDURE Blob64Fn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- BEGIN
- sqlite3_result_blob64(ctx, ADR(bin[0]), 3, SQLiteTransient())
- END Blob64Fn;
- PROCEDURE TooBigFn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- BEGIN
- sqlite3_result_error_toobig(ctx)
- END TooBigFn;
- PROCEDURE NoMemFn (ctx : ContextHandle; argc : INTEGER; argv : ADDRESS);
- BEGIN
- sqlite3_result_error_nomem(ctx)
- END NoMemFn;
- BEGIN
- ExitCode := 1;
- db := NIL; stmt := NIL; ok := FALSE;
- bin[0] := CHR(0); bin[1] := CHR(1); bin[2] := CHR(2);
- auxMarker[0] := 'A';
- IF (sqlite3_open_v2(":memory:", db,
- SQLiteOpenReadWrite + SQLiteOpenCreate + SQLiteOpenMemory,
- NIL) = SQLiteOk) AND (db # NIL)
- AND ExecSQL("CREATE TABLE nums(x INTEGER);")
- AND ExecSQL("INSERT INTO nums VALUES(1);")
- AND ExecSQL("INSERT INTO nums VALUES(2);")
- AND ExecSQL("INSERT INTO nums VALUES(3);") THEN
- ok := TRUE
- END;
- IF ok THEN
- ok := Register("m2_sum", 1, NIL, ADR(SumStep), ADR(SumFinal))
- AND QueryInt("SELECT m2_sum(x) FROM nums;", 6)
- END;
- IF ok THEN
- ok := Register("m2_aux", 0, ADR(AuxFn), NIL, NIL)
- AND QueryInt("SELECT m2_aux();", 1)
- END;
- IF ok THEN
- ok := Register("m2_dup", 1, ADR(DupFn), NIL, NIL)
- AND QueryText("SELECT m2_dup('abc');", "abc")
- END;
- IF ok THEN
- ok := Register("m2_numtype", 1, ADR(NumTypeFn), NIL, NIL)
- AND QueryInt("SELECT m2_numtype('42');", SQLiteInteger)
- END;
- IF ok THEN
- ok := Register("m2_zero32", 0, ADR(Zero32Fn), NIL, NIL)
- AND QueryText("SELECT hex(m2_zero32());", "00000000")
- END;
- IF ok THEN
- ok := Register("m2_zero64", 0, ADR(Zero64Fn), NIL, NIL)
- AND QueryText("SELECT hex(m2_zero64());", "00000000")
- END;
- IF ok THEN
- ok := Register("m2_text64", 0, ADR(Text64Fn), NIL, NIL)
- AND QueryText("SELECT m2_text64();", "hi")
- END;
- IF ok THEN
- ok := Register("m2_blob64", 0, ADR(Blob64Fn), NIL, NIL)
- AND QueryText("SELECT hex(m2_blob64());", "000102")
- END;
- IF ok THEN
- ok := Register("m2_toobig", 0, ADR(TooBigFn), NIL, NIL)
- AND QueryError("SELECT m2_toobig();", SQLiteTooBig)
- END;
- IF ok THEN
- ok := Register("m2_nomem", 0, ADR(NoMemFn), NIL, NIL)
- AND QueryError("SELECT m2_nomem();", SQLiteNoMem)
- END;
- IF db # NIL THEN
- IF sqlite3_close(db) # SQLiteOk THEN ok := FALSE END
- END;
- IF ok THEN ExitCode := 42 END
- END SQLiteAggregate.
|