#include "utf8.h"
#include <exception>
+//#define DB5_DBDIR_HACK 1
#define DEFAULT_RETRY 10
#ifdef BDB5SQLITE
#define kEXT_SQLITE3 ".db5sql"
*/
+static void randomSleep () {
+ usleep (10000 + 100000 * randDouble ());
+}
+
int MLSqlite3::open (ustring& name) {
int rc;
+ int flags = SQLITE_OPEN_READWRITE;
if (initfunc () && ! isPlainFile (name)) {
- rc = sqlite3_open_v2 (name.c_str (), &dbh, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+ flags |= SQLITE_OPEN_CREATE;
finit = true;
+ } else if (fcreate) {
+ flags |= SQLITE_OPEN_CREATE;
} else {
- if (fcreate) {
- rc = sqlite3_open_v2 (name.c_str (), &dbh, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
- } else {
- rc = sqlite3_open_v2 (name.c_str (), &dbh, SQLITE_OPEN_READWRITE, NULL);
- }
}
+
+ rc = sqlite3_open_v2 (name.c_str (), &dbh, flags, NULL);
if (! rc) {
sqlite3_busy_timeout (dbh, 60000);
dbst = NULL;
}
}
-int MLSqlite3::prepare (ustring& sql) {
+int MLSqlite3::prepare (const ustring& sql) {
int rc;
#ifdef DEBUG
*mlenv->log << "\t" << sql << "\n";
}
#endif /* DEBUG */
- rc = sqlite3_prepare_v2 (dbh, sql.c_str (), sql.length (), &dbst, NULL);
+ rc = sqlite3_prepare_v2 (dbh, sql.c_str (), sql.length (), &dbst, NULL);
+ if (rc != SQLITE_OK) {
+ postError (ustring (CharConst ("SQL error: ")) + sqlite3_errmsg (dbh));
+ }
return rc;
}
mlenv->breakProg ();
}
-#if 0
-void MLSqlite3::answer (namearray& vars) {
- int i;
- int n = vars.size ();
- MNodePtr h;
-
- if (isReady ()) {
- for (i = 0; i < n; i ++) {
- if (i < ncols) {
- if (sqlite3_column_type (dbst, i) == SQLITE_NULL) {
- mlenv->setVar (*vars[i], NULL);
- } else {
- ustring* v = new ustring (char_type (sqlite3_column_text (dbst, i)), sqlite3_column_bytes (dbst, i));
- h = newMNode_str (v);
- mlenv->setVar (*vars[i], h ());
- }
- } else {
- mlenv->setVar (*vars[i], NULL);
- }
- }
- }
-}
-#endif
-#if 0
-void MLSqlite3::answer (namearray& vars, int idx) {
- int i;
- int n = vars.size ();
- MNodePtr h;
-
- if (isReady ()) {
- for (i = 0; i < n; i ++) {
- if (i < ncols) {
- if (sqlite3_column_type (dbst, i) == SQLITE_NULL) {
- mlenv->setAry (*vars[i], idx, NULL);
- } else {
- ustring* v = new ustring (char_type (sqlite3_column_text (dbst, i)), sqlite3_column_bytes (dbst, i));
- h = newMNode_str (v);
- mlenv->setAry (*vars[i], idx, h.p);
- }
- } else {
- mlenv->setAry (*vars[i], idx, NULL);
- }
- }
- }
-}
-#endif
-#if 0
-void MLSqlite3::answer_ary (MLSqlite3::fsqlParam& par) {
- int n = 0;
-
- while (isReady ()) {
- n ++;
- answer (par.answer, n);
- if (n >= limit && limit > 0)
- break;
- step ();
- }
- for (int i = 0; i < par.answer.size (); i ++) {
- mlenv->setArySize (*par.answer[i], n);
- }
-}
-#endif
-
MNode* MLSqlite3::answer_list () {
MNodeList ans;
int i;
}
}
-int MLSqlite3::sql (ustring query) {
- int rc;
-
- rc = prepare (query);
- if (rc == SQLITE_OK) {
- rc = sqlite3_step (dbst);
-#if 0
- switch (rc) {
- case SQLITE_DONE:
- break;
- case SQLITE_BUSY:
- break;
- case SQLITE_LOCKED:
- break;
- default:;
- }
-#endif
- finalize ();
- }
- return rc;
-}
-
int MLSqlite3::sql_s (const ustring& query) {
int rc;
int n = 0;
+ rc = prepare (query);
+ if (rc != SQLITE_OK)
+ return rc;
do {
- rc = sql (query);
+ rc = sqlite3_step (dbst);
if (rc == SQLITE_DONE || rc == SQLITE_ROW)
break;
n ++;
if (n > 10) {
mlenv->env->logMessage (ustring (CharConst ("begin busy.")));
mlenv->breakProg ();
+ break;
+ } else {
+ randomSleep ();
}
- // usleep (1000000 + 3000000 * randDouble ());
} while (1);
return rc;
mlenv->setBreakval (NULL);
}
+ustring MLSqlite3::errmsg () {
+ return ustring (sqlite3_errmsg (dbh));
+}
+
static void setDirFunc (MLFunc* mobj) {
MLSqlite3* obj = MObjRef<MLSqlite3> (mobj, cMLSqlite3ID);
ustring u = mobj->mlenv->env->path_to_db ();
-#ifndef BDB5SQLITE /* XXX */
+#ifdef BDB5SQLITE
+#ifdef DB5_DBDIR_HACK
+ sqlite3_set_dbdir (obj->dbh, u.c_str ());
+#endif
+#else
sqlite3_set_dbdir (obj->dbh, u.c_str ());
#endif
}
dbfile = mlenv->env->path_db (db, kEXT_SQLITE3);
obj.finit = false;
if (! obj.open (dbfile))
- throw (ustring ("unable to open database file."));
+// throw (ustring ("unable to open database file."));
+ throw (obj.errmsg ());
mlenv->setMStack (&obj);
{
return mlenv->retval = ans ();
}
-#if 0
-static void pushAnswer (MlEnv* mlenv, MNode* cell, MNode*& arg, MLSqlite3::namearray& answer) {
- ustring* u;
- MNodePtr v;
- MNode* c;
-
- v = eval (arg, mlenv);
- answer.clear ();
- if (v () && v ()->isCons()) {
- c = v ();
- while (c) {
- u = new ustring ();
- if (c->car ())
- *u = c->car ()->to_string ();
- answer.push_back (u);
- nextNode (c);
- }
- } else {
- u = new ustring;
- if (v ())
- *u = v ()->to_string ();
- answer.push_back (u);
- }
-}
-#endif
-
static void bindParam (MNode* p, MLSqlite3::fsqlParam& par, MLSqlite3* obj) {
AutoDelete<ustring> key;
AutoDelete<ustring> val;
MNode* rest;
static paramList kwlist[] = {
{CharConst ("bind"), false},
-// {CharConst ("answer"), false},
-// {CharConst ("@answer"), false},
{NULL, 0, 0}
};
p = eval (keywords[0], mlenv);
bindParam (p (), par, obj);
}
-#if 0
- if (keywords[1]) { // answer
- mode = 1;
- par.answerisary = false;
- pushAnswer (mlenv, cell, keywords[1], par.answer);
- }
- if (keywords[2]) { // @answer
- mode = 1;
- par.answerisary = true;
- pushAnswer (mlenv, cell, keywords[2], par.answer);
- }
-#endif
if (mode == 0) {
while (rest) {
-// u2 = new ustring (eval_str (rest->car (), mlenv));
-// par.bindValue.push_back (u2.release ());
p = eval (rest->car (), mlenv);
nextNode (rest);
if (p ()) {
if (rest)
throw (uErrorBadArg);
-#ifdef DEBUG2
- {
- MLSqlite3::namearray::iterator it1, it2;
- int c;
-
- std::cerr << "sql " << sql << "\n";
- if (mode == 1) {
- for (it1 = bindName.begin (), it2 = bindValue.begin (); it1 != bindName.end (); it1 ++, it2 ++) {
- std::cerr << " :bind " << *it1 << " " << *it2 << "\n";
- }
- } else {
- for (it2 = bindValue.begin (); it2 != bindValue.end (); it2 ++) {
- std::cerr << " " << *it2 << "\n";
- }
- }
-#if 0
- if (answer.size () > 0) {
- if (answerisary)
- std::cerr << " :@answer '(";
- else
- std::cerr << " :answer '(";
- for (c = 0, it1 = answer.begin (); it1 != answer.end (); it1 ++) {
- if (c > 0)
- std::cerr << " ";
- c ++;
- std::cerr << *it1;
- }
- std::cerr << ")\n";
- }
-#endif
- }
-#endif /* DEBUG2 */
-
rc = obj->prepare (par.sql);
if (rc == SQLITE_OK) {
if (mode == 2) {
obj->bind (par.bindName, par.bindValue);
}
obj->exec ();
-#if 0
- if (par.answer.size () > 0) {
+ if (obj->isReady ()) {
if (par.answerisary) {
- if (obj->isReady ()) {
- obj->answer_ary (par);
- } else {
- for (int i = 0; i < par.answer.size (); i ++) {
- mlenv->setArySize (*par.answer[i], 0);
- }
- }
+ ans = obj->answer_list_ary ();
} else {
- if (obj->isReady ()) {
- obj->answer (par.answer);
- obj->finalize ();
- } else {
- for (int i = 0; i < par.answer.size (); i ++) {
- mlenv->setVar (*par.answer[i], NULL);
- }
- }
+ ans = obj->answer_list ();
}
- } else {
-#endif
- if (obj->isReady ()) {
- if (par.answerisary) {
- ans = obj->answer_list_ary ();
- } else {
- ans = obj->answer_list ();
- }
- }
-#if 0
}
-#endif
} else { // ! SQLITE_OK
- obj->postError (ustring (CharConst ("SQL error: ")) + sqlite3_errmsg (obj->dbh));
+// obj->postError (ustring (CharConst ("SQL error: ")) + sqlite3_errmsg (obj->dbh));
}
return ans.release ();
MNode* ml_sqlite3_begin_transaction (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
MNode* arg = cell->cdr ();
MLSqlite3* obj = MObjRef<MLSqlite3> (mobj, cMLSqlite3ID);
-// int retry = 0;
bool fexclusive = false;
bool fbeginquery = false;
MNodePtr abendfunc;