HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_SQL.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_SQL.h
7  *
8  * COMMENTS:
9  * C++ Wrapper around sqlite
10  */
11 
12 #ifndef __UT_SQL_H__
13 #define __UT_SQL_H__
14 
15 #include "UT_API.h"
16 
17 #include "UT_DateTimeField.h"
18 #include "UT_Debug.h"
19 #include "UT_Error.h"
20 #include "UT_ErrorCode.h"
21 #include "UT_SharedPtr.h"
22 #include "UT_StringHolder.h"
23 #include "UT_UniquePtr.h"
24 #include "UT_Function.h"
25 #include "UT_StringArray.h"
26 
27 #include <SYS/SYS_Compiler.h>
28 #include <SYS/SYS_Inline.h>
29 
30 #include <map>
31 #include <tuple>
32 #include <optional>
33 
34 class UT_SqlDatabase;
35 class UT_SqlBaseDriver;
36 class UT_Options;
37 class UT_SqlStatement;
39 class UT_ArrayStringSet;
40 
41 class sqlite3;
42 class sqlite3_stmt;
43 
44 #define NO_DISCARD SYS_NO_DISCARD_RESULT
45 
46 // NB: An actual namespace is used here because std::error_code does an ADL
47 // lookup when creating std::error_code with just the enum class. This allows us
48 // to do `if (ec == UT::SqlError::UT_SQL_HAS_STEPPED)` instead of
49 // `if (ec == UTmakeErrorCode(UT_SqlError::UT_SQL_HAS_STEPPED))`
50 namespace UT
51 {
52 /// Error codes to describe errors as a result of UT_SQL
53 enum class SqlError
54 {
55  UT_SQL_OK = 0,
60 };
61 
64 
65 inline UT_ErrorCode
67 {
68  return UT_ErrorCode{static_cast<int>(e), GetSqlErrorCategory()};
69 }
70 } // namespace UT
71 
72 namespace std
73 {
74  template <> struct is_error_code_enum<UT::SqlError> : true_type
75  {
76  };
77 }
78 
79 namespace UT
80 {
81 template <typename SqlT, typename T, typename = std::void_t<>>
82 inline constexpr bool has_sql_bind_v = false;
83 
84 template <typename SqlT, typename T>
85 inline constexpr bool has_sql_bind_v<
86  SqlT,
87  T,
88  std::void_t<decltype(UTsqlBind(
89  std::declval<SqlT &>(),
90  0,
91  std::declval<const T &>()))>>
92  = true;
93 
94 template <typename SqlT, typename T, typename = std::void_t<>>
95 inline constexpr bool has_sql_get_v = false;
96 
97 template <typename SqlT, typename T>
98 inline constexpr bool has_sql_get_v<
99  SqlT,
100  T,
101  std::void_t<decltype(UTsqlGet(
102  std::declval<SqlT &>(),
103  0,
104  std::declval<T &>()))>>
105  = true;
106 
107 template <typename SqlT, typename T, typename = std::void_t<>>
108 inline constexpr bool is_sql_type_v = false;
109 
110 template <typename SqlT, typename T>
111 inline constexpr bool is_sql_type_v<
112  SqlT,
113  T,
114  std::void_t<decltype(std::declval<SqlT>().bind(0, std::declval<T>()))>>
115  = true;
116 } // namespace UT
117 
119 {
120 public:
121  UT_SqlStatementHandleId(const char* source_file, exint source_line) :
122  mySourceFile(source_file), mySourceLine(source_line)
123  {}
124 
125  bool operator<(const UT_SqlStatementHandleId& id) const
126  {
127  if (mySourceLine != id.mySourceLine)
128  return mySourceLine < id.mySourceLine;
129  return SYSstrcmp(mySourceFile, id.mySourceFile) < 0;
130  }
131 private:
132  const char* mySourceFile;
133  exint mySourceLine;
134 };
135 
136 #define UT_SQL_ID UT_SqlStatementHandleId(__FILE__, __LINE__)
137 
139 {
140 public:
141  struct null_tag_t {};
142  struct Blob
143  {
144  const void* myPtr = nullptr;
145  std::size_t mySize = 0;
146  bool myIsStatic = true;
147  };
148  enum DataType
149  {
150  kUnknown = -1,
155  kNull
156  };
157 
158  virtual ~UT_SqlStatementImpl() = default;
160 
161  const UT_SqlBaseDriver& driver() const
162  {
163  return myDriver;
164  }
165 
166  virtual void reset(bool clear_bindings = false) = 0;
167 
168  virtual void prepare(const UT_StringRef &sql, UT_ErrorCode *ec = nullptr)
169  = 0;
170 
171  NO_DISCARD virtual int columnAsInt(int idx) const = 0;
172  NO_DISCARD virtual bool columnAsBool(int idx) const = 0;
173  NO_DISCARD virtual int64 columnAsInt64(int idx) const = 0;
174  NO_DISCARD virtual UT_StringHolder columnAsStr(int idx) const = 0;
175  NO_DISCARD virtual double columnAsDouble(int idx) const = 0;
176  NO_DISCARD virtual UT_IntArray columnAsIntArray(int idx) const = 0;
177  NO_DISCARD virtual UT_Int64Array columnAsInt64Array(int idx) const = 0;
178  NO_DISCARD virtual UT_DateTimeField columnAsDate(int idx) const = 0;
179  // Stores size of blob in bytes in 'size'.
180  NO_DISCARD virtual const void *columnAsBlob(int idx, int &size) const = 0;
181  NO_DISCARD virtual Blob columnAsBlob(int idx) const = 0;
182  NO_DISCARD virtual null_tag_t columnAsNull(int idx) const = 0;
183  NO_DISCARD virtual UT_StringHolder columnName(int idx) const = 0;
184  NO_DISCARD virtual int columnCount() const = 0;
185  NO_DISCARD virtual DataType columnType(int idx) const = 0;
186  NO_DISCARD virtual int columnBytes(int idx) const = 0;
187 
188  virtual const UT_StringHolder& intTypeString() const = 0;
189  virtual const UT_StringHolder& bigIntTypeString() const = 0;
190  virtual const UT_StringHolder& stringTypeString() const = 0;
191  virtual const UT_StringHolder& nullTypeString() const = 0;
192  virtual const UT_StringHolder& realTypeString() const = 0;
193  virtual const UT_StringHolder& blobTypeString() const = 0;
194  virtual const UT_StringHolder& dateTimeTypeString() const = 0;
195  virtual const UT_StringHolder& boolTypeString() const = 0;
196 
197  // The original text of the sql statement. Do not keep a pointer to it.
198  virtual const char* sql() const = 0;
199 
200  // Add more binds as needed
201  // This binds a NULL
202  virtual bool bind(int idx, null_tag_t) = 0;
203  virtual bool bind(int idx, const UT_StringRef &value) = 0;
204  virtual bool bind(int idx, const char *value) = 0;
205  virtual bool bind(int idx, int value) = 0;
206  virtual bool bind(int idx, int64 value) = 0;
207  virtual bool bind(int idx, bool value) = 0;
208  virtual bool bind(int idx, double value) = 0;
209  // The following methods bind arrays as strings of the form [#, #, ..., #]
210  virtual bool bind(int idx, const UT_IntArray &value) = 0;
211  virtual bool bind(int idx, const UT_Int64Array &value) = 0;
212  virtual bool bind(int idx, const UT_StringArray &value) = 0;
213  virtual bool bind(int idx, const UT_DateTimeField& dt) = 0;
214  // For binding blobs. `size` is required in bytes. Note that this
215  // function does not destroy `value`.
216  virtual bool bind(
217  int idx,
218  const void *value,
219  int size,
220  bool is_static = true)
221  = 0;
222  bool bind(int idx, Blob blob)
223  {
224  return this->bind(idx, blob.myPtr, blob.mySize, blob.myIsStatic);
225  }
226 
227  NO_DISCARD virtual bool isValid() const = 0;
228 
229  const UT_ErrorCode &getError() const { return myError; }
230 
231  // Called when there are rows to iterate over (i.e. SELECT).
232  virtual bool step() = 0;
233  virtual bool run() = 0;
234 
235  virtual int changes() const = 0;
236 
237  virtual bool hasRow() = 0;
238 
239  NO_DISCARD virtual bool tableExists(
240  const UT_StringRef &name,
241  UT_ErrorCode *ec = nullptr) const
242  = 0;
243 
244 protected:
246  myDriver(driver)
247  {}
248 
251 };
252 
254 {
255 public:
257  const UT_SqlBaseDriver &driver,
258  const UT_StringRef &sql);
260  ~UT_SqliteStatementImpl() override;
262 
263  void reset(bool clear_bindings = false) override final;
264 
265  NO_DISCARD int columnAsInt(int idx) const override final;
266  NO_DISCARD bool columnAsBool(int idx) const override final;
267  NO_DISCARD int64 columnAsInt64(int idx) const override final;
268  NO_DISCARD UT_StringHolder columnAsStr(int idx) const override final;
269  NO_DISCARD double columnAsDouble(int idx) const override final;
270  NO_DISCARD UT_IntArray columnAsIntArray(int idx) const override final;
271  NO_DISCARD UT_Int64Array columnAsInt64Array(int idx) const override final;
272  NO_DISCARD UT_DateTimeField columnAsDate(int idx) const override final;
273  // Stores size of blob in bytes in 'size'.
274  NO_DISCARD const void *columnAsBlob(int idx, int &size) const override final;
275  NO_DISCARD Blob columnAsBlob(int idx) const override final;
276  NO_DISCARD null_tag_t columnAsNull(int idx) const override final;
277  NO_DISCARD UT_StringHolder columnName(int idx) const override final;
278  NO_DISCARD int columnCount() const override final;
279  NO_DISCARD DataType columnType(int idx) const override final;
280  NO_DISCARD int columnBytes(int idx) const override final;
281 
282  // The original text of the sql statement. Do not keep a pointer to it.
283  const char* sql() const override final;
284 
285  // Add more binds as needed
286  // This binds a NULL
287  bool bind(int idx, null_tag_t) override final;
288  bool bind(int idx, const UT_StringRef &value) override final;
289  bool bind(int idx, const char *value) override final;
290  bool bind(int idx, int value) override final;
291  bool bind(int idx, int64 value) override final;
292  bool bind(int idx, bool value) override final;
293  bool bind(int idx, double value) override final;
294  // The following methods bind arrays as strings of the form [#, #, ..., #]
295  bool bind(int idx, const UT_IntArray &value) override final;
296  bool bind(int idx, const UT_Int64Array &value) override final;
297  bool bind(int idx, const UT_StringArray &value) override final;
298  // For binding blobs. `size` is required in bytes. Note that this
299  // function does not destroy `value`.
300  bool bind(int idx, const void *value, int size, bool is_static = true)
301  override final;
302  bool bind(int idx, const UT_DateTimeField &dt) override final;
303 
304  NO_DISCARD bool isValid() const override final;
305 
306  const UT_StringHolder& intTypeString() const override final;
307  const UT_StringHolder& bigIntTypeString() const override final;
308  const UT_StringHolder& stringTypeString() const override final;
309  const UT_StringHolder& nullTypeString() const override final;
310  const UT_StringHolder& realTypeString() const override final;
311  const UT_StringHolder& blobTypeString() const override final;
312  const UT_StringHolder& dateTimeTypeString() const override final;
313  const UT_StringHolder& boolTypeString() const override final;
314 
315  // Called when there are rows to iterate over (i.e. SELECT).
316  bool step() override final;
317  bool run() override final;
318 
319  int changes() const override final
320  {
321  return myChanges;
322  }
323  bool hasRow() override final
324  {
325  if (!myHasStepped)
326  {
327  if (!step())
328  {
329  return false;
330  }
331  }
332  return myHasRow;
333  }
334 
336  UT_ErrorCode *ec = nullptr) const override;
337 
338  void prepare(const UT_StringRef& sql, UT_ErrorCode* ec = nullptr) override;
339 private:
340  void finalize_();
341  bool verifyIndex_(int idx) const;
342  bool verifyColumn_(int idx) const;
343  bool verifyHasStepped_() const;
344  int step_();
345 
346  sqlite3_stmt *myCtx = nullptr;
347  int myColumnCount;
348 
349  unsigned myHasStepped : 1, myHasRow : 1;
350  int myChanges = 0;
351 };
352 
354 {
355 public:
357  {
358  public:
360  using iterator_category = std::forward_iterator_tag;
362  using pointer = value_type*;
364 
366  {
367  if (myResult)
368  {
369  myResult->next();
370  if (isDone())
371  myResult = nullptr;
372  }
373  return *this;
374  }
375 
376  bool operator==(const iterator& rhs) const
377  {
378  if (myResult != nullptr && rhs.myResult != nullptr)
379  return myResult->myStmt == rhs.myResult->myStmt;
380  else if (myResult == nullptr && rhs.myResult == nullptr)
381  return true;
382  return false;
383  }
384  bool operator!=(const iterator& rhs) const
385  {
386  return !(*this == rhs);
387  }
388  const UT_SqlResult& operator*() const{
389  return *myResult;
390  }
392  {
393  return *myResult;
394  }
395  const UT_SqlResult* operator->() const
396  {
397  return myResult;
398  }
400  {
401  return myResult;
402  }
403  bool isDone() const
404  {
405  return myResult == nullptr || !myResult->hasResults();
406  }
407 
408  private:
409  friend class UT_SqlResult;
410 
411  iterator(UT_SqlResult* result = nullptr) :
412  myResult(result)
413  {}
414 
415  UT_SqlResult* myResult = nullptr;
416  };
417 
419  {
420  if (hasResults())
421  return iterator(this);
422  return end();
423  }
425  {
426  return iterator();
427  }
428  const iterator begin() const
429  {
430  if (hasResults())
431  return iterator(SYSconst_cast(this));
432  return end();
433  }
434  const iterator end() const
435  {
436  return iterator();
437  }
438  const iterator cbegin() const
439  {
440  return begin();
441  }
442  const iterator cend() const
443  {
444  return end();
445  }
446 
447  const UT_ErrorCode& getError() const;
448  void next();
449  bool hasResults() const;
450 
451  template <typename... Args>
452  std::tuple<Args...> fetchOne(UT_ErrorCode* ec = nullptr);
453  template <typename... Args>
454  UT_Array<std::tuple<Args...>> fetchAll(UT_ErrorCode* ec = nullptr);
455  template <typename T>
456  UT_Array<T> fetchAllFlat(UT_ErrorCode* ec = nullptr);
457  template <typename... Args>
458  std::tuple<Args...> as(UT_ErrorCode* ec = nullptr);
459 
460  UT_SqlStatement* stmt() { return myStmt; }
461 protected:
462  friend class UT_SqlStatement;
464  : myStmt(stmt)
465  {}
466 
468 };
469 
471 {
472 public:
476 
477  UT_SqlStatement(const UT_SqlDatabase& con, const UT_StringRef& sql);
478  UT_SqlStatement(const UT_SqlDatabase& con);
479  UT_SqlStatement(const UT_SqlBaseDriver &driver, const UT_StringRef &sql);
480  UT_SqlStatement(const UT_SqlBaseDriver &driver);
482  ~UT_SqlStatement();
484  UT_SqlStatement(UT_SqlStatement&& stmt) noexcept;
485  UT_SqlStatement& operator=(UT_SqlStatement&&) = delete;
486 
487  void reset(bool clear_bindings = false)
488  {
489  myImpl->reset(clear_bindings);
490  }
491 
492  NO_DISCARD int columnAsInt(int idx) const
493  {
494  return myImpl->columnAsInt(idx);
495  }
496  NO_DISCARD bool columnAsBool(int idx) const
497  {
498  return myImpl->columnAsBool(idx);
499  }
501  {
502  return myImpl->columnAsInt64(idx);
503  }
505  {
506  return myImpl->columnAsStr(idx);
507  }
508  NO_DISCARD double columnAsDouble(int idx) const
509  {
510  return myImpl->columnAsDouble(idx);
511  }
512  NO_DISCARD UT_IntArray columnAsIntArray(int idx) const;
513  NO_DISCARD UT_Int64Array columnAsInt64Array(int idx) const;
515  {
516  return myImpl->columnAsDate(idx);
517  }
518  // Stores size of blob in bytes in 'size'.
519  NO_DISCARD const void *columnAsBlob(int idx, int &size) const
520  {
521  return myImpl->columnAsBlob(idx, size);
522  }
523  NO_DISCARD Blob columnAsBlob(int idx) const
524  {
525  return myImpl->columnAsBlob(idx);
526  }
528  {
529  return myImpl->columnAsNull(idx);
530  }
532  {
533  return myImpl->columnName(idx);
534  }
536  {
537  return myImpl->columnCount();
538  }
540  {
541  return myImpl->columnType(idx);
542  }
543  NO_DISCARD int columnBytes(int idx) const
544  {
545  return myImpl->columnBytes(idx);
546  }
547 
548  // The original text of the sql statement. Do not keep a pointer to it.
549  const char* sql() const
550  {
551  return myImpl->sql();
552  }
553 
554  // Add more binds as needed
555  // This binds a NULL
556  bool bind(int idx, null_tag_t)
557  {
558  return myImpl->bind(idx, null_tag_t{});
559  }
560  bool bind(int idx, const UT_StringRef &value)
561  {
562  return myImpl->bind(idx, value);
563  }
564  bool bind(int idx, const char *value)
565  {
566  return myImpl->bind(idx, value);
567  }
568  bool bind(int idx, int value)
569  {
570  return myImpl->bind(idx, value);
571  }
572  bool bind(int idx, int64 value)
573  {
574  return myImpl->bind(idx, value);
575  }
576  bool bind(int idx, bool value)
577  {
578  return myImpl->bind(idx, value);
579  }
580  bool bind(int idx, double value)
581  {
582  return myImpl->bind(idx, value);
583  }
584  // The following methods bind arrays as strings of the form [#, #, ..., #]
585  bool bind(int idx, const UT_IntArray &value)
586  {
587  return myImpl->bind(idx, value);
588  }
589  bool bind(int idx, const UT_Int64Array &value)
590  {
591  return myImpl->bind(idx, value);
592  }
593  bool bind(int idx, const UT_StringArray &value)
594  {
595  return myImpl->bind(idx, value);
596  }
597  // For binding blobs. `size` is required in bytes. Note that this
598  // function does not destroy `value`.
599  bool bind(int idx, const void *value, int size)
600  {
601  return myImpl->bind(idx, value, size);
602  }
603  bool bind(int idx, Blob blob)
604  {
605  return myImpl->bind(idx, blob);
606  }
607  bool bind(int idx, const UT_DateTimeField& dt)
608  {
609  return myImpl->bind(idx, dt);
610  }
611  template <
612  typename T,
613  std::enable_if_t<UT::has_sql_bind_v<UT_SqlStatement, T>, bool> = true>
614  bool bind(int idx, const T &v)
615  {
616  return bindCustom_(idx, v);
617  }
618 
620  {
621  return myImpl->intTypeString();
622  }
624  {
625  return myImpl->bigIntTypeString();
626  }
628  {
629  return myImpl->stringTypeString();
630  }
632  {
633  return myImpl->nullTypeString();
634  }
636  {
637  return myImpl->realTypeString();
638  }
640  {
641  return myImpl->blobTypeString();
642  }
644  {
645  return myImpl->dateTimeTypeString();
646  }
648  {
649  return myImpl->boolTypeString();
650  }
651 
652  template <typename T>
653  T get(int idx) const
654  {
655  if constexpr (UT::has_sql_get_v<UT_SqlStatement, T>)
656  {
657  T v;
658  UTsqlGet(*this, idx, v);
659  return v;
660  }
661  else
662  {
663  static_assert(
664  !std::is_same_v<T, void> && std::is_same_v<T, void>,
665  "Type not handled.");
666  }
667  return T();
668  }
669 
670  // TODO: Try redesigning this to work with the bind that accepts a blob.
671  template <typename... Args>
672  bool bindAll(Args &&... args)
673  { return bindHelper(1, std::forward<Args>(args)...); }
674 
675  bool bindNull(int idx)
676  { return bind(idx, null_tag_t()); }
677 
678  NO_DISCARD bool isValid() const
679  {
680  return myImpl && myImpl->isValid();
681  }
682 
683  bool hasRow()
684  {
685  return myImpl->hasRow();
686  }
687 
688  // Called when there is nothing to grab after (i.e. INSERT).
689  bool run()
690  {
691  return myImpl->run();
692  }
693  // Called when there are rows to iterate over (i.e. SELECT).
694  bool step()
695  {
696  return myImpl->step();
697  }
698 
699  // Methods on this class will always test myError before doing their
700  // work. If there is already an error, they will do nothing.
701  const UT_ErrorCode &getError() const
702  { return myImpl->getError(); }
703 
704  bool prepare(const UT_StringRef &sql, UT_ErrorCode &ec);
705  bool prepare(
706  const UT_SqlStatementHandleId &id,
707  const UT_StringRef &sql,
708  UT_ErrorCode &ec);
709 
710  /// Helper function to create a new statement to run a new sql statement
711  template <typename... Args>
712  UT_SqlResult execute(const UT_StringRef& sql, Args&&... args)
713  {
714  UT_ErrorCode ec;
715  if (!prepare(sql, ec))
716  {
717  return UT_SqlResult(this);
718  }
719 
720  bindAll(std::forward<Args>(args)...);
721 
722  step();
723 
724  return UT_SqlResult(this);
725  }
726  /// Helper function to create a new statement to run a new sql statement
727  template <typename... Args>
729  const UT_SqlStatementHandleId &id,
730  const UT_StringRef &sql,
731  Args &&...args)
732  {
733  UT_ErrorCode ec;
734  if (!prepare(id, sql, ec))
735  {
736  return UT_SqlResult(this);
737  }
738  bindAll(std::forward<Args>(args)...);
739 
740  step();
741 
742  return UT_SqlResult(this);
743  }
744 
745  template <typename... Args>
747  {
748  reset(true);
749  bindAll(std::forward<Args>(args)...);
750  step();
751  return UT_SqlResult(this);
752  }
753 
754  template <typename... Args>
755  std::optional<std::tuple<Args...>> fetchOne(UT_ErrorCode* ec = nullptr)
756  {
757  constexpr int ColumnCount = sizeof...(Args);
758 
759  if (getError())
760  {
761  if (ec)
762  *ec = getError();
763  return std::nullopt;
764  }
765 
766  if (!hasRow())
767  {
768  if (ec && getError())
769  *ec = getError();
770  return std::nullopt;
771  }
772 
773  auto r = fetchRow_<Args...>(std::make_index_sequence<ColumnCount>{});
774 
775  if (getError())
776  {
777  if (ec)
778  *ec = getError();
779  return std::nullopt;
780  }
781 
782  /// Move to the next row
783  step();
784 
785  return r;
786  }
787 
788  template <typename... Args>
789  UT_Array<std::tuple<Args...>> fetchAll(UT_ErrorCode* ec = nullptr)
790  {
791  UT_Array<std::tuple<Args...>> rows;
792  if (getError())
793  {
794  if (ec)
795  *ec = getError();
796  return rows;
797  }
798 
799  if (!hasRow())
800  {
801  if (ec && getError())
802  *ec = getError();
803  return rows;
804  }
805 
806  constexpr int ColumnCount = sizeof...(Args);
807  auto idx_sequence = std::make_index_sequence<ColumnCount>{};
808  do
809  {
810  rows.emplace_back(fetchRow_<Args...>(idx_sequence));
811  } while (step());
812 
813  if (getError())
814  {
815  rows.clear();
816  if (ec)
817  *ec = getError();
818  }
819 
820  return rows;
821  }
822 
823  template <typename T>
825  {
826  UT_Array<T> rows;
827  if (getError())
828  {
829  if (ec)
830  *ec = getError();
831  return rows;
832  }
833 
834  if (!hasRow())
835  {
836  if (ec && getError())
837  *ec = getError();
838  return rows;
839  }
840 
841  do
842  {
843  rows.emplace_back(get<T>(0));
844  } while (step());
845 
846  if (getError())
847  {
848  rows.clear();
849  if (ec)
850  *ec = getError();
851  }
852 
853  return rows;
854  }
855 
856  template <typename... Args>
857  std::optional<std::tuple<std::tuple<Args...>>> as(UT_ErrorCode* ec = nullptr)
858  {
859  if (getError())
860  {
861  if (ec)
862  *ec = getError();
863  return std::nullopt;
864  }
865 
866  if (!hasRow())
867  {
868  if (ec && getError())
869  *ec = getError();
870  return std::nullopt;
871  }
872 
873  constexpr int ColumnCount = sizeof...(Args);
874  return fetchRow_<Args...>(std::make_index_sequence<ColumnCount>{});
875  }
876 
878  UT_ErrorCode *ec = nullptr) const
879  {
880  return myImpl->tableExists(name, ec);
881  }
882 
883  int changes() const { return myImpl->changes(); }
884 
885  bool isImplEqual(const UT_SqlStatement& rhs) const
886  {
887  return myImpl == rhs.myImpl;
888  }
889 
890 protected:
891  bool bindHelper(int)
892  { return true; }
893  template <typename T, typename... Args>
894  bool bindHelper(int idx, T value, Args &&...args)
895  {
896  if (!bind(idx, value))
897  return false;
898  return bindHelper(idx + 1, std::forward<Args>(args)...);
899  }
900 
901  template <class... Args, std::size_t... Idxs>
902  std::tuple<Args...>
903  fetchRow_(std::index_sequence<Idxs...>)
904  {
905  return std::make_tuple(get<Args>(Idxs)...);
906  }
907 
908 private:
909  template <typename T>
910  bool bindCustom_(int idx, const T& v);
911 
913  const UT_SqlBaseDriver& myDriver;
914 };
915 
916 template <>
917 inline double
918 UT_SqlStatement::get<double>(int idx) const
919 {
920  return columnAsDouble(idx);
921 }
922 
923 template <>
925 UT_SqlStatement::get<UT_SqlStatement::null_tag_t>(int idx) const
926 {
927  return columnAsNull(idx);
928 }
929 
930 template <>
931 inline UT_StringHolder
932 UT_SqlStatement::get<UT_StringHolder>(int idx) const
933 {
934  return columnAsStr(idx);
935 }
936 
937 template <>
938 inline int
939 UT_SqlStatement::get<int>(int idx) const
940 {
941  return columnAsInt(idx);
942 }
943 
944 template <>
945 inline int64
946 UT_SqlStatement::get<int64>(int idx) const
947 {
948  return columnAsInt64(idx);
949 }
950 
951 template <>
952 inline bool
953 UT_SqlStatement::get<bool>(int idx) const
954 {
955  return columnAsBool(idx);
956 }
957 
958 template <>
959 inline UT_DateTimeField
960 UT_SqlStatement::get<UT_DateTimeField>(int idx) const
961 {
962  return columnAsDate(idx);
963 }
964 
965 template <>
966 inline const void *
967 UT_SqlStatement::get<const void *>(int idx) const
968 {
969  int size;
970  return columnAsBlob(idx, size);
971 }
972 
973 template <>
975 UT_SqlStatement::get<UT_SqlStatement::Blob>(int idx) const
976 {
977  return columnAsBlob(idx);
978 }
979 
980 inline const UT_ErrorCode &
982 {
983  return myStmt->getError();
984 }
985 
986 inline void
988 {
989  myStmt->step();
990  if (!hasResults())
991  myStmt = nullptr;
992 }
993 
994 inline bool
996 {
997  return myStmt && myStmt->hasRow();
998 }
999 
1000 template <typename... Args>
1001 inline std::tuple<Args...>
1003 {
1004  return myStmt->fetchOne<Args...>(ec);
1005 }
1006 
1007 template <typename... Args>
1008 inline UT_Array<std::tuple<Args...>>
1010 {
1011  return myStmt->fetchAll<Args...>(ec);
1012 }
1013 
1014 template <typename T>
1015 inline UT_Array<T>
1017 {
1018  return myStmt->fetchAllFlat<T>(ec);
1019 }
1020 
1021 template <typename... Args>
1022 inline std::tuple<Args...>
1024 {
1025  return myStmt->as<Args...>(ec);
1026 }
1027 
1029 {
1030 public:
1031  virtual ~UT_SqlBaseDriver() = default;
1033 
1034  virtual void setHostName(const UT_StringHolder& host)
1035  {
1036  }
1037  virtual void setPort(int port)
1038  {
1039  }
1040  virtual void setUserName(const UT_StringHolder& user)
1041  {
1042  }
1043  virtual void setPassword(const UT_StringHolder& password)
1044  {
1045  }
1046  virtual void setDatabaseName(const UT_StringHolder& db_name)
1047  {
1048  }
1049  virtual void setConnectOptions(const UT_Options& options)
1050  {
1051  }
1052 
1053  virtual bool connect(UT_ErrorCode* ec = nullptr) = 0;
1054  virtual bool close(UT_ErrorCode *ec = nullptr) = 0;
1055  NO_DISCARD virtual bool isValid() const = 0;
1056  NO_DISCARD virtual bool isReadOnly(
1057  const char *db = "main",
1058  UT_ErrorCode *ec = nullptr) const
1059  = 0;
1060 
1061  NO_DISCARD virtual void* nativeAPI() = 0;
1062  NO_DISCARD virtual void* nativeAPI() const = 0;
1063 
1064  NO_DISCARD virtual UT_SharedPtr<UT_SqlStatementImpl> createStatementImpl()
1065  = 0;
1066  NO_DISCARD virtual UT_SharedPtr<UT_SqlStatementImpl> createStatementImpl()
1067  const
1068  = 0;
1069 
1070  /// Check if the specified table exists.
1071  NO_DISCARD virtual bool tableExists(
1072  const UT_StringRef &name,
1073  UT_ErrorCode *ec = nullptr) const
1074  = 0;
1075  NO_DISCARD virtual bool indexExists(
1076  const UT_StringRef &name,
1077  UT_ErrorCode *ec = nullptr) const
1078  = 0;
1079  NO_DISCARD virtual bool viewExists(
1080  const UT_StringRef &name,
1081  UT_ErrorCode *ec = nullptr) const = 0;
1082  NO_DISCARD virtual bool columnExists(
1083  const UT_StringRef &table_name,
1084  const UT_StringRef &column_name,
1085  UT_ErrorCode *ec = nullptr) const
1086  = 0;
1087  NO_DISCARD virtual UT_StringHolder errorMessage() const = 0;
1088  NO_DISCARD virtual int errorCode() const = 0;
1089  NO_DISCARD virtual int extendedErrorCode() const = 0;
1090 
1091  virtual void rollbackSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec)
1092  = 0;
1093  virtual void commitSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec)
1094  = 0;
1095  virtual void startSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec)
1096  = 0;
1097  virtual void commit(UT_ErrorCode &ec) = 0;
1098  virtual void rollback(UT_ErrorCode &ec) = 0;
1099  virtual void setAutoCommit(bool autocommit, UT_ErrorCode* ec = nullptr) = 0;
1100 
1101  /// These are primarily used by UT_SqlTransaction (but can be used by any
1102  /// client code) and provide an abstraction that resembles nested
1103  /// transations. This is inspired by (and follows the same behaviour as):
1104  /// https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase#beginTransaction()
1105  virtual bool startTransaction(UT_ErrorCode *ec = nullptr) = 0;
1106  virtual bool endTransaction(bool commit, UT_ErrorCode *ec = nullptr) = 0;
1107 
1108  /// Get a sql statement that is retrieved from the cache. If the statement
1109  /// is not already cached then its compiled and then cached if the compiled
1110  /// statement is valid.
1111  virtual UT_SharedPtr<UT_SqlStatementImpl> cachedStatement(
1112  const UT_SqlStatementHandleId &id,
1113  const UT_StringRef &sql,
1114  UT_ErrorCode *ec = nullptr) const
1115  = 0;
1116  virtual UT_SharedPtr<UT_SqlStatementImpl> cachedStatement(
1117  const UT_SqlStatementHandleId &id,
1118  UT_Function<UT_StringHolder()> &&creator,
1119  UT_ErrorCode *ec = nullptr) const
1120  = 0;
1121 
1122  /// Find an sql handle based on its id. The sql statement must have already
1123  /// been added from cachedStatement(). This method is typically used when
1124  /// a statement has already been compiled and added to the cache but needs
1125  /// to be dynamically looked up some time later.
1126  virtual UT_SharedPtr<UT_SqlStatementImpl> findCachedStatement(
1127  const UT_SqlStatementHandleId &id) const
1128  = 0;
1129 
1130  NO_DISCARD virtual UT_StringHolder getSchema(
1131  UT_ErrorCode *ec = nullptr) const
1132  = 0;
1133 
1134  /// Helper function to run an sql statement with provided typed args.
1135  template <typename... Args>
1136  bool run(UT_ErrorCode *ec, const UT_StringRef &sql, Args &&...args)
1137  {
1138  UT_SqlStatement stmt(createStatementImpl());
1139  if (sizeof...(Args) > 0)
1140  stmt.bindAll(ec, std::forward<Args>(args)...);
1141  stmt.step();
1142  if (ec)
1143  *ec = stmt.getError();
1144  return !(bool)stmt.getError();
1145  }
1146  /// Returns the number of rows modified, inserted or deleted
1147  virtual int exec(const UT_StringRef &sql, UT_ErrorCode *ec = nullptr) const
1148  = 0;
1149 
1150 protected:
1151  UT_SqlBaseDriver() = default;
1152 };
1153 
1155 {
1156 public:
1157  static constexpr UT_StringLit theFilenameOpt = "SQLITE_FILENAME";
1158  static constexpr UT_StringLit theBusyTimeoutOpt = "SQLITE_BUSY_TIMEOUT";
1159  static constexpr UT_StringLit theThreadingModeOpt = "SQLITE_THREADING";
1160  static constexpr UT_StringLit theTransactionModeOpt
1161  = "SQLITE_TRANSACTION_MODE";
1162  static constexpr UT_StringLit theCreateDirsOpt = "SQLITE_CREATE_DIRS";
1163 
1164  /// Options to define the threading mode of the driver.
1165  /// DEFAULT_MODE := use whatever is the default (ie. do nothing special)
1166  /// MULTI_THREAD_MODE := use multi thread support.
1167  /// - Sqlite is built to be thread safe in serialized mode. This option
1168  /// is a performance enhancement where it locks less but it comes with
1169  /// the requirement that each thread uses its own connection. This
1170  /// option should only be used in very specific cases.
1172  {
1175  };
1176 
1177  UT_SqliteDriver();
1178  ~UT_SqliteDriver() override;
1179 
1181 
1182  void setDatabaseName(const UT_StringHolder& db_name) override
1183  {
1184  myFilename = db_name;
1185  }
1186  void setConnectOptions(const UT_Options& options) override;
1187 
1188  bool connect(UT_ErrorCode* ec = nullptr) override;
1189  bool close(UT_ErrorCode *ec = nullptr) override;
1190 
1191  NO_DISCARD SYS_FORCE_INLINE bool isValid() const override
1192  { return myCtx != nullptr && myFilename.isstring(); }
1193 
1194  NO_DISCARD bool isReadOnly(const char *db = "main",
1195  UT_ErrorCode *ec = nullptr) const override;
1196 
1197  NO_DISCARD void *nativeAPI() override { return myCtx; }
1198  NO_DISCARD void *nativeAPI() const override
1199  {
1200  return SYSconst_cast(this)->myCtx;
1201  }
1202 
1203  /// Check the database's "data_version"
1204  /// (see https://www.sqlite.org/pragma.html#pragma_data_version)
1205  NO_DISCARD int dataVersion(UT_ErrorCode *ec = nullptr) const;
1206 
1207  /// Get/set the database's "user_version"
1208  /// (see https://www.sqlite.org/pragma.html#pragma_user_version)
1209  NO_DISCARD int userVersion(UT_ErrorCode *ec = nullptr) const;
1210  void setUserVersion(int version, UT_ErrorCode *ec = nullptr) const;
1211 
1212  /// Check if the specified table exists.
1214  UT_ErrorCode *ec = nullptr) const override;
1216  UT_ErrorCode *ec = nullptr) const override;
1217  NO_DISCARD bool viewExists(const UT_StringRef& name,
1218  UT_ErrorCode *ec = nullptr) const override;
1219  NO_DISCARD bool columnExists(
1220  const UT_StringRef& table_name,
1221  const UT_StringRef& column_name,
1222  UT_ErrorCode *ec = nullptr) const override;
1223  NO_DISCARD UT_StringHolder errorMessage() const override;
1224  NO_DISCARD int errorCode() const override;
1225  NO_DISCARD int extendedErrorCode() const override;
1226 
1227  NO_DISCARD UT_StringHolder getSchema(UT_ErrorCode *ec = nullptr) const override;
1228 
1229  void rollbackSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec)
1230  override;
1231  void commitSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec) override;
1232  void startSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec) override;
1233  void commit(UT_ErrorCode &ec) override;
1234  void rollback(UT_ErrorCode &ec) override;
1235  void setAutoCommit(bool autocommit, UT_ErrorCode* ec = nullptr) override;
1236 
1237  /// This sets a busy handler that sleeps for a specified amount of time
1238  /// when a table is locked. The handler will sleep multiple times until at
1239  /// least milliseconds of sleeping have accumulated. After the timeout the
1240  /// handler returns 0 which causes the step() to return kSQLITE_BUSY.
1241  void setBusyTimeout(int timeout_ms)
1242  {
1243  myBusyTimeout = timeout_ms;
1244  }
1245 
1246  /// Copy the contents of this database into the provided destination
1247  /// database. Return true on success and false otherwise.
1248  /// On failure, the error code is set in the destination database.
1249  bool copyTo(UT_SqliteDriver &destination, UT_ErrorCode *ec = nullptr)
1250  const;
1251 
1254 
1255  /// Get a sql statement that is retrieved from the cache. If the statement
1256  /// is not already cached then its compiled and then cached if the compiled
1257  /// statement is valid.
1259  const UT_SqlStatementHandleId &id,
1260  const UT_StringRef& sql,
1261  UT_ErrorCode *ec = nullptr) const override;
1262 
1263  /// Get a sql statement that is retrieved from the cache. If the statement
1264  /// is not already cached then the provided creator function is called
1265  /// to compile and then cache the compiled statement if its valid.
1267  const UT_SqlStatementHandleId &id,
1268  UT_Function<UT_StringHolder()>&& creator,
1269  UT_ErrorCode *ec = nullptr) const override;
1270 
1271  /// Find an sql handle based on its id. The sql statement must have already
1272  /// been added from cachedStatement(). This method is typically used when
1273  /// a statement has already been compiled and added to the cache but needs
1274  /// to be dynamically looked up some time later.
1276  const UT_SqlStatementHandleId& id) const override;
1277 
1278  /// These are primarily used by UT_SqlTransaction (but can be used by any
1279  /// client code) and provide an abstraction that resembles nested
1280  /// transations. This is inspired by (and follows the same behaviour as):
1281  /// https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase#beginTransaction()
1282  bool startTransaction(UT_ErrorCode *ec = nullptr) override;
1283  bool endTransaction(bool commit, UT_ErrorCode *ec = nullptr) override;
1284 
1285  int exec(const UT_StringRef &sql, UT_ErrorCode *ec = nullptr)
1286  const override;
1287 protected:
1288  bool schemaItemExists(
1289  const UT_StringRef& type,
1290  const UT_StringRef& name,
1291  UT_ErrorCode *ec) const;
1292 
1293 private:
1294  bool verifyOpen(
1295  const UT_StringHolder &filename,
1296  UT_ErrorCode *ec);
1297 
1298  mutable std::map<UT_SqlStatementHandleId,
1299  UT_SharedPtr<UT_SqlStatementImpl>> myCachedStatements;
1300  sqlite3 *myCtx = nullptr;
1301  SYS_AtomicCounter myActiveTransactionDepth;
1302  bool myShouldCommitTransaction;
1303 
1304  UT_StringHolder myFilename;
1305  int myBusyTimeout = -1;
1306  ThreadingMode myThreadingMode = ThreadingMode::DEFAULT_MODE;
1307  UT_StringHolder myTransactionMode;
1308  bool myCreateDirs = false;
1309 };
1310 
1312 
1314 {
1315 public:
1316  using driver_factory_t = UT_UniquePtr<UT_SqlBaseDriver>(*)();
1317 
1318  UT_SqlDatabase(driver_factory_t factory = UTsqliteFactory) :
1319  myDriver(factory())
1320  {}
1321 
1323  {
1324  return myDriver.get();
1325  }
1326  const UT_SqlBaseDriver* driver() const
1327  {
1328  return myDriver.get();
1329  }
1330 
1331  void setHostName(const UT_StringRef& host)
1332  {
1333  myDriver->setHostName(host);
1334  }
1335  void setPort(int port)
1336  {
1337  myDriver->setPort(port);
1338  }
1339  void setUserName(const UT_StringRef& user)
1340  {
1341  myDriver->setUserName(user);
1342  }
1343  void setPassword(const UT_StringRef& password)
1344  {
1345  myDriver->setPassword(password);
1346  }
1347  void setDatabaseName(const UT_StringRef& db_name)
1348  {
1349  myDriver->setDatabaseName(db_name);
1350  }
1351  void setConnectOptions(const UT_Options& options)
1352  {
1353  myDriver->setConnectOptions(options);
1354  }
1355 
1356  /// Close the sql connection to the db backend
1357  bool close(UT_ErrorCode *ec = nullptr) { return myDriver->close(ec); }
1358  /// Create a db connection with a custom db backend
1359  bool connect(UT_ErrorCode *ec = nullptr)
1360  {
1361  return myDriver && myDriver->connect(ec);
1362  }
1363  /// Check the underlying connection is valid and usable
1364  NO_DISCARD bool isValid() const
1365  {
1366  return myDriver && myDriver->isValid();
1367  }
1369  const char *db = "main",
1370  UT_ErrorCode *ec = nullptr) const
1371  {
1372  return myDriver->isReadOnly(db, ec);
1373  }
1375  {
1376  return myDriver->createStatementImpl();
1377  }
1379  {
1380  return myDriver->createStatementImpl();
1381  }
1382  /// Get a sql statement that is retrieved from the cache. If the statement
1383  /// is not already cached then its compiled and then cached if the compiled
1384  /// statement is valid.
1386  const UT_SqlStatementHandleId &id,
1387  const UT_StringRef& sql,
1388  UT_ErrorCode *ec = nullptr) const
1389  {
1390  return myDriver->cachedStatement(id, sql, ec);
1391  }
1392 
1394  const UT_SqlStatementHandleId &id,
1395  UT_Function<UT_StringHolder()> &&creator,
1396  UT_ErrorCode *ec = nullptr) const
1397  {
1398  return myDriver->cachedStatement(id, std::move(creator), ec);
1399  }
1400 
1401  /// Find an sql handle based on its id. The sql statement must have already
1402  /// been added from cachedStatement(). This method is typically used when
1403  /// a statement has already been compiled and added to the cache but needs
1404  /// to be dynamically looked up some time later.
1406  const UT_SqlStatementHandleId& id) const
1407  {
1408  return myDriver->findCachedStatement(id);
1409  }
1410  /// Helper function to run an sql statement with provided typed args.
1411  template <typename... Args>
1412  bool run(UT_ErrorCode *ec, const UT_StringRef &sql, Args &&... args)
1413  {
1414  UT_SqlStatement stmt(createStatementImpl());
1415  if (sizeof...(Args) > 0)
1416  stmt.bindAll(ec, std::forward<Args>(args)...);
1417  stmt.step();
1418  if (ec)
1419  *ec = stmt.getError();
1420  return !(bool)stmt.getError();
1421  }
1422  /// Returns the number of rows modified, inserted or deleted
1423  int exec(const UT_StringRef &sql, UT_ErrorCode *ec = nullptr) const
1424  {
1425  return myDriver->exec(sql, ec);
1426  }
1427 
1428  /// Check if the specified table exists.
1430  UT_ErrorCode *ec = nullptr) const
1431  {
1432  return myDriver->tableExists(name, ec);
1433  }
1435  UT_ErrorCode *ec = nullptr) const
1436  {
1437  return myDriver->indexExists(name, ec);
1438  }
1440  UT_ErrorCode *ec = nullptr) const
1441  {
1442  return myDriver->viewExists(name, ec);
1443  }
1445  const UT_StringRef& table_name,
1446  const UT_StringRef& column_name,
1447  UT_ErrorCode *ec = nullptr) const
1448  {
1449  return myDriver->columnExists(table_name, column_name, ec);
1450  }
1452  {
1453  return myDriver->errorMessage();
1454  }
1455  NO_DISCARD int errorCode() const
1456  {
1457  return myDriver->errorCode();
1458  }
1460  {
1461  return myDriver->extendedErrorCode();
1462  }
1463 
1464  /// These are primarily used by UT_SqlTransaction (but can be used by any
1465  /// client code) and provide an abstraction that resembles nested transations.
1466  /// This is inspired by (and follows the same behaviour as):
1467  /// https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase#beginTransaction()
1468  bool startTransaction(UT_ErrorCode *ec = nullptr)
1469  {
1470  return myDriver->startTransaction(ec);
1471  }
1472  bool endTransaction(bool commit, UT_ErrorCode *ec = nullptr)
1473  {
1474  return myDriver->endTransaction(commit, ec);
1475  }
1476 
1478  {
1479  return myDriver->getSchema(ec);
1480  }
1481 
1482  NO_DISCARD void* nativeAPI() { return myDriver->nativeAPI(); }
1483  NO_DISCARD void* nativeAPI() const { return myDriver->nativeAPI(); }
1484 
1485  void rollbackSavePoint(const UT_StringHolder& sid, UT_ErrorCode& ec);
1486  void commitSavePoint(const UT_StringHolder& sid, UT_ErrorCode& ec);
1487  UT_StringHolder createSavePoint(UT_ErrorCode& ec);
1488  void commit(UT_ErrorCode& ec);
1489  void rollback(UT_ErrorCode &ec);
1490  void setAutoCommit(bool autocommit, UT_ErrorCode* ec = nullptr);
1491  bool getAutoCommit() const { return myAutocommit; }
1492 
1493 protected:
1495 
1497 
1498  bool myIsInAtomicBlock = false;
1499  bool myCommitOnExit = false;
1500  bool myNeedsRollback = false;
1502  int mySavePointCounter = 0;
1503  bool myAutocommit = true;
1504 };
1505 
1506 // Transactions are a way to group SQL statements.
1507 // This class ensures we properly setup and execute the group (or rollback if needed)
1508 //
1509 // NOTE: If commit() is not explicitly called before the object is destroyed
1510 // (e.g., goes out of scope), the transaction will be aborted (rolled back)
1511 //
1512 // This is DEPRECATED!!! Please use UT_AutoSqlTransaction instead as it has
1513 // full support for savepoints and nested transactions.
1515 {
1516 public:
1517  UT_SqlTransaction(UT_SqlDatabase &connection, UT_ErrorCode *ec = nullptr);
1518  ~UT_SqlTransaction();
1520 
1521  void commit(UT_ErrorCode *ec = nullptr);
1522 
1523 private:
1524  bool myCommited;
1525  UT_SqlDatabase &myConnection;
1526 };
1527 
1528 /// Helper object to optionally create/commit/rollback savepoints and
1529 /// transactions. The user passes a commit callback function which informs the
1530 /// object if the transaction was a success or failure. This callback is
1531 /// called only once on this objects dtor. If it returns true it means the
1532 /// transaction was a success and the transaction/savepoint should be committed.
1533 /// There are helper functions on the object to early commit or rollback when
1534 /// necessary. Generally speaking the user should leave that logic to the dtor
1535 /// and the commit callback.
1537 {
1538 public:
1540 
1542  UT_SqlDatabase &conn,
1543  commit_callback_t&& commit_callback,
1544  bool savepoint = true,
1545  bool durable = false);
1548 
1549  explicit operator bool() const
1550  {
1551  return !myEnterError;
1552  }
1553 
1554  /// Used to early commit the transaction. Generally this should not be used
1555  /// as the transaction exit scope should be used to commit/rollback
1556  /// transactions.
1557  void commit();
1558  /// Used to early rollback the transaction. Generally this should not be
1559  /// used as the transaction exit scope should be used to commit/rollback
1560  /// transactions.
1561  void rollback();
1562  /// Flag this transaction as failed. Once the transaction object dtor is
1563  /// called it will rollback the transaction.
1564  void fail() { myErrorReported = true; }
1565 
1567  {
1568  return myEnterError;
1569  }
1570 private:
1571  void enter_();
1572  void exit_(bool force_rollback);
1573  bool isCurrentError_() const;
1574 
1575  UT_SqlDatabase& myConnection;
1576  UT_ErrorCode myEnterError;
1577  bool mySavePoint = true;
1578  bool myErrorReported = false;
1579  commit_callback_t myCommitCallback;
1580  bool myHasCommitted = false;
1581  bool myDurable = false;
1582 };
1583 
1584 UT_API bool UTsqlBind(
1585  UT_SqlStatement &stmt,
1586  int idx,
1587  const UT_ArrayStringSet& aset);
1588 
1589 template <typename T>
1590 bool
1591 UT_SqlStatement::bindCustom_(int idx, const T &v)
1592 {
1593  return UTsqlBind(*this, idx, v);
1594 }
1595 
1596 #endif // __UT_SQL_H__
NO_DISCARD null_tag_t columnAsNull(int idx) const
Definition: UT_SQL.h:527
virtual void setPassword(const UT_StringHolder &password)
Definition: UT_SQL.h:1043
UT_SqlResult & operator*()
Definition: UT_SQL.h:391
GT_API const UT_StringHolder filename
UT_ErrorCode make_error_code(UT::SqlOrmError e)
Definition: UT_ORMError.h:47
virtual NO_DISCARD int extendedErrorCode() const =0
UT_SqlStatementHandleId(const char *source_file, exint source_line)
Definition: UT_SQL.h:121
bool step()
Definition: UT_SQL.h:694
const UT_ErrorCode & getError() const
Definition: UT_SQL.h:701
UT_SharedPtr< UT_SqlStatementImpl > findCachedStatement(const UT_SqlStatementHandleId &id) const
Definition: UT_SQL.h:1405
virtual NO_DISCARD int columnCount() const =0
const UT_SqlResult & operator*() const
Definition: UT_SQL.h:388
virtual NO_DISCARD int64 columnAsInt64(int idx) const =0
UT_SqlResult executePrepared(Args &&...args)
Definition: UT_SQL.h:746
#define NO_DISCARD
Definition: UT_SQL.h:44
virtual NO_DISCARD UT_IntArray columnAsIntArray(int idx) const =0
UT_SqlDatabase(driver_factory_t factory=UTsqliteFactory)
Definition: UT_SQL.h:1318
bool bind(int idx, const UT_StringArray &value)
Definition: UT_SQL.h:593
virtual bool connect(UT_ErrorCode *ec=nullptr)=0
const UT_ErrorCode & entryFailure()
Definition: UT_SQL.h:1566
void setDatabaseName(const UT_StringHolder &db_name) override
Definition: UT_SQL.h:1182
virtual NO_DISCARD bool isReadOnly(const char *db="main", UT_ErrorCode *ec=nullptr) const =0
const void * myPtr
Definition: UT_SQL.h:144
bool bind(int idx, const char *value)
Definition: UT_SQL.h:564
std::forward_iterator_tag iterator_category
Definition: UT_SQL.h:360
NO_DISCARD bool tableExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:877
virtual NO_DISCARD UT_StringHolder columnName(int idx) const =0
const GLdouble * v
Definition: glcorearb.h:837
constexpr bool has_sql_get_v
Definition: UT_SQL.h:95
virtual void commit(UT_ErrorCode &ec)=0
NO_DISCARD int columnCount() const
Definition: UT_SQL.h:535
const UT_StringHolder & bigIntTypeString() const
Definition: UT_SQL.h:623
std::optional< std::tuple< std::tuple< Args...> > > as(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:857
virtual NO_DISCARD bool indexExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const =0
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool bind(int idx, const UT_Int64Array &value)
Definition: UT_SQL.h:589
virtual void rollbackSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec)=0
bool bind(int idx, null_tag_t)
Definition: UT_SQL.h:556
UT_Array< T > fetchAllFlat(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:1016
NO_DISCARD int extendedErrorCode() const
Definition: UT_SQL.h:1459
void setBusyTimeout(int timeout_ms)
Definition: UT_SQL.h:1241
const UT_StringHolder & blobTypeString() const
Definition: UT_SQL.h:639
NO_DISCARD bool tableExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const
Check if the specified table exists.
Definition: UT_SQL.h:1429
virtual void startSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec)=0
const char * sql() const
Definition: UT_SQL.h:549
const UT_SqlBaseDriver * driver() const
Definition: UT_SQL.h:1326
UT_Array< T > fetchAllFlat(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:824
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:136
NO_DISCARD bool columnAsBool(int idx) const
Definition: UT_SQL.h:496
const UT_StringHolder & boolTypeString() const
Definition: UT_SQL.h:647
virtual const char * sql() const =0
virtual void commitSavePoint(const UT_StringHolder &sid, UT_ErrorCode &ec)=0
const UT_ErrorCode & getError() const
Definition: UT_SQL.h:981
int64 exint
Definition: SYS_Types.h:125
NO_DISCARD Blob columnAsBlob(int idx) const
Definition: UT_SQL.h:523
constexpr bool is_sql_type_v
Definition: UT_SQL.h:108
const UT_StringHolder & nullTypeString() const
Definition: UT_SQL.h:631
bool bind(int idx, Blob blob)
Definition: UT_SQL.h:603
virtual void prepare(const UT_StringRef &sql, UT_ErrorCode *ec=nullptr)=0
bool hasResults() const
Definition: UT_SQL.h:995
virtual void setPort(int port)
Definition: UT_SQL.h:1037
#define UT_API
Definition: UT_API.h:14
UT_SqlResult execute(const UT_StringRef &sql, Args &&...args)
Helper function to create a new statement to run a new sql statement.
Definition: UT_SQL.h:712
virtual NO_DISCARD bool columnExists(const UT_StringRef &table_name, const UT_StringRef &column_name, UT_ErrorCode *ec=nullptr) const =0
**But if you need a result
Definition: thread.h:622
void close() override
std::error_category UT_ErrorCategory
Definition: UT_ErrorCode.h:22
virtual bool step()=0
const iterator begin() const
Definition: UT_SQL.h:428
void setHostName(const UT_StringRef &host)
Definition: UT_SQL.h:1331
OutGridT const XformOp bool bool
int changes() const overridefinal
Definition: UT_SQL.h:319
virtual bool close(UT_ErrorCode *ec=nullptr)=0
NO_DISCARD UT_StringHolder columnAsStr(int idx) const
Definition: UT_SQL.h:504
GLintptr GLsizeiptr GLboolean commit
Definition: glcorearb.h:3363
virtual NO_DISCARD UT_DateTimeField columnAsDate(int idx) const =0
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
const iterator cend() const
Definition: UT_SQL.h:442
NO_DISCARD bool isReadOnly(const char *db="main", UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:1368
bool run(UT_ErrorCode *ec, const UT_StringRef &sql, Args &&...args)
Helper function to run an sql statement with provided typed args.
Definition: UT_SQL.h:1412
const UT_StringHolder & stringTypeString() const
Definition: UT_SQL.h:627
virtual NO_DISCARD bool viewExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const =0
NO_DISCARD UT_SharedPtr< UT_SqlStatementImpl > createStatementImpl()
Definition: UT_SQL.h:1374
std::tuple< Args...> as(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:1023
bool operator!=(const iterator &rhs) const
Definition: UT_SQL.h:384
virtual UT_SharedPtr< UT_SqlStatementImpl > findCachedStatement(const UT_SqlStatementHandleId &id) const =0
virtual void setAutoCommit(bool autocommit, UT_ErrorCode *ec=nullptr)=0
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
UT_SqlStatementImpl(const UT_SqlBaseDriver &driver)
Definition: UT_SQL.h:245
UT_API const UT_ErrorCategory & GetSqlErrorCategory()
virtual void rollback(UT_ErrorCode &ec)=0
bool bindHelper(int)
Definition: UT_SQL.h:891
virtual const UT_StringHolder & blobTypeString() const =0
exint emplace_back(S &&...s)
Definition: UT_ArrayImpl.h:769
std::tuple< Args...> fetchOne(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:1002
virtual void reset(bool clear_bindings=false)=0
bool hasRow()
Definition: UT_SQL.h:683
GLboolean reset
Definition: glad.h:5138
UT_StringArray mySavePoints
Definition: UT_SQL.h:1501
bool bind(int idx, bool value)
Definition: UT_SQL.h:576
virtual void setDatabaseName(const UT_StringHolder &db_name)
Definition: UT_SQL.h:1046
virtual const UT_StringHolder & boolTypeString() const =0
UT_SqlResult(UT_SqlStatement *stmt)
Definition: UT_SQL.h:463
bool operator<(const UT_SqlStatementHandleId &id) const
Definition: UT_SQL.h:125
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
bool startTransaction(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:1468
NO_DISCARD bool indexExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:1434
NO_DISCARD void * nativeAPI() const
Definition: UT_SQL.h:1483
virtual NO_DISCARD bool tableExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const =0
Check if the specified table exists.
bool bind(int idx, double value)
Definition: UT_SQL.h:580
virtual NO_DISCARD UT_StringHolder errorMessage() const =0
NO_DISCARD void * nativeAPI()
Definition: UT_SQL.h:1482
iterator & operator++()
Definition: UT_SQL.h:365
virtual const UT_StringHolder & nullTypeString() const =0
NO_DISCARD UT_StringHolder errorMessage() const
Definition: UT_SQL.h:1451
const UT_SqlBaseDriver & driver() const
Definition: UT_SQL.h:161
GLuint GLuint end
Definition: glcorearb.h:475
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
NO_DISCARD double columnAsDouble(int idx) const
Definition: UT_SQL.h:508
virtual NO_DISCARD double columnAsDouble(int idx) const =0
virtual NO_DISCARD UT_StringHolder getSchema(UT_ErrorCode *ec=nullptr) const =0
bool run(UT_ErrorCode *ec, const UT_StringRef &sql, Args &&...args)
Helper function to run an sql statement with provided typed args.
Definition: UT_SQL.h:1136
bool bindAll(Args &&...args)
Definition: UT_SQL.h:672
const UT_ErrorCode & getError() const
Definition: UT_SQL.h:229
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
NO_DISCARD UT_SharedPtr< UT_SqlStatementImpl > createStatementImpl() const
Definition: UT_SQL.h:1378
UT_API const UT_ErrorCategory & GetSqliteErrorCategory()
virtual NO_DISCARD int columnAsInt(int idx) const =0
long long int64
Definition: SYS_Types.h:116
const iterator cbegin() const
Definition: UT_SQL.h:438
UT_Array< std::tuple< Args...> > fetchAll(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:789
bool isDone() const
Definition: UT_SQL.h:403
virtual bool endTransaction(bool commit, UT_ErrorCode *ec=nullptr)=0
NO_DISCARD int columnBytes(int idx) const
Definition: UT_SQL.h:543
iterator begin()
Definition: UT_SQL.h:418
const UT_SqlResult * operator->() const
Definition: UT_SQL.h:395
NO_DISCARD bool isValid() const
Definition: UT_SQL.h:678
virtual NO_DISCARD bool tableExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const =0
int SYSstrcmp(const char *a, const char *b)
Definition: SYS_String.h:237
NO_DISCARD int columnAsInt(int idx) const
Definition: UT_SQL.h:492
bool bindNull(int idx)
Definition: UT_SQL.h:675
virtual NO_DISCARD UT_SharedPtr< UT_SqlStatementImpl > createStatementImpl()=0
bool bind(int idx, const UT_IntArray &value)
Definition: UT_SQL.h:585
GLuint const GLchar * name
Definition: glcorearb.h:786
UT_API bool UTsqlBind(UT_SqlStatement &stmt, int idx, const UT_ArrayStringSet &aset)
NO_DISCARD UT_DateTimeField columnAsDate(int idx) const
Definition: UT_SQL.h:514
UT_SqlResult execute(const UT_SqlStatementHandleId &id, const UT_StringRef &sql, Args &&...args)
Helper function to create a new statement to run a new sql statement.
Definition: UT_SQL.h:728
bool bind(int idx, const void *value, int size)
Definition: UT_SQL.h:599
const UT_StringHolder & intTypeString() const
Definition: UT_SQL.h:619
void setConnectOptions(const UT_Options &options)
Definition: UT_SQL.h:1351
std::function< T > UT_Function
Definition: UT_Function.h:37
virtual const UT_StringHolder & intTypeString() const =0
virtual const UT_StringHolder & realTypeString() const =0
NO_DISCARD SYS_FORCE_INLINE bool isValid() const override
Definition: UT_SQL.h:1191
NO_DISCARD bool viewExists(const UT_StringRef &name, UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:1439
constexpr bool has_sql_bind_v
Definition: UT_SQL.h:82
virtual NO_DISCARD bool isValid() const =0
virtual const UT_StringHolder & dateTimeTypeString() const =0
NO_DISCARD UT_StringHolder columnName(int idx) const
Definition: UT_SQL.h:531
bool bind(int idx, const T &v)
Definition: UT_SQL.h:614
UT_API UT_UniquePtr< UT_SqlBaseDriver > UTsqliteFactory()
virtual NO_DISCARD int errorCode() const =0
bool bind(int idx, int64 value)
Definition: UT_SQL.h:572
virtual bool run()=0
const iterator end() const
Definition: UT_SQL.h:434
bool run()
Definition: UT_SQL.h:689
virtual NO_DISCARD DataType columnType(int idx) const =0
UT_SqlResult * operator->()
Definition: UT_SQL.h:399
GT_API const UT_StringHolder version
UT_SqlStatement * myStmt
Definition: UT_SQL.h:467
std::size_t mySize
Definition: UT_SQL.h:145
std::error_code UT_ErrorCode
Definition: UT_ErrorCode.h:20
NO_DISCARD bool isValid() const
Check the underlying connection is valid and usable.
Definition: UT_SQL.h:1364
Error getError()
Definition: oidn.hpp:823
bool close(UT_ErrorCode *ec=nullptr)
Close the sql connection to the db backend.
Definition: UT_SQL.h:1357
void reset(bool clear_bindings=false)
Definition: UT_SQL.h:487
GLsizeiptr size
Definition: glcorearb.h:664
bool hasRow() overridefinal
Definition: UT_SQL.h:323
virtual void setHostName(const UT_StringHolder &host)
Definition: UT_SQL.h:1034
A map of string to various well defined value types.
Definition: UT_Options.h:84
bool endTransaction(bool commit, UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:1472
const UT_StringHolder & realTypeString() const
Definition: UT_SQL.h:635
typename pvt::make_void< Ts...>::type void_t
Definition: type_traits.h:37
void setPassword(const UT_StringRef &password)
Definition: UT_SQL.h:1343
bool bind(int idx, int value)
Definition: UT_SQL.h:568
virtual NO_DISCARD UT_Int64Array columnAsInt64Array(int idx) const =0
bool connect(UT_ErrorCode *ec=nullptr)
Create a db connection with a custom db backend.
Definition: UT_SQL.h:1359
virtual NO_DISCARD const void * columnAsBlob(int idx, int &size) const =0
const UT_SqlBaseDriver & myDriver
Definition: UT_SQL.h:249
virtual void setUserName(const UT_StringHolder &user)
Definition: UT_SQL.h:1040
NO_DISCARD void * nativeAPI() const override
Definition: UT_SQL.h:1198
NO_DISCARD int errorCode() const
Definition: UT_SQL.h:1455
virtual NO_DISCARD int columnBytes(int idx) const =0
bool bind(int idx, Blob blob)
Definition: UT_SQL.h:222
NO_DISCARD void * nativeAPI() override
Definition: UT_SQL.h:1197
virtual UT_SharedPtr< UT_SqlStatementImpl > cachedStatement(const UT_SqlStatementHandleId &id, const UT_StringRef &sql, UT_ErrorCode *ec=nullptr) const =0
UT_SharedPtr< UT_SqlStatementImpl > cachedStatement(const UT_SqlStatementHandleId &id, const UT_StringRef &sql, UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:1385
UT_NON_COPYABLE(UT_SqlBaseDriver)
bool bind(int idx, const UT_StringRef &value)
Definition: UT_SQL.h:560
SqlError
Error codes to describe errors as a result of UT_SQL.
Definition: UT_SQL.h:53
NO_DISCARD UT_StringHolder getSchema(UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:1477
iterator end()
Definition: UT_SQL.h:424
**If you just want to fire and args
Definition: thread.h:618
virtual const UT_StringHolder & bigIntTypeString() const =0
UT_SqlStatement * stmt()
Definition: UT_SQL.h:460
virtual NO_DISCARD UT_StringHolder columnAsStr(int idx) const =0
std::tuple< Args...> fetchRow_(std::index_sequence< Idxs...>)
Definition: UT_SQL.h:903
virtual void setConnectOptions(const UT_Options &options)
Definition: UT_SQL.h:1049
virtual bool bind(int idx, null_tag_t)=0
NO_DISCARD const void * columnAsBlob(int idx, int &size) const
Definition: UT_SQL.h:519
UT_NON_COPYABLE(UT_SqlStatementImpl)
bool operator==(const iterator &rhs) const
Definition: UT_SQL.h:376
virtual NO_DISCARD null_tag_t columnAsNull(int idx) const =0
void next()
Definition: UT_SQL.h:987
NO_DISCARD bool columnExists(const UT_StringRef &table_name, const UT_StringRef &column_name, UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:1444
UT_Array< std::tuple< Args...> > fetchAll(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:1009
GLboolean r
Definition: glcorearb.h:1222
UT_SqlBaseDriver * driver()
Definition: UT_SQL.h:1322
UT_Function< bool()> commit_callback_t
Definition: UT_SQL.h:1539
bool isImplEqual(const UT_SqlStatement &rhs) const
Definition: UT_SQL.h:885
NO_DISCARD int64 columnAsInt64(int idx) const
Definition: UT_SQL.h:500
bool bindHelper(int idx, T value, Args &&...args)
Definition: UT_SQL.h:894
void clear()
Resets list to an empty list.
Definition: UT_Array.h:736
NO_DISCARD DataType columnType(int idx) const
Definition: UT_SQL.h:539
virtual bool startTransaction(UT_ErrorCode *ec=nullptr)=0
virtual const UT_StringHolder & stringTypeString() const =0
const UT_StringHolder & dateTimeTypeString() const
Definition: UT_SQL.h:643
UT_SharedPtr< UT_SqlStatementImpl > cachedStatement(const UT_SqlStatementHandleId &id, UT_Function< UT_StringHolder()> &&creator, UT_ErrorCode *ec=nullptr) const
Definition: UT_SQL.h:1393
UT_UniquePtr< UT_SqlBaseDriver > myDriver
Definition: UT_SQL.h:1496
UT_ErrorCode myError
Definition: UT_SQL.h:250
void setUserName(const UT_StringRef &user)
Definition: UT_SQL.h:1339
void setDatabaseName(const UT_StringRef &db_name)
Definition: UT_SQL.h:1347
void setPort(int port)
Definition: UT_SQL.h:1335
std::optional< std::tuple< Args...> > fetchOne(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:755
int exec(const UT_StringRef &sql, UT_ErrorCode *ec=nullptr) const
Returns the number of rows modified, inserted or deleted.
Definition: UT_SQL.h:1423
virtual NO_DISCARD bool columnAsBool(int idx) const =0
virtual int exec(const UT_StringRef &sql, UT_ErrorCode *ec=nullptr) const =0
Returns the number of rows modified, inserted or deleted.
bool bind(int idx, const UT_DateTimeField &dt)
Definition: UT_SQL.h:607
UT_API bool UTsqlGet(const UT_SqlStatement &stmt, int idx, UT_SGuid &sguid)
bool getAutoCommit() const
Definition: UT_SQL.h:1491
int changes() const
Definition: UT_SQL.h:883
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:566