Reprocess: added -track_changes option. Added rtabmap-dpupdate.

This commit is contained in:
matlabbe
2026-07-10 19:39:22 -07:00
parent e321999b15
commit 15109dfa9e
19 changed files with 179202 additions and 47017 deletions

View File

@@ -196,6 +196,16 @@ IF(SQLite3_FOUND)
${LIBRARIES}
${SQLite3_LIBRARIES}
)
# The SQLite session extension (used to track DB diffs) needs SQLite >= 3.13.0.
# Defining SQLITE_ENABLE_SESSION here only exposes the session declarations in the
# system sqlite3.h; whether the linked library was actually built with the extension
# is verified at runtime with sqlite3_compileoption_used("ENABLE_SESSION").
IF(SQLite3_VERSION VERSION_GREATER_EQUAL "3.13.0")
SET(SQLITE3_SESSION_DEFINITIONS SQLITE_ENABLE_SESSION SQLITE_ENABLE_PREUPDATE_HOOK RTABMAP_WITH_SQLITE3_SESSION)
MESSAGE(STATUS " With SQLite3 session ext = YES (system SQLite3 ${SQLite3_VERSION}, verified at runtime)")
ELSE()
MESSAGE(STATUS " With SQLite3 session ext = NO (system SQLite3 ${SQLite3_VERSION} < 3.13.0)")
ENDIF()
ELSE()
SET(SRC_FILES
${SRC_FILES}
@@ -205,6 +215,9 @@ ELSE()
${CMAKE_CURRENT_SOURCE_DIR}/sqlite3
${INCLUDE_DIRS}
)
# We compile the bundled amalgamation ourselves, so enable the session extension in it.
SET(SQLITE3_SESSION_DEFINITIONS SQLITE_ENABLE_SESSION SQLITE_ENABLE_PREUPDATE_HOOK RTABMAP_WITH_SQLITE3_SESSION)
MESSAGE(STATUS " With SQLite3 session ext = YES (bundled SQLite3)")
ENDIF()
IF(TORCH_FOUND)
@@ -830,6 +843,7 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql.in ${CMA
SET(RESOURCES
${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_23_0.sql
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_22_0.sql
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_20_0.sql
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_18_3.sql
@@ -886,13 +900,20 @@ target_include_directories(rtabmap_core SYSTEM PUBLIC
"$<BUILD_INTERFACE:${PUBLIC_INCLUDE_DIRS};${INCLUDE_DIRS}>"
"$<INSTALL_INTERFACE:${PUBLIC_INCLUDE_DIRS}>")
TARGET_LINK_LIBRARIES(rtabmap_core
PUBLIC
rtabmap_utilite
TARGET_LINK_LIBRARIES(rtabmap_core
PUBLIC
rtabmap_utilite
${PUBLIC_LIBRARIES}
PRIVATE
PRIVATE
${LIBRARIES})
# Enable the SQLite session extension for the core sources (bundled sqlite3.c and
# DBDriverSqlite3.cpp). Kept PRIVATE so it only affects rtabmap_core's own TUs and
# never changes the public header layout for downstream consumers.
IF(SQLITE3_SESSION_DEFINITIONS)
target_compile_definitions(rtabmap_core PRIVATE ${SQLITE3_SESSION_DEFINITIONS})
ENDIF()
SET_TARGET_PROPERTIES(
rtabmap_core
PROPERTIES

View File

@@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/util3d.h"
#include "rtabmap/core/Compression.h"
#include "DatabaseSchema_sql.h"
#include "DatabaseSchema_0_23_0_sql.h"
#include "DatabaseSchema_0_22_0_sql.h"
#include "DatabaseSchema_0_20_0_sql.h"
#include "DatabaseSchema_0_18_3_sql.h"
@@ -45,6 +46,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <set>
#include <cstdio>
#include "rtabmap/utilite/UtiLite.h"
@@ -59,7 +61,8 @@ DBDriverSqlite3::DBDriverSqlite3(const ParametersMap & parameters) :
_cacheSize(Parameters::defaultDbSqlite3CacheSize()),
_journalMode(Parameters::defaultDbSqlite3JournalMode()),
_synchronous(Parameters::defaultDbSqlite3Synchronous()),
_tempStore(Parameters::defaultDbSqlite3TempStore())
_tempStore(Parameters::defaultDbSqlite3TempStore()),
_session(0)
{
ULOGGER_DEBUG("treadSafe=%d", sqlite3_threadsafe());
this->parseParameters(parameters);
@@ -218,6 +221,149 @@ void DBDriverSqlite3::setDbInMemory(bool dbInMemory)
}
}
void DBDriverSqlite3::startChangeTracking()
{
#ifdef RTABMAP_WITH_SQLITE3_SESSION
if(_session != 0 || _trackChangesOutput.empty() || _ppDb == 0)
{
// Already tracking, nothing requested, or not connected yet.
return;
}
if(uStrNumCmp(_version, "0.24.0") < 0)
{
UWARN("Database change tracking to \"%s\" was requested but the database "
"version is %s (< 0.24.0). Older schemas lack the primary keys required "
"by the SQLite session extension, so change tracking is disabled.",
_trackChangesOutput.c_str(), _version.c_str());
}
else if(!sqlite3_compileoption_used("ENABLE_SESSION"))
{
UWARN("Database change tracking to \"%s\" was requested but the linked SQLite "
"library was not built with the session extension (ENABLE_SESSION); "
"change tracking is disabled.", _trackChangesOutput.c_str());
}
else if(sqlite3session_create(_ppDb, "main", &_session) == SQLITE_OK)
{
sqlite3session_attach(_session, 0); // 0 = track all tables
UINFO("Tracking database changes; a patchset will be written to \"%s\" on close.",
_trackChangesOutput.c_str());
}
else
{
UWARN("Could not create a SQLite session to track database changes to \"%s\".",
_trackChangesOutput.c_str());
_session = 0;
}
#endif
}
bool DBDriverSqlite3::trackDatabaseChanges(const std::string & outputUrl)
{
UDEBUG("outputUrl=%s", outputUrl.c_str());
_trackChangesOutput = outputUrl;
#ifdef RTABMAP_WITH_SQLITE3_SESSION
// If the connection is already open (e.g. set after connect(), as rtabmap-reprocess
// does after init()), start tracking now on the current baseline state. Otherwise it
// will start automatically when the connection is opened.
if(!outputUrl.empty() && _ppDb != 0)
{
this->startChangeTracking();
}
return _session != 0;
#else
if(!outputUrl.empty())
{
UWARN("Database change tracking to \"%s\" was requested but rtabmap was built "
"against a SQLite library without the session extension; it is disabled.",
outputUrl.c_str());
}
return false;
#endif
}
#ifdef RTABMAP_WITH_SQLITE3_SESSION
static int rtabmapChangesetConflict(void * pCtx, int eConflict, sqlite3_changeset_iter * pIter)
{
// A patchset upgrade must apply cleanly onto the exact database it was generated from.
// Any conflict means the wrong base database (or an already-applied delta), so abort
// rather than silently produce an inconsistent result.
return SQLITE_CHANGESET_ABORT;
}
#endif
bool DBDriverSqlite3::applyChangesFromFile(
const std::string & databasePath,
const std::string & patchsetPath,
std::string * errorMsg)
{
#ifdef RTABMAP_WITH_SQLITE3_SESSION
if(!sqlite3_compileoption_used("ENABLE_SESSION"))
{
if(errorMsg) *errorMsg = "The linked SQLite library was not built with the session extension.";
return false;
}
// Read the compressed patchset file.
FILE * fp = fopen(patchsetPath.c_str(), "rb");
if(!fp)
{
if(errorMsg) *errorMsg = uFormat("Could not open patchset file \"%s\".", patchsetPath.c_str());
return false;
}
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(fileSize <= 0)
{
fclose(fp);
if(errorMsg) *errorMsg = uFormat("Patchset file \"%s\" is empty or unreadable.", patchsetPath.c_str());
return false;
}
std::vector<unsigned char> fileBytes((size_t)fileSize);
size_t bytesRead = fread(fileBytes.data(), 1, (size_t)fileSize, fp);
fclose(fp);
if((long)bytesRead != fileSize)
{
if(errorMsg) *errorMsg = uFormat("Could not read patchset file \"%s\".", patchsetPath.c_str());
return false;
}
// Decompress to the raw patchset (same codec used to write it).
cv::Mat patch = uncompressData(fileBytes.data(), (unsigned long)fileSize);
if(patch.empty())
{
if(errorMsg) *errorMsg = uFormat("Could not decompress patchset file \"%s\".", patchsetPath.c_str());
return false;
}
// Apply onto the target database.
sqlite3 * db = 0;
int rc = sqlite3_open_v2(databasePath.c_str(), &db, SQLITE_OPEN_READWRITE, 0);
if(rc != SQLITE_OK)
{
if(errorMsg) *errorMsg = uFormat("Could not open database \"%s\": %s", databasePath.c_str(), sqlite3_errmsg(db));
sqlite3_close(db);
return false;
}
int nPatch = (int)(patch.total()*patch.elemSize());
rc = sqlite3changeset_apply(db, nPatch, patch.data, 0, rtabmapChangesetConflict, 0);
if(rc != SQLITE_OK)
{
if(errorMsg) *errorMsg = uFormat("Failed to apply patchset to \"%s\" (SQLite error %d: %s). Make "
"sure it is applied to the exact database state the delta was generated from.",
databasePath.c_str(), rc, sqlite3_errstr(rc));
sqlite3_close(db);
return false;
}
sqlite3_close(db);
return true;
#else
if(errorMsg) *errorMsg = "rtabmap was built without SQLite session support.";
return false;
#endif
}
/*
** This function is used to load the contents of a database file on disk
** into the "main" database of open database connection pInMemory, or
@@ -406,6 +552,7 @@ bool DBDriverSqlite3::connectDatabaseQuery(const std::string & url, bool overwri
schemas.push_back(std::make_pair("0.18.3", DATABASESCHEMA_0_18_3_SQL));
schemas.push_back(std::make_pair("0.20.0", DATABASESCHEMA_0_20_0_SQL));
schemas.push_back(std::make_pair("0.22.0", DATABASESCHEMA_0_22_0_SQL));
schemas.push_back(std::make_pair("0.23.0", DATABASESCHEMA_0_23_0_SQL));
schemas.push_back(std::make_pair(uNumber2Str(RTABMAP_VERSION_MAJOR)+"."+uNumber2Str(RTABMAP_VERSION_MINOR), DATABASESCHEMA_SQL));
for(size_t i=0; i<schemas.size(); ++i)
{
@@ -446,6 +593,14 @@ bool DBDriverSqlite3::connectDatabaseQuery(const std::string & url, bool overwri
this->setSynchronous(_synchronous); // this will call the SQL
this->setTempStore(_tempStore); // this will call the SQL
// Start tracking database changes if a recording path was already set (before the
// connection was opened). Done here, after any initial load and once the version is
// known, so the delta reflects only the changes made between open and close.
if(!readOnly)
{
this->startChangeTracking();
}
return true;
}
void DBDriverSqlite3::disconnectDatabaseQuery(bool save, const std::string & outputUrl)
@@ -489,6 +644,56 @@ void DBDriverSqlite3::disconnectDatabaseQuery(bool save, const std::string & out
}
}
#ifdef RTABMAP_WITH_SQLITE3_SESSION
// If change tracking is active, emit the accumulated patchset before closing.
if(_session)
{
int nBuf = 0;
void * pBuf = 0;
int rcp = sqlite3session_patchset(_session, &nBuf, &pBuf);
if(rcp == SQLITE_OK && pBuf && nBuf > 0)
{
// Compress the patchset with the same zlib-based codec used for every other
// rtabmap blob, so the delta is compact for transfer. To apply it later,
// uncompressData() the file and pass the bytes to sqlite3changeset_apply().
cv::Mat compressed = compressData2(cv::Mat(1, nBuf, CV_8UC1, pBuf));
FILE * fp = fopen(_trackChangesOutput.c_str(), "wb");
if(fp)
{
size_t toWrite = compressed.total()*compressed.elemSize();
size_t written = fwrite(compressed.data, 1, toWrite, fp);
fclose(fp);
if(written == toWrite)
{
UINFO("Wrote compressed database patchset (%d -> %d bytes) to \"%s\".",
nBuf, (int)toWrite, _trackChangesOutput.c_str());
}
else
{
UERROR("Could only write %d/%d bytes of the database patchset to \"%s\".",
(int)written, (int)toWrite, _trackChangesOutput.c_str());
}
}
else
{
UERROR("Could not open \"%s\" to write the database patchset.", _trackChangesOutput.c_str());
}
}
else if(rcp != SQLITE_OK)
{
UERROR("Could not generate the database patchset for \"%s\" (SQLite error %d).",
_trackChangesOutput.c_str(), rcp);
}
else
{
UINFO("No database changes to write; \"%s\" was not created.", _trackChangesOutput.c_str());
}
sqlite3_free(pBuf);
sqlite3session_delete(_session);
_session = 0;
}
#endif
// Then close (delete) the database connection
UINFO("Disconnecting database %s...", this->getUrl().c_str());
sqlite3_close(_ppDb);

View File

@@ -1994,6 +1994,11 @@ double Memory::getDbSavingTime() const
return _dbDriver?_dbDriver->getEmptyTrashesTime():0;
}
bool Memory::trackDatabaseChanges(const std::string & outputUrl)
{
return _dbDriver?_dbDriver->trackDatabaseChanges(outputUrl):false;
}
std::set<int> Memory::getAllSignatureIds(bool ignoreChildren) const
{
std::set<int> ids;

View File

@@ -885,6 +885,11 @@ Transform Rtabmap::getPose(int locationId) const
return uValue(_optimizedPoses, locationId, Transform());
}
bool Rtabmap::trackDatabaseChanges(const std::string & outputUrl)
{
return _memory?_memory->trackDatabaseChanges(outputUrl):false;
}
void Rtabmap::setInitialPose(const Transform & initialPose)
{
if(_memory)

View File

@@ -52,6 +52,7 @@ CREATE TABLE Data (
);
CREATE TABLE Link (
id INTEGER PRIMARY KEY, -- required by the SQLite session extension (DB diff tracking); (from_id,to_id) is not unique (a node pair can have several links)
from_id INTEGER NOT NULL,
to_id INTEGER NOT NULL,
type INTEGER NOT NULL, -- kNeighbor=0, kGlobalClosure=1, kLocalSpaceClosure=2, kLocalTimeClosure=3, kUserClosure=4, kVirtualClosure=5, kNeighborMerged=6, kPosePrior=7, kLandmark=8
@@ -72,6 +73,7 @@ CREATE TABLE Word (
);
CREATE TABLE Feature (
id INTEGER PRIMARY KEY, -- required by the SQLite session extension (DB diff tracking)
node_id INTEGER NOT NULL,
word_id INTEGER NOT NULL,
pos_x FLOAT NOT NULL,
@@ -89,6 +91,7 @@ CREATE TABLE Feature (
);
CREATE TABLE GlobalDescriptor (
id INTEGER PRIMARY KEY, -- required by the SQLite session extension (DB diff tracking)
node_id INTEGER NOT NULL,
type INTEGER NOT NULL,
info BLOB,
@@ -99,6 +102,7 @@ CREATE TABLE GlobalDescriptor (
--
CREATE TABLE Info (
id INTEGER PRIMARY KEY, -- required by the SQLite session extension (DB diff tracking)
STM_size INTEGER,
last_sign_added INTEGER,
process_mem_used INTEGER,
@@ -113,11 +117,12 @@ CREATE TABLE Statistics (
stamp FLOAT,
data BLOB, -- compressed string
wm_state BLOB, -- compressed data
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Node(id)
);
CREATE TABLE Admin (
version TEXT,
version TEXT PRIMARY KEY,
preview_image BLOB, -- compressed image
opt_cloud BLOB, -- compressed data
@@ -176,7 +181,6 @@ CREATE INDEX IDX_Feature_node_id on Feature (node_id);
CREATE INDEX IDX_GlobalDescriptor_node_id on GlobalDescriptor (node_id);
CREATE INDEX IDX_Link_from_id on Link (from_id);
CREATE UNIQUE INDEX IDX_node_label on Node (label);
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
-- *******************************************************************
-- VERSION

View File

@@ -0,0 +1,184 @@
-- *******************************************************************
-- DatabaseSchema: Script for creating the database
-- Usage:
-- $ sqlite3 LTM.db < DatabaseSchema.sql
--
-- *******************************************************************
-- *******************************************************************
-- CLEAN
-- *******************************************************************
/*DROP TABLE Node;*/
-- *******************************************************************
-- CREATE
-- *******************************************************************
CREATE TABLE Node (
id INTEGER NOT NULL,
map_id INTEGER NOT NULL,
weight INTEGER,
stamp FLOAT,
pose BLOB, -- 3x4 float
ground_truth_pose BLOB, -- 3x4 float
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
label TEXT,
gps BLOB, -- 1x6 double: stamp, longitude (DD), latitude (DD), altitude (m), accuracy (m), bearing (North 0->360 deg clockwise)
env_sensors BLOB, -- Variable 3xdouble: (sensorId1, value, stamp, sensorId2, value, stamp, ...)
time_enter DATE,
PRIMARY KEY (id)
);
CREATE TABLE Data (
id INTEGER NOT NULL,
image BLOB, -- compressed image (Grayscale or RGB)
depth BLOB, -- compressed image (Depth or Right image)
depth_confidence BLOB, -- compressed data (low=0 high=100)
calibration BLOB, -- fx, fy, cx, cy, [baseline,] width, height, local_transform
scan BLOB, -- compressed data (Laser scan)
scan_info BLOB, -- scan_max_pts, scan_max_range, scan_format, local_transform
ground_cells BLOB, -- compressed data (occupancy grid)
obstacle_cells BLOB, -- compressed data (occupancy grid)
empty_cells BLOB, -- compressed data (occupancy grid)
cell_size FLOAT,
view_point_x FLOAT,
view_point_y FLOAT,
view_point_z FLOAT,
user_data BLOB, -- compressed data (User data)
time_enter DATE,
PRIMARY KEY (id)
);
CREATE TABLE Link (
from_id INTEGER NOT NULL,
to_id INTEGER NOT NULL,
type INTEGER NOT NULL, -- kNeighbor=0, kGlobalClosure=1, kLocalSpaceClosure=2, kLocalTimeClosure=3, kUserClosure=4, kVirtualClosure=5, kNeighborMerged=6, kPosePrior=7, kLandmark=8
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
transform BLOB, -- 3x4 float
user_data BLOB, -- compressed data (User data)
FOREIGN KEY (from_id) REFERENCES Node(id),
FOREIGN KEY (to_id) REFERENCES Node(id)
);
--
CREATE TABLE Word (
id INTEGER NOT NULL,
descriptor_size INTEGER NOT NULL,
descriptor BLOB NOT NULL,
time_enter DATE,
PRIMARY KEY (id)
);
CREATE TABLE Feature (
node_id INTEGER NOT NULL,
word_id INTEGER NOT NULL,
pos_x FLOAT NOT NULL,
pos_y FLOAT NOT NULL,
size INTEGER NOT NULL,
dir FLOAT NOT NULL,
response FLOAT NOT NULL,
octave INTEGER NOT NULL,
depth_x FLOAT,
depth_y FLOAT,
depth_z FLOAT,
descriptor_size INTEGER,
descriptor BLOB,
FOREIGN KEY (node_id) REFERENCES Node(id)
);
CREATE TABLE GlobalDescriptor (
node_id INTEGER NOT NULL,
type INTEGER NOT NULL,
info BLOB,
data BLOB NOT NULL,
FOREIGN KEY (node_id) REFERENCES Node(id)
);
--
CREATE TABLE Info (
STM_size INTEGER,
last_sign_added INTEGER,
process_mem_used INTEGER,
database_mem_used INTEGER,
dictionary_size INTEGER,
parameters TEXT,
time_enter DATE
);
CREATE TABLE Statistics (
id INTEGER NOT NULL,
stamp FLOAT,
data BLOB, -- compressed string
wm_state BLOB, -- compressed data
FOREIGN KEY (id) REFERENCES Node(id)
);
CREATE TABLE Admin (
version TEXT,
preview_image BLOB, -- compressed image
opt_cloud BLOB, -- compressed data
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
opt_poses BLOB, -- compressed N*3x4 float
opt_last_localization BLOB, -- 3x4 float
opt_polygons_size INTEGER, -- e.g., 3
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
opt_tex_materials BLOB, -- compressed image
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
opt_map_x_min FLOAT,
opt_map_y_min FLOAT,
opt_map_resolution FLOAT,
dictionary_index BLOB, -- serialized dictionary index
time_enter DATE
);
-- *******************************************************************
-- TRIGGERS
-- *******************************************************************
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
BEGIN
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
END;
-- Creating a trigger for time_enter
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
BEGIN
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
CREATE TRIGGER insert_Data_timeEnter AFTER INSERT ON Data
BEGIN
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
BEGIN
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
BEGIN
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
END;
-- *******************************************************************
-- INDEXES
-- *******************************************************************
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
CREATE INDEX IDX_GlobalDescriptor_node_id on GlobalDescriptor (node_id);
CREATE INDEX IDX_Link_from_id on Link (from_id);
CREATE UNIQUE INDEX IDX_node_label on Node (label);
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
-- *******************************************************************
-- VERSION
-- *******************************************************************
INSERT INTO Admin(version) VALUES('0.23.0');

View File

@@ -1,3 +1,3 @@
Version 3.53.3
Info: https://www.sqlite.org/
License: Public domain (https://www.sqlite.org/copyright.html)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,12 +15,10 @@
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
#ifndef SQLITE3EXT_H
#define SQLITE3EXT_H
#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
/*
** The following structure holds pointers to all of the SQLite API
** routines.
@@ -28,7 +26,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
** WARNING: In order to maintain backwards compatibility, add new
** interfaces to the end of this structure only. If you insert new
** interfaces in the middle of this structure, then older different
** versions of SQLite will not be able to load each others' shared
** versions of SQLite will not be able to load each other's shared
** libraries!
*/
struct sqlite3_api_routines {
@@ -136,7 +134,7 @@ struct sqlite3_api_routines {
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
char * (*xsnprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
@@ -248,13 +246,151 @@ struct sqlite3_api_routines {
int (*uri_boolean)(const char*,const char*,int);
sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64);
const char *(*uri_parameter)(const char*,const char*);
char *(*vsnprintf)(int,char*,const char*,va_list);
char *(*xvsnprintf)(int,char*,const char*,va_list);
int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*);
/* Version 3.8.7 and later */
int (*auto_extension)(void(*)(void));
int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64,
void(*)(void*));
int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64,
void(*)(void*),unsigned char);
int (*cancel_auto_extension)(void(*)(void));
int (*load_extension)(sqlite3*,const char*,const char*,char**);
void *(*malloc64)(sqlite3_uint64);
sqlite3_uint64 (*msize)(void*);
void *(*realloc64)(void*,sqlite3_uint64);
void (*reset_auto_extension)(void);
void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64,
void(*)(void*));
void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64,
void(*)(void*), unsigned char);
int (*strglob)(const char*,const char*);
/* Version 3.8.11 and later */
sqlite3_value *(*value_dup)(const sqlite3_value*);
void (*value_free)(sqlite3_value*);
int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64);
int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64);
/* Version 3.9.0 and later */
unsigned int (*value_subtype)(sqlite3_value*);
void (*result_subtype)(sqlite3_context*,unsigned int);
/* Version 3.10.0 and later */
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
/* Version 3.14.0 and later */
int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
char *(*expanded_sql)(sqlite3_stmt*);
/* Version 3.18.0 and later */
void (*set_last_insert_rowid)(sqlite3*,sqlite3_int64);
/* Version 3.20.0 and later */
int (*prepare_v3)(sqlite3*,const char*,int,unsigned int,
sqlite3_stmt**,const char**);
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
sqlite3_stmt**,const void**);
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
void *(*value_pointer)(sqlite3_value*,const char*);
int (*vtab_nochange)(sqlite3_context*);
int (*value_nochange)(sqlite3_value*);
const char *(*vtab_collation)(sqlite3_index_info*,int);
/* Version 3.24.0 and later */
int (*keyword_count)(void);
int (*keyword_name)(int,const char**,int*);
int (*keyword_check)(const char*,int);
sqlite3_str *(*str_new)(sqlite3*);
char *(*str_finish)(sqlite3_str*);
void (*str_appendf)(sqlite3_str*, const char *zFormat, ...);
void (*str_vappendf)(sqlite3_str*, const char *zFormat, va_list);
void (*str_append)(sqlite3_str*, const char *zIn, int N);
void (*str_appendall)(sqlite3_str*, const char *zIn);
void (*str_appendchar)(sqlite3_str*, int N, char C);
void (*str_reset)(sqlite3_str*);
int (*str_errcode)(sqlite3_str*);
int (*str_length)(sqlite3_str*);
char *(*str_value)(sqlite3_str*);
/* Version 3.25.0 and later */
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void (*xValue)(sqlite3_context*),
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
void(*xDestroy)(void*));
/* Version 3.26.0 and later */
const char *(*normalized_sql)(sqlite3_stmt*);
/* Version 3.28.0 and later */
int (*stmt_isexplain)(sqlite3_stmt*);
int (*value_frombind)(sqlite3_value*);
/* Version 3.30.0 and later */
int (*drop_modules)(sqlite3*,const char**);
/* Version 3.31.0 and later */
sqlite3_int64 (*hard_heap_limit64)(sqlite3_int64);
const char *(*uri_key)(const char*,int);
const char *(*filename_database)(const char*);
const char *(*filename_journal)(const char*);
const char *(*filename_wal)(const char*);
/* Version 3.32.0 and later */
const char *(*create_filename)(const char*,const char*,const char*,
int,const char**);
void (*free_filename)(const char*);
sqlite3_file *(*database_file_object)(const char*);
/* Version 3.34.0 and later */
int (*txn_state)(sqlite3*,const char*);
/* Version 3.36.1 and later */
sqlite3_int64 (*changes64)(sqlite3*);
sqlite3_int64 (*total_changes64)(sqlite3*);
/* Version 3.37.0 and later */
int (*autovacuum_pages)(sqlite3*,
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
void*, void(*)(void*));
/* Version 3.38.0 and later */
int (*error_offset)(sqlite3*);
int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
int (*vtab_distinct)(sqlite3_index_info*);
int (*vtab_in)(sqlite3_index_info*,int,int);
int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
/* Version 3.39.0 and later */
int (*deserialize)(sqlite3*,const char*,unsigned char*,
sqlite3_int64,sqlite3_int64,unsigned);
unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
unsigned int);
const char *(*db_name)(sqlite3*,int);
/* Version 3.40.0 and later */
int (*value_encoding)(sqlite3_value*);
/* Version 3.41.0 and later */
int (*is_interrupted)(sqlite3*);
/* Version 3.43.0 and later */
int (*stmt_explain)(sqlite3_stmt*,int);
/* Version 3.44.0 and later */
void *(*get_clientdata)(sqlite3*,const char*);
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
/* Version 3.50.0 and later */
int (*setlk_timeout)(sqlite3*,int,int);
/* Version 3.51.0 and later */
int (*set_errmsg)(sqlite3*,int,const char*);
int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
/* Version 3.52.0 and later */
void (*str_truncate)(sqlite3_str*,int);
void (*str_free)(sqlite3_str*);
int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*));
int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*);
};
/*
** This is the function signature used for all extension entry points. It
** is also defined in the file "loadext.c".
*/
typedef int (*sqlite3_loadext_entry)(
sqlite3 *db, /* Handle to the database. */
char **pzErrMsg, /* Used to set error string on failure. */
const sqlite3_api_routines *pThunk /* Extension API function pointers. */
);
/*
** The following macros redefine the API routines so that they are
** redirected throught the global sqlite3_api structure.
** redirected through the global sqlite3_api structure.
**
** This header file is also used by the loadext.c source file
** (part of the main SQLite library - not an extension) so that
@@ -263,7 +399,7 @@ struct sqlite3_api_routines {
** the API. So the redefinition macros are only valid if the
** SQLITE_CORE macros is undefined.
*/
#ifndef SQLITE_CORE
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
#ifndef SQLITE_OMIT_DEPRECATED
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
@@ -366,7 +502,7 @@ struct sqlite3_api_routines {
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
#define sqlite3_snprintf sqlite3_api->snprintf
#define sqlite3_snprintf sqlite3_api->xsnprintf
#define sqlite3_step sqlite3_api->step
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
@@ -390,6 +526,7 @@ struct sqlite3_api_routines {
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
#define sqlite3_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_overload_function sqlite3_api->overload_function
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
@@ -465,11 +602,126 @@ struct sqlite3_api_routines {
#define sqlite3_uri_boolean sqlite3_api->uri_boolean
#define sqlite3_uri_int64 sqlite3_api->uri_int64
#define sqlite3_uri_parameter sqlite3_api->uri_parameter
#define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf
#define sqlite3_uri_vsnprintf sqlite3_api->xvsnprintf
#define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2
#endif /* SQLITE_CORE */
/* Version 3.8.7 and later */
#define sqlite3_auto_extension sqlite3_api->auto_extension
#define sqlite3_bind_blob64 sqlite3_api->bind_blob64
#define sqlite3_bind_text64 sqlite3_api->bind_text64
#define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension
#define sqlite3_load_extension sqlite3_api->load_extension
#define sqlite3_malloc64 sqlite3_api->malloc64
#define sqlite3_msize sqlite3_api->msize
#define sqlite3_realloc64 sqlite3_api->realloc64
#define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension
#define sqlite3_result_blob64 sqlite3_api->result_blob64
#define sqlite3_result_text64 sqlite3_api->result_text64
#define sqlite3_strglob sqlite3_api->strglob
/* Version 3.8.11 and later */
#define sqlite3_value_dup sqlite3_api->value_dup
#define sqlite3_value_free sqlite3_api->value_free
#define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64
#define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64
/* Version 3.9.0 and later */
#define sqlite3_value_subtype sqlite3_api->value_subtype
#define sqlite3_result_subtype sqlite3_api->result_subtype
/* Version 3.10.0 and later */
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
/* Version 3.14.0 and later */
#define sqlite3_trace_v2 sqlite3_api->trace_v2
#define sqlite3_expanded_sql sqlite3_api->expanded_sql
/* Version 3.18.0 and later */
#define sqlite3_set_last_insert_rowid sqlite3_api->set_last_insert_rowid
/* Version 3.20.0 and later */
#define sqlite3_prepare_v3 sqlite3_api->prepare_v3
#define sqlite3_prepare16_v3 sqlite3_api->prepare16_v3
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
#define sqlite3_result_pointer sqlite3_api->result_pointer
#define sqlite3_value_pointer sqlite3_api->value_pointer
/* Version 3.22.0 and later */
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
#define sqlite3_value_nochange sqlite3_api->value_nochange
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
/* Version 3.24.0 and later */
#define sqlite3_keyword_count sqlite3_api->keyword_count
#define sqlite3_keyword_name sqlite3_api->keyword_name
#define sqlite3_keyword_check sqlite3_api->keyword_check
#define sqlite3_str_new sqlite3_api->str_new
#define sqlite3_str_finish sqlite3_api->str_finish
#define sqlite3_str_appendf sqlite3_api->str_appendf
#define sqlite3_str_vappendf sqlite3_api->str_vappendf
#define sqlite3_str_append sqlite3_api->str_append
#define sqlite3_str_appendall sqlite3_api->str_appendall
#define sqlite3_str_appendchar sqlite3_api->str_appendchar
#define sqlite3_str_reset sqlite3_api->str_reset
#define sqlite3_str_errcode sqlite3_api->str_errcode
#define sqlite3_str_length sqlite3_api->str_length
#define sqlite3_str_value sqlite3_api->str_value
/* Version 3.25.0 and later */
#define sqlite3_create_window_function sqlite3_api->create_window_function
/* Version 3.26.0 and later */
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
/* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain sqlite3_api->stmt_isexplain
#define sqlite3_value_frombind sqlite3_api->value_frombind
/* Version 3.30.0 and later */
#define sqlite3_drop_modules sqlite3_api->drop_modules
/* Version 3.31.0 and later */
#define sqlite3_hard_heap_limit64 sqlite3_api->hard_heap_limit64
#define sqlite3_uri_key sqlite3_api->uri_key
#define sqlite3_filename_database sqlite3_api->filename_database
#define sqlite3_filename_journal sqlite3_api->filename_journal
#define sqlite3_filename_wal sqlite3_api->filename_wal
/* Version 3.32.0 and later */
#define sqlite3_create_filename sqlite3_api->create_filename
#define sqlite3_free_filename sqlite3_api->free_filename
#define sqlite3_database_file_object sqlite3_api->database_file_object
/* Version 3.34.0 and later */
#define sqlite3_txn_state sqlite3_api->txn_state
/* Version 3.36.1 and later */
#define sqlite3_changes64 sqlite3_api->changes64
#define sqlite3_total_changes64 sqlite3_api->total_changes64
/* Version 3.37.0 and later */
#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
/* Version 3.38.0 and later */
#define sqlite3_error_offset sqlite3_api->error_offset
#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
#define sqlite3_vtab_in sqlite3_api->vtab_in
#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
/* Version 3.39.0 and later */
#ifndef SQLITE_OMIT_DESERIALIZE
#define sqlite3_deserialize sqlite3_api->deserialize
#define sqlite3_serialize sqlite3_api->serialize
#endif
#define sqlite3_db_name sqlite3_api->db_name
/* Version 3.40.0 and later */
#define sqlite3_value_encoding sqlite3_api->value_encoding
/* Version 3.41.0 and later */
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
/* Version 3.43.0 and later */
#define sqlite3_stmt_explain sqlite3_api->stmt_explain
/* Version 3.44.0 and later */
#define sqlite3_get_clientdata sqlite3_api->get_clientdata
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
/* Version 3.50.0 and later */
#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
/* Version 3.51.0 and later */
#define sqlite3_set_errmsg sqlite3_api->set_errmsg
#define sqlite3_db_status64 sqlite3_api->db_status64
/* Version 3.52.0 and later */
#define sqlite3_str_truncate sqlite3_api->str_truncate
#define sqlite3_str_free sqlite3_api->str_free
#define sqlite3_carray_bind sqlite3_api->carray_bind
#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#ifndef SQLITE_CORE
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
/* This case when the file really is being compiled as a loadable
** extension */
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
@@ -484,4 +736,4 @@ struct sqlite3_api_routines {
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
#endif /* _SQLITE3EXT_H_ */
#endif /* SQLITE3EXT_H */