55constexpr char const *gSQliteVfsName =
"ROOT-Davix-readonly";
64 VfsRootFile() =
default;
67 std::unique_ptr<ROOT::Internal::RRawFile> fRawFile;
74int VfsRdOnlyClose(sqlite3_file *pFile)
76 VfsRootFile *p =
reinterpret_cast<VfsRootFile *
>(pFile);
84int 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;
93int VfsRdOnlyWrite(sqlite3_file * ,
const void * ,
int , sqlite_int64 )
95 return SQLITE_OPEN_READONLY;
100int VfsRdOnlyTruncate(sqlite3_file * , sqlite_int64 )
102 return SQLITE_OPEN_READONLY;
107int VfsRdOnlySync(sqlite3_file * ,
int )
114int VfsRdOnlyFileSize(sqlite3_file *pFile, sqlite_int64 *pSize)
116 VfsRootFile *p =
reinterpret_cast<VfsRootFile *
>(pFile);
117 *pSize = p->fRawFile->GetSize();
123int VfsRdOnlyLock(sqlite3_file * ,
int )
130int VfsRdOnlyUnlock(sqlite3_file * ,
int )
137int VfsRdOnlyCheckReservedLock(sqlite3_file * ,
int *pResOut)
145int VfsRdOnlyFileControl(sqlite3_file * ,
int ,
void * )
147 return SQLITE_NOTFOUND;
152int VfsRdOnlySectorSize(sqlite3_file * )
154 return SQLITE_OPEN_READONLY;
159int VfsRdOnlyDeviceCharacteristics(sqlite3_file * )
161 return SQLITE_OPEN_READONLY;
166int 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))
202 ::Error(
"VfsRdOnlyOpen",
"Cannot open %s\n", zName);
207 ::Error(
"VfsRdOnlyOpen",
"cannot determine file size of %s\n", zName);
211 p->pFile.pMethods = &io_methods;
221int VfsRdOnlyDelete(sqlite3_vfs * ,
const char * ,
int )
223 return SQLITE_IOERR_DELETE;
228int VfsRdOnlyAccess(sqlite3_vfs * ,
const char * ,
int flags,
int *pResOut)
231 if (flags == SQLITE_ACCESS_READWRITE) {
232 return SQLITE_OPEN_READONLY;
239int VfsRdOnlyFullPathname(sqlite3_vfs * ,
const char *zPath,
int nOut,
char *zOut)
241 zOut[nOut - 1] =
'\0';
242 sqlite3_snprintf(nOut, zOut,
"%s", zPath);
248int VfsRdOnlyRandomness(sqlite3_vfs * ,
int nBuf,
char *zBuf)
250 for (
int i = 0; i < nBuf; ++i) {
258int VfsRdOnlySleep(sqlite3_vfs * ,
int microseconds)
267int VfsRdOnlyGetLastError(sqlite3_vfs * ,
int ,
char * )
274int VfsRdOnlyCurrentTimeInt64(sqlite3_vfs * , sqlite3_int64 *piNow)
276 static constexpr sqlite3_int64 unixEpoch = 24405875 * (sqlite3_int64)8640000;
279 *piNow = ((sqlite3_int64)t) * 1000 + unixEpoch;
285int VfsRdOnlyCurrentTime(sqlite3_vfs *vfs,
double *prNow)
288 int rc = VfsRdOnlyCurrentTimeInt64(vfs, &i);
289 *prNow = i / 86400000.0;
295static struct sqlite3_vfs kSqlite3Vfs = {
305 VfsRdOnlyFullPathname,
312 VfsRdOnlyCurrentTime,
313 VfsRdOnlyGetLastError,
314 VfsRdOnlyCurrentTimeInt64,
321static bool RegisterSqliteVfs()
324 retval = sqlite3_vfs_register(&kSqlite3Vfs,
false);
325 return (retval == SQLITE_OK);
337struct RSqliteDSDataSet {
338 sqlite3 *fDb =
nullptr;
339 sqlite3_stmt *fQuery =
nullptr;
344 :
fType(
type), fIsActive(false), fInteger(0), fReal(0.0), fText(), fBlob(), fNull(nullptr)
352 default:
throw std::runtime_error(
"Internal error");
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))
388 for (
int i = 0; i < colCount; ++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)
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");
434 default:
throw std::runtime_error(
"Unhandled data type");
470 std::string errmsg =
"The type selected for column \"";
472 errmsg +=
"\" does not correspond to column type, which is ";
474 throw std::runtime_error(errmsg);
477 fValues[index].fIsActive =
true;
486 std::vector<std::pair<ULong64_t, ULong64_t>> entryRanges;
487 int retval = sqlite3_step(
fDataSet->fQuery);
489 case SQLITE_DONE:
return entryRanges;
507 for (
unsigned i = 0; i <
N; ++i) {
512 throw std::runtime_error(
"Unknown column: " + std::string(colName));
527 int retval = sqlite3_reset(
fDataSet->fQuery);
528 if (retval != SQLITE_OK)
529 throw std::runtime_error(
"SQlite error, reset");
543 ROOT::RDataFrame rdf(std::make_unique<RSqliteDS>(std::string(fileName), std::string(query)));
553 for (
unsigned i = 0; i <
N; ++i) {
562 nbytes = sqlite3_column_bytes(
fDataSet->fQuery, i);
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);
577 default:
throw std::runtime_error(
"Unhandled column type");
588 ::Warning(
"SetNSlots",
"Currently the SQlite data source faces performance degradation in multi-threaded mode. "
589 "Consider turning off IMT.");
598 std::string errmsg =
"SQlite error: ";
599 errmsg += sqlite3_errstr(errcode);
600 throw std::runtime_error(errmsg);
unsigned long long ULong64_t
void Error(const char *location, const char *msgfmt,...)
void Warning(const char *location, const char *msgfmt,...)
R__EXTERN TRandom * gRandom
R__EXTERN TSystem * gSystem
static std::unique_ptr< RRawFile > Create(std::string_view url, ROptions options=ROptions())
Factory method that returns a suitable concrete implementation according to the transport in the url.
static constexpr int kFeatureHasSize
GetSize() does not return kUnknownFileSize.
std::vector< void * > Record_t
void SetNSlots(unsigned int nSlots) final
Almost a no-op, many slots can in fact reduce the performance due to thread synchronization.
static constexpr char const * fgTypeNames[]
Corresponds to the types defined in ETypes.
std::string GetLabel() final
Return a string representation of the datasource type.
void Initialise() final
Resets the SQlite query engine at the beginning of the event loop.
std::vector< std::string > fColumnNames
~RSqliteDS()
Frees the sqlite resources and closes the file.
bool HasColumn(std::string_view colName) const final
A linear search through the columns for the given name.
std::vector< ETypes > fColumnTypes
std::string GetTypeName(std::string_view colName) const final
Returns the C++ type for a given column name, implemented as a linear search through all the columns.
ETypes
All the types known to SQlite. Changes require changing fgTypeNames, too.
Record_t GetColumnReadersImpl(std::string_view name, const std::type_info &) final
Activates the given column's result value.
RSqliteDS(const std::string &fileName, const std::string &query)
Build the dataframe.
std::unique_ptr< Internal::RSqliteDSDataSet > fDataSet
std::vector< std::pair< ULong64_t, ULong64_t > > GetEntryRanges() final
Returns a range of size 1 as long as more rows are available in the SQL result set.
const std::vector< std::string > & GetColumnNames() const final
Returns the SELECT queries names.
bool SetEntry(unsigned int slot, ULong64_t entry) final
Stores the result of the current active sqlite query row as a C++ value.
void SqliteError(int errcode)
Helper function to throw an exception if there is a fatal sqlite error, e.g. an I/O error.
std::vector< Value_t > fValues
The data source is inherently single-threaded and returns only one row at a time. This vector holds t...
ROOT's RDataFrame offers a high level interface for analyses of data stored in TTrees,...
virtual UInt_t Integer(UInt_t imax)
Returns a random integer uniformly distributed on the interval [ 0, imax-1 ].
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
basic_string_view< char > string_view
RDataFrame MakeSqliteDataFrame(std::string_view fileName, std::string_view query)
Factory method to create a SQlite RDataFrame.
void * fPtr
Points to one of the values; an address to this pointer is returned by GetColumnReadersImpl.
std::vector< unsigned char > fBlob