trace_processor: split registration from schema generation

For span tables, we will need to discover the schema at
xCreate/xConnect time i.e. we won't know the schema of the table up
front.

Split these two orthogonal concepts to allow for span tables.

Change-Id: Ia62c44df8b4c6891d7637966578e8b32889bc6b3
diff --git a/src/trace_processor/counters_table.cc b/src/trace_processor/counters_table.cc
index 29fb6bf..86cf70c 100644
--- a/src/trace_processor/counters_table.cc
+++ b/src/trace_processor/counters_table.cc
@@ -29,19 +29,23 @@
 
 }  // namespace
 
-CountersTable::CountersTable(const TraceStorage* storage) : storage_(storage) {}
+CountersTable::CountersTable(sqlite3*, const TraceStorage* storage)
+    : storage_(storage) {}
 
 void CountersTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
-  Table::Register<CountersTable>(db, storage,
-                                 "CREATE TABLE counters("
-                                 "ts UNSIGNED BIG INT, "
-                                 "name text, "
-                                 "value UNSIGNED BIG INT, "
-                                 "dur UNSIGNED BIG INT, "
-                                 "ref UNSIGNED INT, "
-                                 "reftype TEXT, "
-                                 "PRIMARY KEY(name, ts, ref)"
-                                 ") WITHOUT ROWID;");
+  Table::Register<CountersTable>(db, storage, "counters");
+}
+
+std::string CountersTable::CreateTableStmt(int, const char* const*) {
+  return "CREATE TABLE x("
+         "ts UNSIGNED BIG INT, "
+         "name text, "
+         "value UNSIGNED BIG INT, "
+         "dur UNSIGNED BIG INT, "
+         "ref UNSIGNED INT, "
+         "reftype TEXT, "
+         "PRIMARY KEY(name, ts, ref)"
+         ") WITHOUT ROWID;";
 }
 
 std::unique_ptr<Table::Cursor> CountersTable::CreateCursor() {
diff --git a/src/trace_processor/counters_table.h b/src/trace_processor/counters_table.h
index 53dacba..a28f366 100644
--- a/src/trace_processor/counters_table.h
+++ b/src/trace_processor/counters_table.h
@@ -39,9 +39,10 @@
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
 
-  CountersTable(const TraceStorage*);
+  CountersTable(sqlite3*, const TraceStorage*);
 
   // Table implementation.
+  std::string CreateTableStmt(int argc, const char* const* argv) override;
   std::unique_ptr<Table::Cursor> CreateCursor() override;
   int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
 
diff --git a/src/trace_processor/process_table.cc b/src/trace_processor/process_table.cc
index e999617..a5b34e4 100644
--- a/src/trace_processor/process_table.cc
+++ b/src/trace_processor/process_table.cc
@@ -29,16 +29,20 @@
 
 }  // namespace
 
-ProcessTable::ProcessTable(const TraceStorage* storage) : storage_(storage) {}
+ProcessTable::ProcessTable(sqlite3*, const TraceStorage* storage)
+    : storage_(storage) {}
 
 void ProcessTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
-  Table::Register<ProcessTable>(db, storage,
-                                "CREATE TABLE process("
-                                "upid UNSIGNED INT, "
-                                "name TEXT, "
-                                "pid UNSIGNED INT, "
-                                "PRIMARY KEY(upid)"
-                                ") WITHOUT ROWID;");
+  Table::Register<ProcessTable>(db, storage, "process");
+}
+
+std::string ProcessTable::CreateTableStmt(int, const char* const*) {
+  return "CREATE TABLE x("
+         "upid UNSIGNED INT, "
+         "name TEXT, "
+         "pid UNSIGNED INT, "
+         "PRIMARY KEY(upid)"
+         ") WITHOUT ROWID;";
 }
 
 std::unique_ptr<Table::Cursor> ProcessTable::CreateCursor() {
diff --git a/src/trace_processor/process_table.h b/src/trace_processor/process_table.h
index 64bd1f5..33c5a30 100644
--- a/src/trace_processor/process_table.h
+++ b/src/trace_processor/process_table.h
@@ -34,9 +34,10 @@
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
 
-  ProcessTable(const TraceStorage*);
+  ProcessTable(sqlite3*, const TraceStorage*);
 
   // Table implementation.
+  std::string CreateTableStmt(int argc, const char* const* argv) override;
   std::unique_ptr<Table::Cursor> CreateCursor() override;
   int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
 
diff --git a/src/trace_processor/sched_slice_table.cc b/src/trace_processor/sched_slice_table.cc
index 2813dd7..ee0bff7 100644
--- a/src/trace_processor/sched_slice_table.cc
+++ b/src/trace_processor/sched_slice_table.cc
@@ -89,19 +89,22 @@
 
 }  // namespace
 
-SchedSliceTable::SchedSliceTable(const TraceStorage* storage)
+SchedSliceTable::SchedSliceTable(sqlite3*, const TraceStorage* storage)
     : storage_(storage) {}
 
 void SchedSliceTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
-  Table::Register<SchedSliceTable>(db, storage,
-                                   "CREATE TABLE sched("
-                                   "ts UNSIGNED BIG INT, "
-                                   "cpu UNSIGNED INT, "
-                                   "dur UNSIGNED BIG INT, "
-                                   "utid UNSIGNED INT, "
-                                   "cycles UNSIGNED BIG INT, "
-                                   "PRIMARY KEY(cpu, ts)"
-                                   ") WITHOUT ROWID;");
+  Table::Register<SchedSliceTable>(db, storage, "sched");
+}
+
+std::string SchedSliceTable::CreateTableStmt(int, const char* const*) {
+  return "CREATE TABLE sched("
+         "ts UNSIGNED BIG INT, "
+         "cpu UNSIGNED INT, "
+         "dur UNSIGNED BIG INT, "
+         "utid UNSIGNED INT, "
+         "cycles UNSIGNED BIG INT, "
+         "PRIMARY KEY(cpu, ts)"
+         ") WITHOUT ROWID;";
 }
 
 std::unique_ptr<Table::Cursor> SchedSliceTable::CreateCursor() {
diff --git a/src/trace_processor/sched_slice_table.h b/src/trace_processor/sched_slice_table.h
index f3e1750..25e4ee1 100644
--- a/src/trace_processor/sched_slice_table.h
+++ b/src/trace_processor/sched_slice_table.h
@@ -41,11 +41,12 @@
     kCycles = 4,
   };
 
-  SchedSliceTable(const TraceStorage* storage);
+  SchedSliceTable(sqlite3*, const TraceStorage* storage);
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
 
   // Table implementation.
+  std::string CreateTableStmt(int argc, const char* const* argv) override;
   std::unique_ptr<Table::Cursor> CreateCursor() override;
   int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
 
diff --git a/src/trace_processor/slice_table.cc b/src/trace_processor/slice_table.cc
index cbf82c8..e271d93 100644
--- a/src/trace_processor/slice_table.cc
+++ b/src/trace_processor/slice_table.cc
@@ -28,23 +28,27 @@
 namespace perfetto {
 namespace trace_processor {
 
-SliceTable::SliceTable(const TraceStorage* storage) : storage_(storage) {}
+SliceTable::SliceTable(sqlite3*, const TraceStorage* storage)
+    : storage_(storage) {}
 
 void SliceTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
-  Table::Register<SliceTable>(db, storage,
-                              "CREATE TABLE slices("
-                              "ts UNSIGNED BIG INT, "
-                              "dur UNSIGNED BIG INT, "
-                              "utid UNSIGNED INT,"
-                              "cat STRING,"
-                              "name STRING,"
-                              "depth INT,"
-                              "stack_id UNSIGNED BIG INT,"
-                              "parent_stack_id UNSIGNED BIG INT,"
-                              "PRIMARY KEY(utid, ts, depth)"
-                              ") WITHOUT ROWID;");
+  Table::Register<SliceTable>(db, storage, "slices");
+}
+
+std::string SliceTable::CreateTableStmt(int, const char* const*) {
   // TODO(primiano): add support for ts_lower_bound. It requires the guarantee
   // that slices are pushed in the storage monotonically.
+  return "CREATE TABLE x("
+         "ts UNSIGNED BIG INT, "
+         "dur UNSIGNED BIG INT, "
+         "utid UNSIGNED INT,"
+         "cat STRING,"
+         "name STRING,"
+         "depth INT,"
+         "stack_id UNSIGNED BIG INT,"
+         "parent_stack_id UNSIGNED BIG INT,"
+         "PRIMARY KEY(utid, ts, depth)"
+         ") WITHOUT ROWID;";
 }
 
 std::unique_ptr<Table::Cursor> SliceTable::CreateCursor() {
diff --git a/src/trace_processor/slice_table.h b/src/trace_processor/slice_table.h
index b821ec8..8cbf2a7 100644
--- a/src/trace_processor/slice_table.h
+++ b/src/trace_processor/slice_table.h
@@ -47,11 +47,12 @@
     kParentStackId = 7,
   };
 
-  SliceTable(const TraceStorage* storage);
+  SliceTable(sqlite3*, const TraceStorage* storage);
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
 
   // Table implementation.
+  std::string CreateTableStmt(int argc, const char* const* argv) override;
   std::unique_ptr<Table::Cursor> CreateCursor() override;
   int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
 
diff --git a/src/trace_processor/string_table.cc b/src/trace_processor/string_table.cc
index 7324d0c..9e204d1 100644
--- a/src/trace_processor/string_table.cc
+++ b/src/trace_processor/string_table.cc
@@ -28,15 +28,19 @@
 namespace perfetto {
 namespace trace_processor {
 
-StringTable::StringTable(const TraceStorage* storage) : storage_(storage) {}
+StringTable::StringTable(sqlite3*, const TraceStorage* storage)
+    : storage_(storage) {}
 
 void StringTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
-  Table::Register<StringTable>(db, storage,
-                               "CREATE TABLE strings("
-                               "id UNSIGNED BIG INT, "
-                               "str STRING,"
-                               "PRIMARY KEY(id)"
-                               ") WITHOUT ROWID;");
+  Table::Register<StringTable>(db, storage, "strings");
+}
+
+std::string StringTable::CreateTableStmt(int, const char* const*) {
+  return "CREATE TABLE x("
+         "id UNSIGNED BIG INT, "
+         "str STRING,"
+         "PRIMARY KEY(id)"
+         ") WITHOUT ROWID;";
 }
 
 std::unique_ptr<Table::Cursor> StringTable::CreateCursor() {
diff --git a/src/trace_processor/string_table.h b/src/trace_processor/string_table.h
index 324969f..1d5efc7 100644
--- a/src/trace_processor/string_table.h
+++ b/src/trace_processor/string_table.h
@@ -36,11 +36,12 @@
     kString = 1,
   };
 
-  StringTable(const TraceStorage* storage);
+  StringTable(sqlite3*, const TraceStorage* storage);
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
 
   // Table implementation.
+  std::string CreateTableStmt(int argc, const char* const* argv) override;
   std::unique_ptr<Table::Cursor> CreateCursor() override;
   int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
 
diff --git a/src/trace_processor/table.cc b/src/trace_processor/table.cc
index d21a014..75eac08 100644
--- a/src/trace_processor/table.cc
+++ b/src/trace_processor/table.cc
@@ -27,10 +27,9 @@
 namespace {
 
 struct TableDescriptor {
-  std::string name;
-  std::string create_statement;
   Table::Factory factory;
   const TraceStorage* storage = nullptr;
+  std::string name;
   sqlite3_module module = {};
 };
 
@@ -52,34 +51,31 @@
 
 void Table::RegisterInternal(sqlite3* db,
                              const TraceStorage* storage,
-                             const std::string& create_statement,
+                             const std::string& table_name,
                              Factory factory) {
-  const std::string prefix = "CREATE TABLE ";
-  PERFETTO_CHECK(create_statement.substr(0, prefix.size()) == prefix);
-  size_t name_end = create_statement.find("(");
-  PERFETTO_CHECK(name_end != std::string::npos && name_end > prefix.size());
-  auto table_name =
-      create_statement.substr(prefix.size(), name_end - prefix.size());
-  PERFETTO_CHECK(table_name.size() > 0 && isalnum(table_name.front()) &&
-                 isalnum(table_name.back()));
-
   std::unique_ptr<TableDescriptor> desc(new TableDescriptor());
-  desc->name = table_name;
-  desc->create_statement = create_statement;
   desc->storage = storage;
   desc->factory = factory;
+  desc->name = table_name;
   sqlite3_module* module = &desc->module;
   memset(module, 0, sizeof(*module));
 
-  module->xConnect = [](sqlite3* xdb, void* arg, int, const char* const*,
-                        sqlite3_vtab** tab, char**) {
+  module->xConnect = [](sqlite3* xdb, void* arg, int argc,
+                        const char* const* argv, sqlite3_vtab** tab, char**) {
     const TableDescriptor* xdesc = static_cast<const TableDescriptor*>(arg);
-    int res = sqlite3_declare_vtab(xdb, xdesc->create_statement.c_str());
+    auto table = xdesc->factory(xdb, xdesc->storage);
+
+    auto create_stmt = table->CreateTableStmt(argc, argv);
+    if (create_stmt.empty())
+      return SQLITE_ERROR;
+
+    int res = sqlite3_declare_vtab(xdb, create_stmt.c_str());
     if (res != SQLITE_OK)
       return res;
 
     // Freed in xDisconnect().
-    *tab = xdesc->factory(xdesc->storage, xdesc->name).release();
+    table->name_ = xdesc->name;
+    *tab = table.release();
 
     return SQLITE_OK;
   };
diff --git a/src/trace_processor/table.h b/src/trace_processor/table.h
index 9118d08..f5da6f3 100644
--- a/src/trace_processor/table.h
+++ b/src/trace_processor/table.h
@@ -37,8 +37,7 @@
 class Table : public sqlite3_vtab {
  public:
   using Factory =
-      std::function<std::unique_ptr<Table>(const TraceStorage*,
-                                           const std::string& name)>;
+      std::function<std::unique_ptr<Table>(sqlite3*, const TraceStorage*)>;
 
   // When set it logs all BestIndex and Filter actions on the console.
   static bool debug;
@@ -80,11 +79,12 @@
   template <typename T>
   static void Register(sqlite3* db,
                        const TraceStorage* storage,
-                       const std::string& create_statement) {
-    RegisterInternal(db, storage, create_statement, GetFactory<T>());
+                       const std::string& name) {
+    RegisterInternal(db, storage, name, GetFactory<T>());
   }
 
   // Methods to be implemented by derived table classes.
+  virtual std::string CreateTableStmt(int argc, const char* const* argv) = 0;
   virtual std::unique_ptr<Cursor> CreateCursor() = 0;
   virtual int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) = 0;
 
@@ -95,16 +95,14 @@
  private:
   template <typename TableType>
   static Factory GetFactory() {
-    return [](const TraceStorage* storage, const std::string& name) {
-      auto table = std::unique_ptr<Table>(new TableType(storage));
-      table->name_ = name;
-      return table;
+    return [](sqlite3* db, const TraceStorage* storage) {
+      return std::unique_ptr<Table>(new TableType(db, storage));
     };
   }
 
   static void RegisterInternal(sqlite3* db,
                                const TraceStorage*,
-                               const std::string& create,
+                               const std::string& name,
                                Factory);
 
   // Overriden functions from sqlite3_vtab.
diff --git a/src/trace_processor/thread_table.cc b/src/trace_processor/thread_table.cc
index 34287ce..c130c3c 100644
--- a/src/trace_processor/thread_table.cc
+++ b/src/trace_processor/thread_table.cc
@@ -29,17 +29,21 @@
 
 }  // namespace
 
-ThreadTable::ThreadTable(const TraceStorage* storage) : storage_(storage) {}
+ThreadTable::ThreadTable(sqlite3*, const TraceStorage* storage)
+    : storage_(storage) {}
 
 void ThreadTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
-  Table::Register<ThreadTable>(db, storage,
-                               "CREATE TABLE thread("
-                               "utid UNSIGNED INT, "
-                               "upid UNSIGNED INT, "
-                               "name TEXT, "
-                               "tid UNSIGNED INT, "
-                               "PRIMARY KEY(utid)"
-                               ") WITHOUT ROWID;");
+  Table::Register<ThreadTable>(db, storage, "thread");
+}
+
+std::string ThreadTable::CreateTableStmt(int, const char* const*) {
+  return "CREATE TABLE x("
+         "utid UNSIGNED INT, "
+         "upid UNSIGNED INT, "
+         "name TEXT, "
+         "tid UNSIGNED INT, "
+         "PRIMARY KEY(utid)"
+         ") WITHOUT ROWID;";
 }
 
 std::unique_ptr<Table::Cursor> ThreadTable::CreateCursor() {
diff --git a/src/trace_processor/thread_table.h b/src/trace_processor/thread_table.h
index d5b3609..9b19b1b 100644
--- a/src/trace_processor/thread_table.h
+++ b/src/trace_processor/thread_table.h
@@ -34,9 +34,10 @@
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
 
-  ThreadTable(const TraceStorage*);
+  ThreadTable(sqlite3*, const TraceStorage*);
 
   // Table implementation.
+  std::string CreateTableStmt(int argc, const char* const* argv) override;
   std::unique_ptr<Table::Cursor> CreateCursor() override;
   int BestIndex(const QueryConstraints&, BestIndexInfo*) override;