sqlite test
authorMichael Wallner <mike@php.net>
Fri, 12 Feb 2016 15:00:17 +0000 (16:00 +0100)
committerMichael Wallner <mike@php.net>
Fri, 12 Feb 2016 15:00:17 +0000 (16:00 +0100)
.gitattributes [new file with mode: 0644]
tests/sqlite/sqlite.psi [new file with mode: 0644]
tests/sqlite/sqlite001.db [new file with mode: 0644]
tests/sqlite/sqlite001.phpt [new file with mode: 0644]

diff --git a/.gitattributes b/.gitattributes
new file mode 100644 (file)
index 0000000..375cd8c
--- /dev/null
@@ -0,0 +1 @@
+/tests/sqlite/sqlite001.db binary
diff --git a/tests/sqlite/sqlite.psi b/tests/sqlite/sqlite.psi
new file mode 100644 (file)
index 0000000..4fea4c6
--- /dev/null
@@ -0,0 +1,70 @@
+lib "sqlite3";
+
+extern const char *sqlite3_libversion(void);
+function sqlite3\version() : string {
+       return to_string(sqlite3_libversion);
+}
+
+extern const char *sqlite3_errstr(int errno);
+function sqlite3\errstr(int $errno) : string {
+       let errno = intval($errno);
+       return to_string(sqlite3_errstr);
+}
+
+/* obviously fake, we ever always need a pointer to it */
+struct sqlite3::(8, 8);
+
+typedef struct sqlite3 sqlite3;
+
+typedef int64_t sqlite_int64;
+typedef uint64_t sqlite_uint64;
+
+typedef sqlite_int64 sqlite3_int64;
+typedef sqlite_uint64 sqlite3_uint64;
+
+extern void sqlite3_free(void *ptr);
+function sqlite3\free(object $object) : void {
+       let ptr = objval($object);
+       return void(sqlite3_free);
+}
+
+extern int sqlite3_close(sqlite3 *db);
+function sqlite3\close(object $db) : int {
+       let db = objval($db);
+       return to_int(sqlite3_close);
+}
+
+extern int sqlite3_open(const char *filename, sqlite3 **db_ptr);
+function sqlite3\open(string $uri, object &$db) : int {
+       let filename = pathval($uri);
+       let db_ptr = &NULL;
+       return to_int(sqlite3_open);
+       set $db = to_object(*db_ptr);
+}
+
+typedef int (*sqlite3_callback)(void *data, int argc, char** argv, char** cols);
+
+/*
+ * C calls into us, so we have to have a way to define how the callback 
+ * arguments have to be marshaled for the userland callback, i.e. from 
+ * native C types to ZE zvals /and/ how the userland return value has
+ * to be marshaled to a native type. All in all, the opposite of function impls.
+ */
+
+extern int sqlite3_exec(sqlite3 *db, const char *sql, sqlite3_callback callback, void *data, char **errmsg);
+function sqlite3\exec(object $db, string $sql, callable $cb, mixed $cd, string &$error = null) : int {
+       let db = objval($db);
+       let sql = strval($sql);
+       let callback = callback intval(
+               $cb(
+                       zval(data), 
+                       to_int(argc), 
+                       to_array(argv, argc, to_string(argv)),
+                       to_array(cols, argc, to_string(cols))
+               )
+       );
+       let data = zval($cd);
+       let errmsg = &NULL;
+       return to_int(sqlite3_exec);
+       set $error = to_string(*errmsg);
+}
diff --git a/tests/sqlite/sqlite001.db b/tests/sqlite/sqlite001.db
new file mode 100644 (file)
index 0000000..0800e0e
Binary files /dev/null and b/tests/sqlite/sqlite001.db differ
diff --git a/tests/sqlite/sqlite001.phpt b/tests/sqlite/sqlite001.phpt
new file mode 100644 (file)
index 0000000..41b25e7
--- /dev/null
@@ -0,0 +1,86 @@
+--TEST--
+sqlite3
+--INI--
+psi.directory={PWD}:{PWD}/../../psi.d
+--SKIPIF--
+<?php
+extension_loaded("psi") or printf("%s\n", "skip - need ext/psi");
+function_exists("sqlite3\\open") or printf("%s\n", "skip - need libsqlite3");
+?>
+--FILE--
+===TEST===
+<?php
+
+var_dump(sqlite3\version());
+
+copy(__DIR__."/sqlite001.db", __DIR__."/sqlite001.tmp");
+
+$rc = sqlite3\open(__DIR__."/sqlite001.tmp", $db);
+if ($rc) {
+       printf("%s\n", sqlite3\errstr($rc));
+}
+
+function callback($context, int $argc, array $argv, array $cols) {
+       $context->row = $context->row ?? 0;
+
+       for ($i = 0; $i < $argc; ++$i) {
+               printf("%d: %s = %s\n", $context->row, $cols[$i], $argv[$i] ?? "<NULL>");
+       }
+       printf("\n");
+       ++$context->row;
+}
+
+$rc = sqlite3\exec($db, "SELECT * FROM test", "callback", new stdClass, $error);
+if ($rc) {
+       printf("%s: '%s'\n", sqlite3\errstr($rc), $error);
+}
+
+$rc = sqlite3\exec($db, "INSERT INTO test VALUES (3,'three')", "callback", new stdClass, $error);
+if ($rc) {
+       printf("%s: '%s'\n", sqlite3\errstr($rc), $error);
+}
+
+$rc = sqlite3\exec($db, "SELECT * FROM test", "callback", new stdClass, $error);
+if ($rc) {
+       printf("%s: '%s'\n", sqlite3\errstr($rc), $error);
+}
+
+$rc = sqlite3\exec($db, "SELECT *", "callback", new stdClass, $error);
+if ($rc) {
+       printf("%s: '%s'\n", sqlite3\errstr($rc), $error);
+}
+
+sqlite3\close($db);
+
+$rc = sqlite3\exec($db, "SELECT * FROM test", "callback", new stdClass, $error);
+if ($rc) {
+       printf("%s: '%s'\n", sqlite3\errstr($rc), $error);
+}
+
+?>
+===DONE===
+--EXPECTF--
+===TEST===
+string(%d) "3.%d.%s"
+0: id = 1
+0: data = one
+
+1: id = 2
+1: data = two
+
+0: id = 1
+0: data = one
+
+1: id = 2
+1: data = two
+
+2: id = 3
+2: data = three
+
+SQL logic error or missing database: 'no tables specified'
+library routine called out of sequence: ''
+===DONE===
+--CLEAN--
+<?php
+@unlink(__DIR__."/sqlite001.tmp");
+?>