On Mon, Apr 22, 2013 at 7:39 AM, Paolo Bolzoni <
paolo.bolzoni.br...@gmail.com> wrote:

> I noticed that sqlite3_blob_write cannot increase the size of the pointed
> open blob. So I ask, there is a way to treat a blob as a stream so I can
> write
> or read values in it with ease?
>

Short answer:  No.

SQLite packs information tightly together to conserve space in the database
file.  So if you have a row with 5 columns, A through E, then the content
of those 5 columns are immediately adjacent to each other.  If you increase
the size of the blob in column C, then content of columns D and E have to
be moved out of the way.  Similarly, multiple rows are packed tightly
together, so if you increase the size of the blob in column E, than means
subsequent rows have to be moved out of the way, or else the entire row
being changed has to be rewritten into a different spot in the file.

Going even further into the weeds: even if you happen to have some free
space in file after the current row and the blob is the last column in the
row, due to some encoding decisions that were made way back in 2004, we
cannot increase the size of a row without rewriting the entire row.  To do
otherwise would result in an incompatible file format.

So, no, you cannot arbitrarily increase the size of a BLOB using
sqlite3_blob_write().  However, as Roger mentioned, you can populate the
blob with empty space initially using zeroblob() and then overwrite it with
the content you need, incrementally.

Or, if you really want file-system semantics on top of your database (and
this is a reasonably idea, actually) you could write a wrapper library that
implemented file-system semantics on top of SQLite.  I propose an API
something like this:

  SQLFILE *sqlite3fs_fopen(const char *zPath, const char *zMode);
  size_t   sqlite3fs_fread(void*, size_t, size_t, SQLFILE*);
  size_t   sqlite3fs_fwrite(const void*, size_t, size_t, SQLFILE*);
  int      sqlite3fs_fseek(SQLFILE*, size_t offset, int whence);
  size_t   sqlite3fs_ftell(SQLFILE*);
  void     sqlite3fs_rewind(SQLFILE*);
  int      sqlite3fs_ftruncate(SQLFILE*, size_t);
  int      sqlite3fs_rename(const char *zFrom, const char *zTo);
  int      sqlite3fs_unlink(const char *zPath);
  int      sqlite3fs_stat(const char *zPath, struct stat*);
  SQLDIR  *sqlite3fs_opendir(const char *zPath);
  dirent  *sqlite3fs_readdir(SQLDIR*);
  int      sqlite3fs_closedir(SQLDIR*);

The "files" in this wrapper could be stored as one or more page-sized
chunks in separate rows of some backing-store table with a designated
name.  The multiple small blobs could then be pulled together transparently
by the sqlite3fs_fread() routine.  And large writes would be split apart
into several separate INSERTs by sqlite3fs_write().  Since each chunk is a
separate row, files could be increased or decreased in size simply by
adding and deleting rows from the backing store table.  Changing or adding
a single byte to a file means rewriting the last chunk, but for a large
file that is a lot cheaper than rewriting the whole file.  Note also that
real filesystems also have to write in chunks because disk drives work in
chunks.  There really is no such thing as adding a single byte to a file -
you always really overwrite the whole last page.

Putting together a library such as outlined above would provide a
convenient and simple migration path for applications that wanted to
transition from a pile-of-files storage format toward using an SQLite
database as their application file format.

Imagine what could happen if, for example, git where to start using this
library.  Instead of the ".git" directory containing lots and lots of
separate files, your repository would be a single ".git" file which was
really an SQLite database accessed through the "sqlite3fs" wrapper.
Minimal changes (renaming file I/O routines) would be required to the git
core.  But once you have an SQLite database used in place of a
pile-of-files, you can start adding new tables to do lots of interesting
things like hosting bug reports or a wiki as part of your repository (as
Fossil does).

As another example, consider the OpenOffice presentation application whose
current file format (the *.odp file) is a ZIP archive containing lots of
image and XML files.  If the *.odp file where replaced by an SQLite
database with the "sqlite3fs" wrapper, then you would be able to make
incremental changes to an OpenOffice presentation, instead of having to
recreate the entire multi-megabyte ZIP archive in the *.odp file simply
because of a one-character change on one slide.  And your changes would be
atomic, obviating the need for those annoying backups that OpenOffice makes
periodically.

In summary:  No, a bare SQLite blob does not provide file-system
semantics.  But you can write a wrapper library around SQLite that does
provide file-system semantics for large blobs, and doing so would have many
advantages and be a worth-while project, I think.

If anyone reading this wants to undertake such a project, I can provide you
with technical advice, website space with a suitable domain name (ex:
filesystem.sqlite.org), and a Fossil repository to keep the code in.
-- 
D. Richard Hipp
d...@sqlite.org
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to