summaryrefslogtreecommitdiffstats
path: root/ml/dlib/examples/sqlite_ex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/examples/sqlite_ex.cpp')
-rw-r--r--ml/dlib/examples/sqlite_ex.cpp137
1 files changed, 137 insertions, 0 deletions
diff --git a/ml/dlib/examples/sqlite_ex.cpp b/ml/dlib/examples/sqlite_ex.cpp
new file mode 100644
index 000000000..4f1e30a2a
--- /dev/null
+++ b/ml/dlib/examples/sqlite_ex.cpp
@@ -0,0 +1,137 @@
+// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
+
+/*
+ This example gives a quick overview of dlib's C++ API for the popular SQLite library.
+*/
+
+
+#include <iostream>
+#include <dlib/sqlite.h>
+#include <dlib/matrix.h>
+
+using namespace dlib;
+using namespace std;
+
+// ----------------------------------------------------------------------------------------
+
+bool table_exists (
+ database& db,
+ const std::string& tablename
+)
+{
+ // Sometimes you want to just run a query that returns one thing. In this case, we
+ // want to see how many tables are in our database with the given tablename. The only
+ // possible outcomes are 1 or 0 and we can do this by looking in the special
+ // sqlite_master table that records such database metadata. For these kinds of "one
+ // result" queries we can use the query_int() method which executes a SQL statement
+ // against a database and returns the result as an int.
+ return query_int(db, "select count(*) from sqlite_master where name = '"+tablename+"'")==1;
+}
+
+// ----------------------------------------------------------------------------------------
+
+int main() try
+{
+ // Open the SQLite database in the stuff.db file (or create an empty database in
+ // stuff.db if it doesn't exist).
+ database db("stuff.db");
+
+ // Create a people table that records a person's name, age, and their "data".
+ if (!table_exists(db,"people"))
+ db.exec("create table people (name, age, data)");
+
+
+ // Now let's add some data to this table. We can do this by making a statement object
+ // as shown. Here we use the special ? character to indicate bindable arguments and
+ // below we will use st.bind() statements to populate those fields with values.
+ statement st(db, "insert into people VALUES(?,?,?)");
+
+ // The data for Davis
+ string name = "Davis";
+ int age = 32;
+ matrix<double> m = randm(3,3); // some random "data" for Davis
+
+ // You can bind any of the built in scalar types (e.g. int, float) or std::string and
+ // they will go into the table as the appropriate SQL types (e.g. INT, TEXT). If you
+ // try to bind any other object it will be saved as a binary blob if the type has an
+ // appropriate void serialize(const T&, std::ostream&) function defined for it. The
+ // matrix has such a serialize function (as do most dlib types) so the bind below saves
+ // the matrix as a binary blob.
+ st.bind(1, name);
+ st.bind(2, age);
+ st.bind(3, m);
+ st.exec(); // execute the SQL statement. This does the insert.
+
+
+ // We can reuse the statement to add more data to the database. In fact, if you have a
+ // bunch of statements to execute it is fastest if you reuse them in this manner.
+ name = "John";
+ age = 82;
+ m = randm(2,3);
+ st.bind(1, name);
+ st.bind(2, age);
+ st.bind(3, m);
+ st.exec();
+
+
+
+ // Now lets print out all the rows in the people table.
+ statement st2(db, "select * from people");
+ st2.exec();
+ // Loop over all the rows obtained by executing the statement with .exec().
+ while(st2.move_next())
+ {
+ string name;
+ int age;
+ matrix<double> m;
+ // Analogously to bind, we can grab the columns straight into C++ types. Here the
+ // matrix is automatically deserialized by calling its deserialize() routine.
+ st2.get_column(0, name);
+ st2.get_column(1, age);
+ st2.get_column(2, m);
+ cout << name << " " << age << "\n" << m << endl << endl;
+ }
+
+
+
+ // Finally, if you want to make a bunch of atomic changes to a database then you should
+ // do so inside a transaction. Here, either all the database modifications that occur
+ // between the creation of my_trans and the invocation of my_trans.commit() will appear
+ // in the database or none of them will. This way, if an exception or other error
+ // happens halfway though your transaction you won't be left with your database in an
+ // inconsistent state.
+ //
+ // Additionally, if you are going to do a large amount of inserts or updates then it is
+ // much faster to group them into a transaction.
+ transaction my_trans(db);
+
+ name = "Dude";
+ age = 49;
+ m = randm(4,2);
+ st.bind(1, name);
+ st.bind(2, age);
+ st.bind(3, m);
+ st.exec();
+
+ name = "Bob";
+ age = 29;
+ m = randm(2,2);
+ st.bind(1, name);
+ st.bind(2, age);
+ st.bind(3, m);
+ st.exec();
+
+ // If you comment out this line then you will see that these inserts do not take place.
+ // Specifically, what happens is that when my_trans is destructed it rolls back the
+ // entire transaction unless commit() has been called.
+ my_trans.commit();
+
+}
+catch (std::exception& e)
+{
+ cout << e.what() << endl;
+}
+
+// ----------------------------------------------------------------------------------------
+
+