class Amalgalite::SQLite3::Blob

The Blob class enables incremental IO on blob items. If you do not need incremental IO on a binary object, then you do not need to use Blob.

Public Class Methods

new( database, table_name, column_name, row_id, flag ) → Blob click to toggle source

Create a new Blob object and associate it with the approriate, database, table, column and row. flag indicates if the Blob is to be opened for writing “w” or reading “r”.

VALUE am_sqlite3_blob_initialize( VALUE self, VALUE db, VALUE db_name, VALUE table_name, VALUE column_name, VALUE rowid, VALUE flag) 
{
    am_sqlite3_blob *am_blob;
    int              rc;
    am_sqlite3      *am_db;
    char            *zDb      = StringValuePtr( db_name );
    char            *zTable   = StringValuePtr( table_name );
    char            *zColumn  = StringValuePtr( column_name );
    sqlite3_int64    iRow     = NUM2SQLINT64( rowid )  ;
    VALUE            flag_str = StringValue( flag );
    int              flags    = 0;

    /* extract the blob struct */
    Data_Get_Struct(self, am_sqlite3_blob, am_blob);
    
    /* extract the sqlite3 db struct */
    Data_Get_Struct(db, am_sqlite3, am_db);

    /* make sure that the flags are valid, only 'r' or 'w' are allowed */
    if ( ( RSTRING_LEN( flag_str ) != 1) || 
         ( ( 'r' != RSTRING_PTR( flag_str )[0] ) && 
           ( 'w' != RSTRING_PTR( flag_str )[0] ))) {
        rb_raise( eAS_Error, "Error opening Blob in db = %s, table = %s, column = %s, rowid = %lu.  Invalid flag '%s'.  Must be either 'w' or 'r'\n",
                             zDb, zTable, zColumn, (unsigned long)iRow, RSTRING_PTR( flag_str ));
    }

    /* switch to write mode */
    if ( 'w' == RSTRING_PTR( flag_str )[0] ) { 
        flags = 1;
    }

    /* open the blob and associate the db to it */
    rc = sqlite3_blob_open( am_db->db, zDb, zTable, zColumn, iRow, flags, &( am_blob->blob ) );
    if ( SQLITE_OK != rc ) {
        rb_raise( eAS_Error, "Error opening Blob in db = %s, table = %s, column = %s, rowid = %lu : [SQLITE_ERROR %d] %s\n", zDb, zTable, zColumn, (unsigned long)iRow, rc, sqlite3_errmsg( am_db->db) );  
    }
    am_blob->length = sqlite3_blob_bytes( am_blob->blob );
    am_blob->db = am_db->db;

    /* if a block is given then yield self and close the blob when done */
    if ( rb_block_given_p() ) {
        rb_yield( self );
        am_sqlite3_blob_close( self );
        return Qnil;
    } else {
        return self;
    }
}

Public Instance Methods

close → nil click to toggle source

Closes the blob.

VALUE am_sqlite3_blob_close( VALUE self )
{
    am_sqlite3_blob *am_blob;
    int              rc;
    
    Data_Get_Struct(self, am_sqlite3_blob, am_blob);
    rc = sqlite3_blob_close( am_blob->blob );
    if ( SQLITE_OK != rc ) {
        rb_raise(eAS_Error, "Error closing blob: [SQLITE_ERROR %d] %s\n",
                rc, sqlite3_errmsg( am_blob->db ));
    }


    return Qnil;
}
length → length in bytes of the blob click to toggle source

Returns the number of bytes in the blob.

VALUE am_sqlite3_blob_length( VALUE self )
{
    am_sqlite3_blob *am_blob;

    Data_Get_Struct(self, am_sqlite3_blob, am_blob);

    return INT2FIX( am_blob->length );
}
read( int ) → String containting int number of bytes or nil if eof. click to toggle source

returns int number of bytes as a String from the database

VALUE am_sqlite3_blob_read( VALUE self, VALUE length )
{
    am_sqlite3_blob *am_blob;
    int             rc;
    int              n = NUM2INT( length );
    void           *buf = NULL;
    VALUE          result;

    Data_Get_Struct(self, am_sqlite3_blob, am_blob);

    /* we have to be exact on the number of bytes to read.  n + current_offset
     * cannot be larger than the blob's length
     */
    if ( (n + am_blob->current_offset > am_blob->length)) {
        n = am_blob->length - am_blob->current_offset;
    }

    if ( am_blob->current_offset == am_blob->length ) {
        return Qnil;
    }

    buf = (void *)malloc( n );
    rc = sqlite3_blob_read( am_blob->blob, buf, n, am_blob->current_offset); 

    if ( rc != SQLITE_OK ) {
        rb_raise(eAS_Error, "Error reading %d bytes blob at offset %d: [SQLITE_ERROR %d] %s\n",
                n, am_blob->current_offset, rc, sqlite3_errmsg( am_blob->db ));
    }

    am_blob->current_offset += n;

    result = rb_str_new( (char*)buf, n );
    free( buf );
    return result;

}
write( buf ) → int click to toggle source

writes the contents of the string buffer to the blob and returns the number of bytes written.

VALUE am_sqlite3_blob_write( VALUE self, VALUE buf )
{
    am_sqlite3_blob *am_blob;
    int              rc;
    VALUE            str = StringValue( buf );
    int              n   = (int)RSTRING_LEN( str );
    char            *chk_buf = NULL;

    Data_Get_Struct(self, am_sqlite3_blob, am_blob);

    rc = sqlite3_blob_write( am_blob->blob, RSTRING_PTR(str), n, am_blob->current_offset); 

    if ( rc  != SQLITE_OK ) {
        rb_raise(eAS_Error, "Error writing %d bytes blob at offset %d: [SQLITE_ERROR %d] %s\n",
                n, am_blob->current_offset, rc, sqlite3_errmsg( am_blob->db ));
    }

    chk_buf = (char *) malloc( n  + 1);
    chk_buf[n] = '\0';
    sqlite3_blob_read( am_blob->blob, chk_buf, n, 0);

    am_blob->current_offset += n;

    return INT2FIX( n );

}