variant.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 
3 /*
4  * Copyright (c) 2020, Bjarne von Horn
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  * * Neither the name of the copyright holder nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL BJARNE VON HORN BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #pragma once
31 
32 #include <boost/variant.hpp>
33 #include <string>
34 #include <sstream>
35 #include <sqlite3.h>
38 
39 namespace warehouse_ros_sqlite
40 {
41 class BindVisitor : boost::static_visitor<int>
42 {
43  sqlite3_stmt* stmt_;
44  int idx_;
45 
46 public:
47  BindVisitor(sqlite3_stmt* stmt, int start_idx = 1) : stmt_(stmt), idx_(start_idx)
48  {
49  }
50  int operator()(int i)
51  {
52  return sqlite3_bind_int64(stmt_, idx_++, i);
53  }
54  int operator()(double d)
55  {
56  return sqlite3_bind_double(stmt_, idx_++, d);
57  }
58  int operator()(const std::string& s)
59  {
60  return sqlite3_bind_blob64(stmt_, idx_++, s.data(), s.size(), SQLITE_STATIC);
61  }
62  int operator()(NullValue /* unused */)
63  {
64  return sqlite3_bind_null(stmt_, idx_++);
65  }
66  int getTotalBinds() const
67  {
68  return idx_ - 1;
69  }
70 };
71 
72 class EnsureColumnVisitor : boost::static_visitor<>
73 {
74  sqlite3* db_;
75  std::string unescaped_tablename_;
77  std::string unescaped_colname_;
78  bool columnExists()
79  {
80  const std::string colname(schema::METADATA_COLUMN_PREFIX + unescaped_colname_);
81  return sqlite3_table_column_metadata(db_, schema::DB_NAME, unescaped_tablename_.c_str(), colname.c_str(), nullptr,
82  nullptr, nullptr, nullptr, nullptr) == SQLITE_OK;
83  }
84  void addColumn(const char* datatype)
85  {
86  std::ostringstream query_builder;
87  query_builder << "ALTER TABLE " << escaped_tablename_ << " ADD "
88  << schema::escape_columnname_with_prefix(unescaped_colname_) << " " << datatype << ";";
89  if (sqlite3_exec(db_, query_builder.str().c_str(), nullptr, nullptr, nullptr) != SQLITE_OK)
90  {
91  throw InternalError("could not create column", db_);
92  }
93  }
94 
95 public:
96  EnsureColumnVisitor(sqlite3* db, const std::string& unescaped_tablename)
97  : db_(db)
98  , unescaped_tablename_(unescaped_tablename)
99  , escaped_tablename_(schema::escape_identifier(unescaped_tablename))
100  {
101  }
102  void operator()(int /*unused*/)
103  {
104  if (!columnExists())
105  addColumn("INTEGER");
106  }
107  void operator()(double /*unused*/)
108  {
109  if (!columnExists())
110  addColumn("FLOAT");
111  }
112  void operator()(const std::string& /*unused*/)
113  {
114  if (!columnExists())
115  addColumn("BLOB");
116  }
117  void operator()(NullValue /* unused */)
118  {
119  if (!columnExists())
120  throw std::runtime_error("not implemented");
121  }
122  EnsureColumnVisitor& setColumnName(const std::string& unescaped_column)
123  {
124  unescaped_colname_ = unescaped_column;
125  return *this;
126  }
127 };
128 
129 namespace detail
130 {
131 template <typename R, typename T>
133 {
134  static R get(T /* unused */)
135  {
136  throw boost::bad_get();
137  }
138 };
139 
140 template <typename R>
141 struct NullValueGet<R, typename std::enable_if<!std::is_same<R, NullValue>::value, R>::type>
142 {
143  static R get(R r)
144  {
145  return std::forward<R>(r);
146  }
147 };
148 
149 template <typename R>
151 {
152  static R get(NullValue /* unused */)
153  {
154  return R();
155  }
156 };
157 
158 } // namespace detail
159 
160 template <typename R>
161 struct NullValueVisitor : boost::static_visitor<R>
162 {
163  template <typename T>
164  R operator()(T t) const
165  {
166  return detail::NullValueGet<R, T>::get(std::forward<T>(t));
167  }
168 };
169 } // namespace warehouse_ros_sqlite
BindVisitor(sqlite3_stmt *stmt, int start_idx=1)
Definition: variant.h:47
EnsureColumnVisitor & setColumnName(const std::string &unescaped_column)
Definition: variant.h:122
int operator()(const std::string &s)
Definition: variant.h:58
std::string escaped_tablename
Definition: utils.h:97
constexpr const char * DB_NAME
Definition: utils.h:83
void operator()(const std::string &)
Definition: variant.h:112
schema::escaped_tablename escaped_tablename_
Definition: variant.h:76
escaped_columnname escape_columnname_with_prefix(const std::string &c)
Definition: utils.h:102
EnsureColumnVisitor(sqlite3 *db, const std::string &unescaped_tablename)
Definition: variant.h:96
std::string escape_identifier(const std::string &s)
Definition: utils.h:98
void addColumn(const char *datatype)
Definition: variant.h:84
constexpr const char * METADATA_COLUMN_PREFIX
Definition: utils.h:84


warehouse_ros_sqlite
Author(s): Bjarne von Horn
autogenerated on Fri Nov 11 2022 03:44:33