# $Id: sqlite3dbm.sno,v 1.9 2020-01-17 06:53:08 phil Exp $
# database compatible with Pythonn sqlite3dbm
**=pea
**=sect NAME
**snobol4sqlite3dbm \- "dbm" style interface for SNOBOL4 using SQLite3
**=cut
-include "sqlite3.sno"
*
	SQL3DBM_CREATE = 'CREATE TABLE IF NOT EXISTS kv_table ('
+				'key TEXT PRIMARY KEY,'
+				'val TEXT)'
	SQL3DBM_SET = 'INSERT INTO kv_table (key, val) VALUES (?, ?)'
	SQL3DBM_REP = 'INSERT OR REPLACE INTO kv_table (key, val)'
+				' VALUES (?, ?)'
	SQL3DBM_GET = 'SELECT val FROM kv_table WHERE key = ?'
	SQL3DBM_DEL = 'DELETE FROM kv_table WHERE key = ?'
	SQL3DBM_KEYS = 'SELECT key FROM kv_table'
*
	SQL3DBM_CURSORS = TABLE()
*
**=pea
**=sect SYNOPSIS
**=code
**-INCLUDE 'sqlite3dbm.3'
**
**        dbhandle = SQL3DBM_OPEN(file,flags,mode)
**
**        SQL3DBM_CLOSE(dbhandle)
**
**        SQL3DBM_STORE(dbhandle,key,datum,flags)
**
**        datum = SQL3DBM_FETCH(dbhandle,key)
**
**        SQL3DBM_DELETE(dbhandle,key)
**
**        key = SQL3DBM_FIRSTKEY(dbhandle)
**
**        key = SQL3DBM_NEXTKEY(dbhandle)
**
**        SQL3DBM_ERRMSG(dbhandle)
**=ecode
**=sect DESCRIPTION
**A DBM compatible interface for B<snobol4>(1) using the B<sqlite3>
**embedded database engine, and allows concurrent access by multiple
**processes.
**=item B<SQL3DBM_OPEN>
**takes a filename (STRING), and ignores any additional arguments, and
**returns a database handle.
**=item B<SQL3DBM_CLOSE>
**takes a database handle and closes it.
**=item B<SQL3DBM_STORE>
**takes a database handle, a key, a value, and a flag,
**one of B<SQL3DBM_INSERT> or B<SQL3DBM_REPLACE>.
**=item B<SQL3DBM_FETCH>
**takes a database handle and a key and returns a datum (if any) stored with
**that key.
**=item B<SQL3DBM_DELETE>
**takes a database handle and a key and deletes the stored datum (if any).
**=item B<SQL3DBM_FIRSTKEY>
**takes a database handle and returns a database key.
**=item B<SQL3DBM_NEXTKEY>
**takes a database handle and returns a database key
**when called after B<SQL3DBM_FIRSTKEY>.
**=item B<SQL3DBM_ERRMSG>
**takes a database handle and string for the last B<sqlite3> database error.
**=cut
	DEFINE("SQL3DBM_OPEN(file,flags,mode)conn,dbh,data")
	DEFINE("SQL3DBM_CLOSE(dbh)")
	DEFINE("SQL3DBM_STORE(dbh,key,val,flags)stmt,sql")
	DEFINE("SQL3DBM_FETCH(dbh,key)stmt")
	DEFINE("SQL3DBM_DELETE(dbh,key)stmt")
	DEFINE("SQL3DBM_FIRSTKEY(dbh)")
	DEFINE("SQL3DBM_NEXTKEY(dbh)tmp")
	DEFINE("SQL3DBM_ERRMSG(dbh)")

	SQL3DBM_INSERT = 0
	SQL3DBM_REPLACE = 1

	:(SQL3DBM.END)

SQL3DBM_OPEN
+	SQL3DBM_OPEN = SQLITE3_OPEN(file)		:F(FRETURN)
	SQLITE3_EXEC(SQL3DBM_OPEN, SQL3DBM_CREATE)	:S(RETURN)
	SQLITE3_CLOSE(SQL3DBM_OPEN)			:(FRETURN)
****
SQL3DBM_CLOSE
+	DIFFER(SQL3DBM_CURSORS[dbh]) SQLITE3_FINALIZE(SQL3DBM_CURSORS[dbh])
	SQL3DBM_CURSORS[dbh] =
+	SQLITE3_CLOSE(dbh)				:S(RETURN)F(FRETURN)
****
SQL3DBM_STORE
+	sql = (EQ(flags,SQL3DBM_REPLACE) SQL3DBM_REP, SQL3DBM_SET)
	stmt = SQLITE3_PREPARE(dbh, sql, key, val)	:F(FRETURN)
	IDENT(SQLITE3_STEP(stmt),"done")		:F(SQL3DBM_FINALIZE)
	SQLITE3_FINALIZE(stmt)				:S(RETURN)F(FRETURN)
****
SQL3DBM_FETCH
+	stmt = SQLITE3_PREPARE(dbh, SQL3DBM_GET, key)	:F(FRETURN)
	IDENT(SQLITE3_STEP(stmt),"row")			:F(SQL3DBM_FINALIZE)
	SQL3DBM_FETCH = SQLITE3_COLUMN_VALUE(stmt, 0)	:F(SQL3DBM_FINALIZE)
	SQLITE3_FINALIZE(stmt)				:S(RETURN)F(FRETURN)
****
SQL3DBM_DELETE
+	stmt = SQLITE3_PREPARE(dbh, SQL3DBM_DEL, key)	:F(FRETURN)
	IDENT(SQLITE3_STEP(stmt),"done")		:F(SQL3DBM_FINALIZE)
	SQLITE3_FINALIZE(stmt)				:S(RETURN)F(FRETURN)
****
SQL3DBM_FIRSTKEY
+	SQL3DBM_CURSORS[dbh] = SQLITE3_PREPARE(dbh, SQL3DBM_KEYS) :F(FRETURN)
	SQL3DBM_FIRSTKEY = SQL3DBM_NEXTKEY(dbh)		:S(RETURN)F(FRETURN)
****
SQL3DBM_NEXTKEY
+	IDENT(SQL3DBM_CURSORS[dbh])			:S(FRETURN)
	tmp = SQLITE3_STEP(SQL3DBM_CURSORS[dbh])	:F(FRETURN)
	IDENT(tmp, "done")				:S(SQL3DBM_NEXTKEY_DONE)
	DIFFER(tmp, "row")				:S(FRETURN)
	SQL3DBM_NEXTKEY = SQLITE3_COLUMN_VALUE(SQL3DBM_CURSORS[dbh], 0)
+							:F(FRETURN)S(RETURN)
SQL3DBM_NEXTKEY_DONE
	SQLITE3_FINALIZE(SQL3DBM_CURSORS[dbh])
	SQL3DBM_CURSORS[dbh] =
	SQL3DBM_NEXTKEY =				:(RETURN)
****
SQL3DBM_ERRMSG
+	SQL3DBM_ERRMSG = SQLITE3_ERRMSG(dbh)		:S(RETURN)F(FRETURN)
**** common error tail
SQL3DBM_FINALIZE
+	SQLITE3_FINALIZE(stmt)				:(FRETURN)
****
SQL3DBM.END
**=pea
**=sect COMPATIBILITY
**database compatible with Python sqlite3dbm
**=sect SEE ALSO
**B<snobol4>(1), B<snobol4dbm>(3), B<sqlite3>(1)
**=sect AUTHOR
**Philip L. Budne
**=cut
