55 constexpr
char const *gSQliteVfsName =
"ROOT-Davix-readonly";
64 VfsRootFile() =
default;
67 std::unique_ptr<ROOT::Internal::RRawFile> fRawFile;
74 int VfsRdOnlyClose(sqlite3_file *pFile)
76 VfsRootFile *p =
reinterpret_cast<VfsRootFile *
>(pFile);
84 int VfsRdOnlyRead(sqlite3_file *pFile,
void *zBuf,
int count, sqlite_int64 offset)
86 VfsRootFile *p =
reinterpret_cast<VfsRootFile *
>(pFile);
87 auto nbytes = p->fRawFile->ReadAt(zBuf, count, offset);
88 return (nbytes != static_cast<unsigned int>(count)) ? SQLITE_IOERR : SQLITE_OK;
93 int VfsRdOnlyWrite(sqlite3_file * ,
const void * ,
int , sqlite_int64 )
95 return SQLITE_OPEN_READONLY;
100 int VfsRdOnlyTruncate(sqlite3_file * , sqlite_int64 )
102 return SQLITE_OPEN_READONLY;
107 int VfsRdOnlySync(sqlite3_file * ,
int )
114 int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize)
116 VfsRootFile *p =
reinterpret_cast<VfsRootFile *
>(pFile);
117 *pSize = p->fRawFile->GetSize();
123 int VfsRdOnlyLock(sqlite3_file * ,
int )
130 int VfsRdOnlyUnlock(sqlite3_file * ,
int )
137 int VfsRdOnlyCheckReservedLock(sqlite3_file * ,
int *pResOut)
145 int VfsRdOnlyFileControl(sqlite3_file * ,
int ,
void * )
147 return SQLITE_NOTFOUND;
152 int VfsRdOnlySectorSize(sqlite3_file * )
154 return SQLITE_OPEN_READONLY;
159 int VfsRdOnlyDeviceCharacteristics(sqlite3_file * )
161 return SQLITE_OPEN_READONLY;
166 int VfsRdOnlyOpen(sqlite3_vfs * ,
const char *zName, sqlite3_file *pFile,
int flags,
int * )
169 VfsRootFile *p =
new (pFile) VfsRootFile();
170 p->pFile.pMethods =
nullptr;
174 static const sqlite3_io_methods io_methods = {
184 VfsRdOnlyCheckReservedLock,
185 VfsRdOnlyFileControl,
187 VfsRdOnlyDeviceCharacteristics,
197 if (flags & (SQLITE_OPEN_READWRITE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_EXCLUSIVE))
200 p->fRawFile = ROOT::Internal::RRawFile::Create(zName);
202 ::Error(
"VfsRdOnlyOpen",
"Cannot open %s\n", zName);
206 if (!(p->fRawFile->GetFeatures() & ROOT::Internal::RRawFile::kFeatureHasSize)) {
207 ::Error(
"VfsRdOnlyOpen",
"cannot determine file size of %s\n", zName);
211 p->pFile.pMethods = &io_methods;
221 int VfsRdOnlyDelete(sqlite3_vfs * ,
const char * ,
int )
223 return SQLITE_IOERR_DELETE;
228 int VfsRdOnlyAccess(sqlite3_vfs * ,
const char * ,
int flags,
int *pResOut)
231 if (flags == SQLITE_ACCESS_READWRITE) {
232 return SQLITE_OPEN_READONLY;
239 int VfsRdOnlyFullPathname(sqlite3_vfs * ,
const char *zPath,
int nOut,
char *zOut)
241 zOut[nOut - 1] =
'\0';
242 sqlite3_snprintf(nOut, zOut,
"%s", zPath);
248 int VfsRdOnlyRandomness(sqlite3_vfs * ,
int nBuf,
char *zBuf)
250 for (
int i = 0; i < nBuf; ++i) {
251 zBuf[i] = (char)gRandom->Integer(256);
258 int VfsRdOnlySleep(sqlite3_vfs * ,
int microseconds)
261 gSystem->Sleep((microseconds + 1000 - 1) / 1000);
267 int VfsRdOnlyGetLastError(sqlite3_vfs * ,
int ,
char * )
274 int VfsRdOnlyCurrentTimeInt64(sqlite3_vfs * , sqlite3_int64 *piNow)
276 static constexpr sqlite3_int64 unixEpoch = 24405875 * (sqlite3_int64)8640000;
279 *piNow = ((sqlite3_int64)t) * 1000 + unixEpoch;
285 int VfsRdOnlyCurrentTime(sqlite3_vfs *vfs,
double *prNow)
288 int rc = VfsRdOnlyCurrentTimeInt64(vfs, &i);
289 *prNow = i / 86400000.0;
295 static struct sqlite3_vfs kSqlite3Vfs = {
305 VfsRdOnlyFullPathname,
312 VfsRdOnlyCurrentTime,
313 VfsRdOnlyGetLastError,
314 VfsRdOnlyCurrentTimeInt64,
321 static bool RegisterSqliteVfs()
324 retval = sqlite3_vfs_register(&kSqlite3Vfs,
false);
325 return (retval == SQLITE_OK);
337 struct RSqliteDSDataSet {
338 sqlite3 *fDb =
nullptr;
339 sqlite3_stmt *fQuery =
nullptr;
343 RSqliteDS::Value_t::Value_t(RSqliteDS::ETypes type)
344 : fType(type), fIsActive(false), fInteger(0), fReal(0.0), fText(), fBlob(), fNull(nullptr)
347 case ETypes::kInteger: fPtr = &fInteger;
break;
348 case ETypes::kReal: fPtr = &fReal;
break;
349 case ETypes::kText: fPtr = &fText;
break;
350 case ETypes::kBlob: fPtr = &fBlob;
break;
351 case ETypes::kNull: fPtr = &fNull;
break;
352 default:
throw std::runtime_error(
"Internal error");
356 constexpr
char const *RSqliteDS::fgTypeNames[];
364 RSqliteDS::RSqliteDS(
const std::string &fileName,
const std::string &query)
365 : fDataSet(std::make_unique<Internal::RSqliteDSDataSet>()), fNSlots(0), fNRow(0)
367 static bool hasSqliteVfs = RegisterSqliteVfs();
369 throw std::runtime_error(
"Cannot register SQlite VFS in RSqliteDS");
373 retval = sqlite3_open_v2(fileName.c_str(), &fDataSet->fDb, SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX,
375 if (retval != SQLITE_OK)
378 retval = sqlite3_prepare_v2(fDataSet->fDb, query.c_str(), -1, &fDataSet->fQuery,
nullptr);
379 if (retval != SQLITE_OK)
382 int colCount = sqlite3_column_count(fDataSet->fQuery);
383 retval = sqlite3_step(fDataSet->fQuery);
384 if ((retval != SQLITE_ROW) && (retval != SQLITE_DONE))
387 fValues.reserve(colCount);
388 for (
int i = 0; i < colCount; ++i) {
389 fColumnNames.emplace_back(sqlite3_column_name(fDataSet->fQuery, i));
390 int type = SQLITE_NULL;
393 const char *declTypeCstr = sqlite3_column_decltype(fDataSet->fQuery, i);
394 if (declTypeCstr ==
nullptr) {
395 if (retval == SQLITE_ROW)
396 type = sqlite3_column_type(fDataSet->fQuery, i);
398 std::string declType(declTypeCstr);
399 std::transform(declType.begin(), declType.end(), declType.begin(), ::toupper);
400 if (declType ==
"INTEGER")
401 type = SQLITE_INTEGER;
402 else if (declType ==
"FLOAT")
404 else if (declType ==
"TEXT")
406 else if (declType ==
"BLOB")
409 throw std::runtime_error(
"Unexpected column decl type");
414 fColumnTypes.push_back(ETypes::kInteger);
415 fValues.emplace_back(ETypes::kInteger);
418 fColumnTypes.push_back(ETypes::kReal);
419 fValues.emplace_back(ETypes::kReal);
422 fColumnTypes.push_back(ETypes::kText);
423 fValues.emplace_back(ETypes::kText);
426 fColumnTypes.push_back(ETypes::kBlob);
427 fValues.emplace_back(ETypes::kBlob);
431 fColumnTypes.push_back(ETypes::kNull);
432 fValues.emplace_back(ETypes::kNull);
434 default:
throw std::runtime_error(
"Unhandled data type");
441 RSqliteDS::~RSqliteDS()
444 sqlite3_finalize(fDataSet->fQuery);
447 sqlite3_close_v2(fDataSet->fDb);
454 const std::vector<std::string> &RSqliteDS::GetColumnNames()
const
461 RDataSource::Record_t RSqliteDS::GetColumnReadersImpl(std::string_view name,
const std::type_info &ti)
463 const auto index = std::distance(fColumnNames.begin(), std::find(fColumnNames.begin(), fColumnNames.end(), name));
464 const auto type = fColumnTypes[index];
466 if ((type == ETypes::kInteger &&
typeid(Long64_t) != ti) || (type == ETypes::kReal &&
typeid(
double) != ti) ||
467 (type == ETypes::kText &&
typeid(std::string) != ti) ||
468 (type == ETypes::kBlob &&
typeid(std::vector<unsigned char>) != ti) ||
469 (type == ETypes::kNull &&
typeid(
void *) != ti)) {
470 std::string errmsg =
"The type selected for column \"";
472 errmsg +=
"\" does not correspond to column type, which is ";
473 errmsg += GetTypeName(name);
474 throw std::runtime_error(errmsg);
477 fValues[index].fIsActive =
true;
478 return std::vector<void *>{fNSlots, &fValues[index].fPtr};
484 std::vector<std::pair<ULong64_t, ULong64_t>> RSqliteDS::GetEntryRanges()
486 std::vector<std::pair<ULong64_t, ULong64_t>> entryRanges;
487 int retval = sqlite3_step(fDataSet->fQuery);
489 case SQLITE_DONE:
return entryRanges;
491 entryRanges.emplace_back(fNRow, fNRow + 1);
503 std::string RSqliteDS::GetTypeName(std::string_view colName)
const
505 unsigned N = fColumnNames.size();
507 for (
unsigned i = 0; i < N; ++i) {
508 if (colName == fColumnNames[i]) {
509 return fgTypeNames[
static_cast<int>(fColumnTypes[i])];
512 throw std::runtime_error(
"Unknown column: " + std::string(colName));
517 bool RSqliteDS::HasColumn(std::string_view colName)
const
519 return std::find(fColumnNames.begin(), fColumnNames.end(), colName) != fColumnNames.end();
524 void RSqliteDS::Initialise()
527 int retval = sqlite3_reset(fDataSet->fQuery);
528 if (retval != SQLITE_OK)
529 throw std::runtime_error(
"SQlite error, reset");
532 std::string RSqliteDS::GetLabel()
541 RDataFrame MakeSqliteDataFrame(std::string_view fileName, std::string_view query)
543 ROOT::RDataFrame rdf(std::make_unique<RSqliteDS>(std::string(fileName), std::string(query)));
549 bool RSqliteDS::SetEntry(
unsigned int , ULong64_t entry)
551 R__ASSERT(entry + 1 == fNRow);
552 unsigned N = fValues.size();
553 for (
unsigned i = 0; i < N; ++i) {
554 if (!fValues[i].fIsActive)
558 switch (fValues[i].fType) {
559 case ETypes::kInteger: fValues[i].fInteger = sqlite3_column_int64(fDataSet->fQuery, i);
break;
560 case ETypes::kReal: fValues[i].fReal = sqlite3_column_double(fDataSet->fQuery, i);
break;
562 nbytes = sqlite3_column_bytes(fDataSet->fQuery, i);
564 fValues[i].fText =
"";
566 fValues[i].fText =
reinterpret_cast<const char *
>(sqlite3_column_text(fDataSet->fQuery, i));
570 nbytes = sqlite3_column_bytes(fDataSet->fQuery, i);
571 fValues[i].fBlob.resize(nbytes);
573 std::memcpy(fValues[i].fBlob.data(), sqlite3_column_blob(fDataSet->fQuery, i), nbytes);
576 case ETypes::kNull:
break;
577 default:
throw std::runtime_error(
"Unhandled column type");
585 void RSqliteDS::SetNSlots(
unsigned int nSlots)
588 ::Warning(
"SetNSlots",
"Currently the SQlite data source faces performance degradation in multi-threaded mode. "
589 "Consider turning off IMT.");
596 void RSqliteDS::SqliteError(
int errcode)
598 std::string errmsg =
"SQlite error: ";
599 errmsg += sqlite3_errstr(errcode);
600 throw std::runtime_error(errmsg);