summaryrefslogtreecommitdiffstats
path: root/sqlstmt.cc
blob: eca932f5e9bebd082266c31d60053e156f7d6fd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <cassert>
#include <iostream>
#include <memory>
#include <sstream>

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include <notmuch.h>
#include <sqlite3.h>

#include "sqlstmt.h"

using namespace std;

static void
dbthrow (sqlite3 *db, const char *query)
{
  const char *dbpath = sqlite3_db_filename (db, "main");
  if (!dbpath)
    dbpath = "sqlite3 database";
  ostringstream errbuf;
  if (query)
    errbuf << dbpath << ":\n  Query: " << query
	   << "\n  Error: " << sqlite3_errmsg (db);
  else
    errbuf << dbpath << ": " << sqlite3_errmsg (db);
  throw sqlerr_t (errbuf.str ());
}

sqlstmt_t &
sqlstmt_t::set_status (int status)
{
  status_ = status;
  if (status != SQLITE_OK && status != SQLITE_ROW && status != SQLITE_DONE)
    dbthrow (sqlite3_db_handle (stmt_), nullptr);
  return *this;
}

void
sqlstmt_t::fail ()
{
  assert (status_ != SQLITE_OK);
  if (status_ == SQLITE_DONE)
    throw sqldone_t(string ("No rows left in query: ") + sqlite3_sql (stmt_));
  else
    throw sqlerr_t(string ("sqlstmt_t::operator[]: used after error\n"
			   "  Query: ") + sqlite3_sql (stmt_)
		   + "\n  Error: " + sqlite3_errstr(status_));
}

sqlstmt_t::sqlstmt_t (sqlite3 *db, const char *fmt, ...)
{
  va_list ap;
  va_start (ap, fmt);
  char *query = sqlite3_vmprintf(fmt, ap);
  va_end (ap);

  if (!query)
    throw sqlerr_t ("sqlite3_vmprintf: out of memory");
  unique_ptr<char, decltype(&sqlite3_free)> _c (query, sqlite3_free);

  const char *tail;
  if (sqlite3_prepare_v2(db, query, -1, &stmt_, &tail))
    dbthrow (db, query);
  if (tail && *tail)
    throw sqlerr_t (string("illegal compound query\n  Query:  ") + query);
}

sqlstmt_t::sqlstmt_t(const sqlstmt_t &l)
{
  int err = sqlite3_prepare_v2(sqlite3_db_handle(l.stmt_),
			       sqlite3_sql(l.stmt_), -1, &stmt_, nullptr);
  if (err)
    throw sqlerr_t (string("could not copy query\n  Query:  ")
		    + sqlite3_sql(l.stmt_) + "\n  Error:  "
		    + sqlite3_errstr(err) + "\n");
}

void
sqlexec (sqlite3 *db, const char *fmt, ...)
{
  char *query;
  va_list ap;
  va_start (ap, fmt);
  query = sqlite3_vmprintf (fmt, ap);
  unique_ptr<char, decltype(&sqlite3_free)> _c (query, sqlite3_free);
  va_end (ap);
  if (!query)
    throw sqlerr_t ("sqlite3_vmprintf: out of memory in sqlexec");
  int err = sqlite3_exec (db, query, NULL, NULL, NULL);
  if (err != SQLITE_OK && err != SQLITE_DONE && err != SQLITE_ROW)
    dbthrow (db, query);
}