scc 2025.09
SystemC components library
scv_tr_sqlite.cpp
1/*******************************************************************************
2 * Copyright 2014, 2018 MINRES Technologies GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16#include "sqlite3.h"
17#include <array>
18#include <cstdio>
19#include <iostream>
20#include <sstream>
21#include <stdexcept>
22#include <string>
23#include <unordered_map>
24#include <vector>
25#ifdef HAS_SCV
26#include <scv.h>
27#else
28#include <scv-tr.h>
29namespace scv_tr {
30#endif
31// ----------------------------------------------------------------------------
32constexpr auto SQLITEWRAPPER_ERROR = 1000;
33constexpr auto with_transactions = false;
34// ----------------------------------------------------------------------------
35using namespace std;
36
37class SQLiteDB {
38public:
39 class SQLiteException : public runtime_error {
40 public:
41 SQLiteException(const int nErrCode, const char* msg, bool doFree = true)
42 : runtime_error(msg)
43 , mnErrCode(0) {
44 if(doFree && msg)
45 sqlite3_free(const_cast<char*>(msg));
46 }
47 const int errorCode() { return mnErrCode; }
48 const char* errorMessage() { return what(); }
49
50 private:
51 int mnErrCode;
52 };
53
54 SQLiteDB() = default;
55
56 void open(const string szFile) {
57 int nRet = sqlite3_open(szFile.c_str(), &db);
58 if(nRet != SQLITE_OK)
59 throw SQLiteException(nRet, sqlite3_errmsg(db), false);
60 sqlite3_busy_timeout(db, busyTimeoutMs);
61 sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, 1ULL << 26, 1ULL << 30);
62 char* zSql = sqlite3_mprintf("PRAGMA journal_mode=OFF;\n"
63 "PRAGMA synchronous=OFF;\n");
64 char* zErrMsg = nullptr;
65 nRet = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
66 if(nRet != SQLITE_OK)
67 throw SQLiteException(nRet, sqlite3_errmsg(db), false);
68 sqlite3_free(zSql);
69 }
70
71 inline bool isOpen() { return db != nullptr; }
72
73 void close() {
74 if(db) {
75 int nRet = sqlite3_close(db);
76 if(nRet == SQLITE_OK)
77 db = nullptr;
78 else if(nRet == SQLITE_BUSY) {
79 while(nRet == SQLITE_BUSY) { // maybe include _LOCKED
80 sqlite3_stmt* stmt = sqlite3_next_stmt(db, nullptr);
81 if(stmt)
82 sqlite3_finalize(stmt); // don't trap, can't handle it anyway
83 nRet = sqlite3_close(db);
84 }
85 if(nRet != SQLITE_OK)
86 throw SQLiteException(SQLITEWRAPPER_ERROR, "Unable to close database", false);
87 db = nullptr;
88 } else
89 throw SQLiteException(SQLITEWRAPPER_ERROR, "Unable to close database", false);
90 }
91 }
92
93 inline int exec(const string szSQL) { return exec(szSQL.c_str()); }
94 inline sqlite3_stmt* prepare(const string szSQL) {
95 sqlite3_stmt* ret = nullptr;
96 const char* tail;
97 sqlite3_prepare_v2(db, szSQL.c_str(), szSQL.size(), &ret, &tail);
98 return ret;
99 }
100
101 int exec(const char* szSQL) {
102 checkDB();
103 char* szError = nullptr;
104 int nRet = sqlite3_exec(db, szSQL, nullptr, nullptr, &szError);
105 if(nRet == SQLITE_OK)
106 return sqlite3_changes(db);
107 else
108 throw SQLiteException(nRet, szError);
109 }
110
111 int exec(sqlite3_stmt* stmt) {
112 checkDB();
113 int nRet = sqlite3_step(stmt);
114 if(nRet == SQLITE_OK || nRet == SQLITE_DONE) {
115 sqlite3_reset(stmt);
116 return sqlite3_changes(db);
117 } else
118 throw SQLiteException(nRet, sqlite3_errmsg(db));
119 }
120
121protected:
122 inline void checkDB() {
123 if(!db)
124 throw SQLiteException(SQLITEWRAPPER_ERROR, "Database not open", false);
125 }
126
127private:
128 int busyTimeoutMs{60000};
129 sqlite3* db{nullptr};
130};
131// ----------------------------------------------------------------------------
132static SQLiteDB db;
133static vector<vector<uint64_t>*> concurrencyLevel;
134static sqlite3_stmt *string_stmt, *stream_stmt, *gen_stmt, *tx_stmt, *evt_stmt, *attr_stmt, *rel_stmt;
135
136// ----------------------------------------------------------------------------
137enum EventType { BEGIN, RECORD, END };
138using data_type = scv_extensions_if::data_type;
139// ----------------------------------------------------------------------------
140#define SIM_PROPS "ScvSimProps"
141#define STRING_TABLE "ScvStrings"
142#define STREAM_TABLE "ScvStream"
143#define GENERATOR_TABLE "ScvGenerator"
144#define TX_TABLE "ScvTx"
145#define TX_EVENT_TABLE "ScvTxEvent"
146#define TX_ATTRIBUTE_TABLE "ScvTxAttribute"
147#define TX_RELATION_TABLE "ScvTxRelation"
148
149static void dbCb(const scv_tr_db& _scv_tr_db, scv_tr_db::callback_reason reason, void* data) {
150 char* tail = nullptr;
151 // This is called from the scv_tr_db ctor.
152 static string fName("DEFAULT_scv_tr_sqlite");
153 switch(reason) {
154 case scv_tr_db::CREATE:
155 if((_scv_tr_db.get_name() != nullptr) && (strlen(_scv_tr_db.get_name()) != 0))
156 fName = _scv_tr_db.get_name();
157 try {
158 remove(fName.c_str());
159 db.open(fName);
160 // performance related according to
161 // http://blog.quibb.org/2010/08/fast-bulk-inserts-into-sqlite/
162 db.exec("PRAGMA synchronous=OFF");
163 db.exec("PRAGMA count_changes=OFF");
164 db.exec("PRAGMA journal_mode=OFF");
165 db.exec("PRAGMA temp_store=MEMORY");
166 // scv_out << "TB Transaction Recording has started, file = " <<
167 // my_sqlite_file_name << endl;
168 db.exec("CREATE TABLE IF NOT EXISTS " STRING_TABLE "("
169 "id INTEGER NOT null PRIMARY KEY, "
170 "value TEXT"
171 ");");
172 db.exec("CREATE TABLE IF NOT EXISTS " STREAM_TABLE "("
173 "id INTEGER NOT null PRIMARY KEY, "
174 "name INTEGER REFERENCES " STRING_TABLE "(id), "
175 "kind INTEGER REFERENCES " STRING_TABLE "(id)"
176 ");");
177 db.exec("CREATE TABLE IF NOT EXISTS " GENERATOR_TABLE "("
178 "id INTEGER NOT null PRIMARY KEY, "
179 "stream INTEGER REFERENCES " STREAM_TABLE "(id), "
180 "name INTEGER REFERENCES " STRING_TABLE "(id), "
181 "begin_attr INTEGER, "
182 "end_attr INTEGER"
183 ");");
184 db.exec("CREATE TABLE IF NOT EXISTS " TX_TABLE "("
185 "id INTEGER NOT null PRIMARY KEY, "
186 "generator INTEGER REFERENCES " GENERATOR_TABLE "(id), "
187 "stream INTEGER REFERENCES " STREAM_TABLE "(id), "
188 "concurrencyLevel INTEGER"
189 ");");
190 db.exec("CREATE TABLE IF NOT EXISTS " TX_EVENT_TABLE "("
191 "tx INTEGER REFERENCES " TX_TABLE "(id), "
192 "type INTEGER, "
193 "time INTEGER"
194 ");");
195 db.exec("CREATE TABLE IF NOT EXISTS " TX_ATTRIBUTE_TABLE "("
196 "tx INTEGER REFERENCES " TX_TABLE "(id), "
197 "type INTEGER, "
198 "name INTEGER REFERENCES " STRING_TABLE "(id), "
199 "data_type INTEGER, "
200 "data_value TEXT"
201 ");");
202 db.exec("CREATE TABLE IF NOT EXISTS " TX_RELATION_TABLE "("
203 "name INTEGER REFERENCES " STRING_TABLE "(id), "
204 "src INTEGER REFERENCES " TX_TABLE "(id), "
205 "sink INTEGER REFERENCES " TX_TABLE "(id)"
206 ");");
207 db.exec("CREATE TABLE IF NOT EXISTS " SIM_PROPS "(time_resolution INTEGER);");
208 if(with_transactions)
209 db.exec("BEGIN TRANSACTION");
210 std::ostringstream ss;
211 ss << "INSERT INTO " SIM_PROPS " (time_resolution) values (" << (long)(sc_core::sc_get_time_resolution().to_seconds() * 1e15)
212 << ");";
213 db.exec(ss.str().c_str());
214 string_stmt = db.prepare("INSERT INTO " STRING_TABLE " (id, value) values (@ID,@VALUE);");
215 stream_stmt = db.prepare("INSERT INTO " STREAM_TABLE " (id, name, kind) values (@ID,@NAME,@KIND);");
216 gen_stmt = db.prepare("INSERT INTO " GENERATOR_TABLE " (id,stream, name)"
217 " values (@ID,@STRM_DI,@NAME);");
218 tx_stmt = db.prepare("INSERT INTO " TX_TABLE " (id,generator,stream, concurrencyLevel)"
219 " values (@ID,@GEN_ID,@STREAM_ID,@CONC_LEVEL);");
220 evt_stmt = db.prepare("INSERT INTO " TX_EVENT_TABLE " (tx,type,time)"
221 " values (@TX_ID,@TYPE,@TIMESTAMP);");
222 attr_stmt = db.prepare("INSERT INTO " TX_ATTRIBUTE_TABLE " (tx,type,name,data_type,data_value) "
223 "values (@ID,@EVENTID,@NAME,@TYPE,@VALUE);");
224 rel_stmt = db.prepare("INSERT INTO " TX_RELATION_TABLE " (name,sink,src)"
225 "values (@NAME,@ID1,@ID2);");
226 } catch(SQLiteDB::SQLiteException& e) {
227 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't open recording file");
228 }
229 break;
230 case scv_tr_db::DELETE:
231 try {
232 // scv_out << "Transaction Recording is closing file: " <<
233 // my_sqlite_file_name << endl;
234 if(with_transactions)
235 db.exec("COMMIT TRANSACTION");
236 db.close();
237 } catch(SQLiteDB::SQLiteException& e) {
238 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't close recording file");
239 }
240 break;
241 default:
242 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Unknown reason in scv_tr_db callback");
243 }
244}
245// ----------------------------------------------------------------------------
246static std::unordered_map<std::string, uint64_t> str_map;
247uint64_t getStringId(std::string const& s) {
248 auto it = str_map.find(s);
249 if(it != std::end(str_map))
250 return it->second;
251 auto id = str_map.size();
252 str_map.insert({s, id});
253 try {
254 sqlite3_bind_int64(string_stmt, 1, id);
255 sqlite3_bind_text(string_stmt, 2, s.c_str(), -1, SQLITE_TRANSIENT);
256 db.exec(string_stmt);
257 } catch(SQLiteDB::SQLiteException& e) {
258 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create string entry");
259 }
260 return id;
261}
262// ----------------------------------------------------------------------------
263static void streamCb(const scv_tr_stream& s, scv_tr_stream::callback_reason reason, void* data) {
264 if(reason == scv_tr_stream::CREATE && db.isOpen()) {
265 try {
266 sqlite3_bind_int64(stream_stmt, 1, s.get_id());
267 sqlite3_bind_int64(stream_stmt, 2, getStringId(s.get_name()));
268 sqlite3_bind_int64(stream_stmt, 3, getStringId(s.get_stream_kind() ? s.get_stream_kind() : "<unnamed>"));
269 db.exec(stream_stmt);
270 if(concurrencyLevel.size() <= s.get_id())
271 concurrencyLevel.resize(s.get_id() + 1);
272 concurrencyLevel[s.get_id()] = new vector<uint64_t>();
273 } catch(SQLiteDB::SQLiteException& e) {
274 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create stream");
275 }
276 }
277}
278// ----------------------------------------------------------------------------
279void recordAttribute(uint64_t id, EventType event, const string& name, data_type type, const string& value) {
280 try {
281 sqlite3_bind_int64(attr_stmt, 1, id);
282 sqlite3_bind_int64(attr_stmt, 2, event);
283 sqlite3_bind_int64(attr_stmt, 3, getStringId(name));
284 sqlite3_bind_int64(attr_stmt, 4, type);
285 sqlite3_bind_int64(attr_stmt, 5, getStringId(value));
286 db.exec(attr_stmt);
287 } catch(SQLiteDB::SQLiteException& e) {
288 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create attribute entry");
289 }
290}
291// ----------------------------------------------------------------------------
292inline void recordAttribute(uint64_t id, EventType event, const string& name, data_type type, long long value) {
293 recordAttribute(id, event, name, type, std::to_string(value));
294}
295// ----------------------------------------------------------------------------
296inline void recordAttribute(uint64_t id, EventType event, const string& name, data_type type, double value) {
297 recordAttribute(id, event, name, type, std::to_string(value));
298}
299// ----------------------------------------------------------------------------
300static void recordAttributes(uint64_t id, EventType eventType, string& prefix, const scv_extensions_if* my_exts_p) {
301 if(my_exts_p == nullptr)
302 return;
303 string name;
304 if(prefix == "") {
305 name = my_exts_p->get_name();
306 } else {
307 if((my_exts_p->get_name() == nullptr) || (strlen(my_exts_p->get_name()) == 0)) {
308 name = prefix;
309 } else {
310 name = prefix + "." + my_exts_p->get_name();
311 }
312 }
313 if(name == "")
314 name = "<unnamed>";
315 switch(my_exts_p->get_type()) {
316 case scv_extensions_if::RECORD: {
317 int num_fields = my_exts_p->get_num_fields();
318 if(num_fields > 0) {
319 for(int field_counter = 0; field_counter < num_fields; field_counter++) {
320 const scv_extensions_if* field_data_p = my_exts_p->get_field(field_counter);
321 recordAttributes(id, eventType, prefix, field_data_p);
322 }
323 }
324 } break;
325 case scv_extensions_if::ENUMERATION:
326 recordAttribute(id, eventType, name, scv_extensions_if::ENUMERATION, my_exts_p->get_enum_string((int)(my_exts_p->get_integer())));
327 break;
328 case scv_extensions_if::BOOLEAN:
329 recordAttribute(id, eventType, name, scv_extensions_if::BOOLEAN, my_exts_p->get_bool() ? "TRUE" : "FALSE");
330 break;
331 case scv_extensions_if::INTEGER:
332 case scv_extensions_if::FIXED_POINT_INTEGER:
333 recordAttribute(id, eventType, name, scv_extensions_if::INTEGER, my_exts_p->get_integer());
334 break;
335 case scv_extensions_if::UNSIGNED:
336 recordAttribute(id, eventType, name, scv_extensions_if::UNSIGNED, my_exts_p->get_integer());
337 break;
338 case scv_extensions_if::POINTER:
339 recordAttribute(id, eventType, name, scv_extensions_if::POINTER, (long long)my_exts_p->get_pointer());
340 break;
341 case scv_extensions_if::STRING:
342 recordAttribute(id, eventType, name, scv_extensions_if::STRING, my_exts_p->get_string());
343 break;
344 case scv_extensions_if::FLOATING_POINT_NUMBER:
345 recordAttribute(id, eventType, name, scv_extensions_if::FLOATING_POINT_NUMBER, my_exts_p->get_double());
346 break;
347 case scv_extensions_if::BIT_VECTOR: {
348 sc_bv_base tmp_bv(my_exts_p->get_bitwidth());
349 my_exts_p->get_value(tmp_bv);
350 recordAttribute(id, eventType, name, scv_extensions_if::BIT_VECTOR, tmp_bv.to_string());
351 } break;
352 case scv_extensions_if::LOGIC_VECTOR: {
353 sc_lv_base tmp_lv(my_exts_p->get_bitwidth());
354 my_exts_p->get_value(tmp_lv);
355 recordAttribute(id, eventType, name, scv_extensions_if::LOGIC_VECTOR, tmp_lv.to_string());
356 } break;
357 case scv_extensions_if::ARRAY:
358 for(int array_elt_index = 0; array_elt_index < my_exts_p->get_array_size(); array_elt_index++) {
359 const scv_extensions_if* field_data_p = my_exts_p->get_array_elt(array_elt_index);
360 recordAttributes(id, eventType, prefix, field_data_p);
361 }
362 break;
363 default: {
364 std::array<char, 100> tmpString{};
365 sprintf(tmpString.data(), "Unsupported attribute type = %d", my_exts_p->get_type());
366 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, tmpString.data());
367 }
368 }
369}
370// ----------------------------------------------------------------------------
371static void generatorCb(const scv_tr_generator_base& g, scv_tr_generator_base::callback_reason reason, void* data) {
372 if(reason == scv_tr_generator_base::CREATE && db.isOpen()) {
373 try {
374 sqlite3_bind_int64(gen_stmt, 1, g.get_id());
375 sqlite3_bind_int64(gen_stmt, 2, g.get_scv_tr_stream().get_id());
376 sqlite3_bind_int64(gen_stmt, 3, getStringId(g.get_name()));
377 db.exec(gen_stmt);
378 } catch(SQLiteDB::SQLiteException& e) {
379 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create generator entry");
380 }
381 }
382}
383// ----------------------------------------------------------------------------
384static void transactionCb(const scv_tr_handle& t, scv_tr_handle::callback_reason reason, void* data) {
385 if(!db.isOpen())
386 return;
387 if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
388 return;
389 if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
390 return;
391
392 uint64_t id = t.get_id();
393 uint64_t streamId = t.get_scv_tr_stream().get_id();
394 vector<uint64_t>::size_type concurrencyIdx;
395 const scv_extensions_if* my_exts_p;
396 switch(reason) {
397 case scv_tr_handle::BEGIN: {
398 try {
399 if(concurrencyLevel.size() <= streamId)
400 concurrencyLevel.resize(streamId + 1);
401 vector<uint64_t>* levels = concurrencyLevel[streamId];
402 if(levels == nullptr) {
403 levels = new vector<uint64_t>();
404 concurrencyLevel[id] = levels;
405 }
406 for(concurrencyIdx = 0; concurrencyIdx < levels->size(); ++concurrencyIdx)
407 if((*levels)[concurrencyIdx] == 0)
408 break;
409 if(concurrencyIdx == levels->size())
410 levels->push_back(id);
411 else
412 (*levels)[concurrencyIdx] = id;
413
414 sqlite3_bind_int64(tx_stmt, 1, id);
415 sqlite3_bind_int64(tx_stmt, 2, t.get_scv_tr_generator_base().get_id());
416 sqlite3_bind_int64(tx_stmt, 3, t.get_scv_tr_stream().get_id());
417 sqlite3_bind_int64(tx_stmt, 3, concurrencyIdx);
418 db.exec(tx_stmt);
419
420 sqlite3_bind_int64(evt_stmt, 1, id);
421 sqlite3_bind_int(evt_stmt, 2, BEGIN);
422 sqlite3_bind_int64(evt_stmt, 3, t.get_begin_sc_time().value());
423 db.exec(evt_stmt);
424
425 } catch(SQLiteDB::SQLiteException& e) {
426 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, e.errorMessage());
427 }
428 my_exts_p = t.get_begin_exts_p();
429 if(my_exts_p == nullptr) {
430 my_exts_p = t.get_scv_tr_generator_base().get_begin_exts_p();
431 }
432 string tmp_str =
433 t.get_scv_tr_generator_base().get_begin_attribute_name() ? t.get_scv_tr_generator_base().get_begin_attribute_name() : "";
434 recordAttributes(id, BEGIN, tmp_str, my_exts_p);
435 } break;
436 case scv_tr_handle::END: {
437 try {
438 vector<uint64_t>* levels = concurrencyLevel[streamId];
439 for(concurrencyIdx = 0; concurrencyIdx < levels->size(); ++concurrencyIdx)
440 if((*levels)[concurrencyIdx] == id)
441 break;
442 if(concurrencyIdx == levels->size())
443 levels->push_back(id);
444 else
445 levels->at(concurrencyIdx) = id;
446
447 sqlite3_bind_int64(evt_stmt, 1, t.get_id());
448 sqlite3_bind_int(evt_stmt, 2, END);
449 sqlite3_bind_int64(evt_stmt, 3, t.get_end_sc_time().value());
450 db.exec(evt_stmt);
451
452 } catch(SQLiteDB::SQLiteException& e) {
453 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create transaction end");
454 }
455 my_exts_p = t.get_end_exts_p();
456 if(my_exts_p == nullptr) {
457 my_exts_p = t.get_scv_tr_generator_base().get_end_exts_p();
458 }
459 string tmp_str =
460 t.get_scv_tr_generator_base().get_end_attribute_name() ? t.get_scv_tr_generator_base().get_end_attribute_name() : "";
461 recordAttributes(t.get_id(), END, tmp_str, my_exts_p);
462 } break;
463 default:;
464 }
465}
466// ----------------------------------------------------------------------------
467static void attributeCb(const scv_tr_handle& t, const char* name, const scv_extensions_if* ext, void* data) {
468 if(!db.isOpen())
469 return;
470 if(t.get_scv_tr_stream().get_scv_tr_db() == nullptr)
471 return;
472 if(t.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
473 return;
474 string tmp_str(name == nullptr ? "" : name);
475 recordAttributes(t.get_id(), RECORD, tmp_str, ext);
476}
477// ----------------------------------------------------------------------------
478static void relationCb(const scv_tr_handle& tr_1, const scv_tr_handle& tr_2, void* data, scv_tr_relation_handle_t relation_handle) {
479 if(!db.isOpen())
480 return;
481 if(tr_1.get_scv_tr_stream().get_scv_tr_db() == nullptr)
482 return;
483 if(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_recording() == false)
484 return;
485 try {
486 sqlite3_bind_int64(rel_stmt, 1, getStringId(tr_1.get_scv_tr_stream().get_scv_tr_db()->get_relation_name(relation_handle)));
487 sqlite3_bind_int64(rel_stmt, 2, tr_1.get_id());
488 sqlite3_bind_int64(rel_stmt, 3, tr_2.get_id());
489 db.exec(rel_stmt);
490 } catch(SQLiteDB::SQLiteException& e) {
491 _scv_message::message(_scv_message::TRANSACTION_RECORDING_INTERNAL, "Can't create transaction relation");
492 }
493}
494// ----------------------------------------------------------------------------
496 scv_tr_db::register_class_cb(dbCb);
497 scv_tr_stream::register_class_cb(streamCb);
498 scv_tr_generator_base::register_class_cb(generatorCb);
499 scv_tr_handle::register_class_cb(transactionCb);
500 scv_tr_handle::register_record_attribute_cb(attributeCb);
501 scv_tr_handle::register_relation_cb(relationCb);
502}
503// ----------------------------------------------------------------------------
504#ifndef HAS_SCV
505}
506#endif
SystemC Verification Library (SCV) Transaction Recording.
void scv_tr_sqlite_init()
initializes the infrastructure to use a SQLite based transaction recording database