Example #1
0
        /// <summary>
        /// Compares two blob fields that reside in the two databases on which the blob reader writer object
        /// was opened (you need to use the dual databases constructor in order to use this method).
        /// </summary>
        /// <param name="tableName">The name of the table that contains the blob field</param>
        /// <param name="columnName">The name of the column that contains the blob field</param>
        /// <param name="rowid1">The row id in the first database where the blob field is located.</param>
        /// <param name="rowid2">The row id in the second database where the blob field is located.</param>
        /// <param name="comparer">An optional delegate to get progress notifications and be allowed to
        /// cancel the comparison process.</param>
        /// <returns>TRUE if the two blobs are the same, FALSE if they are different.</returns>
        public bool CompareBlobs(string tableName, string columnName, long rowid1, long rowid2, BlobProgressHandler comparer)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException("Object was disposed.");
            }

            if (_conn2 == IntPtr.Zero)
            {
                throw new InvalidOperationException("You need to use a dual database constructor");
            }

            tableName  = SQLiteParser.Utils.Chop(tableName);
            columnName = SQLiteParser.Utils.Chop(columnName);

            try
            {
                byte[] bbytes1 = null;
                byte[] bbytes2 = null;

                _errorCode = (SQLiteErrorCode)sqlite3_blob_open(_conn1, "main", tableName, columnName, rowid1, 0, ref _blob1);
                if (_errorCode > SQLiteErrorCode.Ok)
                {
                    bbytes1 = GetFieldBytes(_conn1, tableName, columnName, rowid1);
                }
                _errorCode = (SQLiteErrorCode)sqlite3_blob_open(_conn2, "main", tableName, columnName, rowid2, 0, ref _blob2);
                if (_errorCode > SQLiteErrorCode.Ok)
                {
                    bbytes2 = GetFieldBytes(_conn2, tableName, columnName, rowid2);
                }

                if (bbytes1 != null && bbytes2 != null)
                {
                    if (bbytes1.Length != bbytes2.Length)
                    {
                        return(false);
                    }
                    for (int i = 0; i < bbytes1.Length; i++)
                    {
                        if (bbytes1[i] != bbytes2[i])
                        {
                            return(false);
                        }
                    }
                    return(true);
                }

                int count1;
                if (bbytes1 != null)
                {
                    count1 = bbytes1.Length;
                }
                else
                {
                    count1 = sqlite3_blob_bytes(_blob1);
                }

                int count2;
                if (bbytes2 != null)
                {
                    count2 = bbytes2.Length;
                }
                else
                {
                    count2 = sqlite3_blob_bytes(_blob2);
                }

                if (count1 != count2)
                {
                    return(false);
                }

                int count = count1;

                int offset = 0;
                while (count > 0)
                {
                    int toread = (count > PAGESIZE ? PAGESIZE : count);

                    if (bbytes1 == null)
                    {
                        _errorCode = (SQLiteErrorCode)sqlite3_blob_read(_blob1, _buffer1, toread, offset);
                        if (_errorCode > SQLiteErrorCode.Ok)
                        {
                            throw new SQLiteException(_errorCode, "sqlite3_blob_read failed");
                        }
                    }

                    if (bbytes2 == null)
                    {
                        _errorCode = (SQLiteErrorCode)sqlite3_blob_read(_blob2, _buffer2, toread, offset);
                        if (_errorCode > SQLiteErrorCode.Ok)
                        {
                            throw new SQLiteException(_errorCode, "sqlite3_blob_read failed");
                        }
                    }

                    if (bbytes1 == null && bbytes2 == null)
                    {
                        for (int i = 0; i < toread; i++)
                        {
                            if (_buffer1[i] != _buffer2[i])
                            {
                                return(false);
                            }
                        }
                    }
                    else if (bbytes1 != null)
                    {
                        for (int i = 0; i < bbytes1.Length; i++)
                        {
                            if (bbytes1[i] != _buffer2[i])
                            {
                                return(false);
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < bbytes2.Length; i++)
                        {
                            if (bbytes2[i] != _buffer1[i])
                            {
                                return(false);
                            }
                        }
                    }

                    if (comparer != null)
                    {
                        bool cancel = false;
                        comparer(offset + toread, count1, ref cancel);
                        if (cancel)
                        {
                            throw new UserCancellationException();
                        }
                    }

                    offset += toread;
                    count  -= toread;
                } // while

                // Close the blob handles
                if (bbytes1 == null)
                {
                    sqlite3_blob_close(_blob1);
                    _blob1 = IntPtr.Zero;
                }

                if (bbytes2 == null)
                {
                    sqlite3_blob_close(_blob2);
                    _blob2 = IntPtr.Zero;
                }

                return(true);
            }
            finally
            {
                if (_blob1 != IntPtr.Zero)
                {
                    sqlite3_blob_close(_blob1);
                    _blob1 = IntPtr.Zero;
                }
                if (_blob2 != IntPtr.Zero)
                {
                    sqlite3_blob_close(_blob2);
                    _blob2 = IntPtr.Zero;
                }
            } // finally
        }
Example #2
0
        /// <summary>
        /// Copy a BLOB field from the source row to the target row
        /// </summary>
        /// <param name="targetdb">The path to the target row database</param>
        /// <param name="tableName">The name of the table where the row resides</param>
        /// <param name="columnName">The name of the BLOB column</param>
        /// <param name="fromRowId">The ID of the source row</param>
        /// <param name="toRowId">The ID of the target row</param>
        /// <param name="handler">An optional progress notifications handler</param>
        public void CopyBlob(string targetdb, string tableName, string columnName, long fromRowId, long toRowId, BlobProgressHandler handler)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException("Object was disposed.");
            }

            if (_conn2 != IntPtr.Zero)
            {
                throw new InvalidOperationException("You need to use a non-dual database constructor");
            }

            // Open conncetion to the target database as read-write
            _errorCode = (SQLiteErrorCode)sqlite3_open(targetdb, ref _conn2);
            if (_errorCode > SQLiteErrorCode.Ok)
            {
                throw new SQLiteException(_errorCode, "can't open file: " + targetdb);
            }

            try
            {
                // Open source BLOB handle and compute its size
                _errorCode = (SQLiteErrorCode)sqlite3_blob_open(_conn1, "main", tableName, columnName, fromRowId, 0, ref _blob1);
                if (_errorCode > SQLiteErrorCode.Ok)
                {
                    throw new SQLiteException(_errorCode, "failed to open BLOB handle");
                }
                int count1 = sqlite3_blob_bytes(_blob1);

                bool needsResizing = false;

                // Open target BLOB handle and check if it needs to be resized first
                _errorCode = (SQLiteErrorCode)sqlite3_blob_open(_conn2, "main", tableName, columnName, toRowId, 1, ref _blob2);
                if (_errorCode > SQLiteErrorCode.Ok)
                {
                    needsResizing = true;
                }
                else
                {
                    int count2 = sqlite3_blob_bytes(_blob2);
                    if (count1 != count2)
                    {
                        needsResizing = true;
                    }
                } // else

                // If the target BLOB needs resizing do it now.
                if (needsResizing)
                {
                    // We'll need to resize the target BLOB field
                    IntPtr stmt = IntPtr.Zero;
                    IntPtr tail = IntPtr.Zero;

                    // Close the BLOB handle if necessary
                    if (_blob2 != IntPtr.Zero)
                    {
                        _errorCode = (SQLiteErrorCode)sqlite3_blob_close(_blob2);
                        _blob2     = IntPtr.Zero;
                        if (_errorCode > SQLiteErrorCode.Ok)
                        {
                            throw new SQLiteException(_errorCode, "can't close BLOB handle");
                        }
                    }

                    // Prepare SQL statement for zeroing the BLOB field in the correct size for the BLOB
                    // length we want to write to it.
                    _errorCode = (SQLiteErrorCode)sqlite3_prepare_v2(_conn2, "UPDATE " +
                                                                     SQLiteParser.Utils.QuoteIfNeeded(tableName) + " SET " +
                                                                     SQLiteParser.Utils.QuoteIfNeeded(columnName) +
                                                                     " = @blob WHERE RowID = @rowid", -1, ref stmt, ref tail);
                    if (_errorCode > SQLiteErrorCode.Ok)
                    {
                        throw new SQLiteException(_errorCode, "sqlite3_prepare_v2 failed");
                    }

                    try
                    {
                        // Bind the BLOB parameter
                        _errorCode = (SQLiteErrorCode)sqlite3_bind_zeroblob(stmt, 1, count1);
                        if (_errorCode > SQLiteErrorCode.Ok)
                        {
                            throw new SQLiteException(_errorCode, "failed to bind zero-blob");
                        }

                        // Bind the RowID parameter
                        _errorCode = (SQLiteErrorCode)sqlite3_bind_int64(stmt, 2, toRowId);
                        if (_errorCode > SQLiteErrorCode.Ok)
                        {
                            throw new SQLiteException(_errorCode, "failed to bind rowid");
                        }

                        // Execute the prepared statement
                        _errorCode = (SQLiteErrorCode)sqlite3_step(stmt);
                        if (_errorCode > SQLiteErrorCode.Ok && _errorCode < SQLiteErrorCode.Row)
                        {
                            throw new SQLiteException(_errorCode, "failed to execute zeroblob command");
                        }
                    }
                    finally
                    {
                        // Finalize the prepared statement (we don't need it for more executions).
                        sqlite3_finalize(stmt);
                    } // catch

                    // Re-open the target BLOB field
                    _errorCode = (SQLiteErrorCode)sqlite3_blob_open(_conn2, "main", tableName, columnName, toRowId, 1, ref _blob2);
                    if (_errorCode > SQLiteErrorCode.Ok)
                    {
                        throw new SQLiteException(_errorCode, "failed to re-open target BLOB handle");
                    }
                } // if

                int count  = count1;
                int offset = 0;
                while (count > 0)
                {
                    int toread = (count > PAGESIZE ? PAGESIZE : count);

                    // Read the BLOB data from the source database
                    _errorCode = (SQLiteErrorCode)sqlite3_blob_read(_blob1, _buffer1, toread, offset);
                    if (_errorCode > SQLiteErrorCode.Ok)
                    {
                        throw new SQLiteException(_errorCode, "sqlite3_blob_read failed");
                    }

                    // Write it to the target database
                    _errorCode = (SQLiteErrorCode)sqlite3_blob_write(_blob2, _buffer1, toread, offset);
                    if (_errorCode > SQLiteErrorCode.Ok)
                    {
                        throw new SQLiteException(_errorCode, "sqlite3_blob_read failed");
                    }

                    offset += toread;
                    count  -= toread;

                    if (handler != null)
                    {
                        bool cancel = false;
                        handler(offset, count1, ref cancel);
                        if (cancel)
                        {
                            throw new UserCancellationException();
                        }
                    }
                } // while

                // Close the blob handles
                sqlite3_blob_close(_blob1); _blob1 = IntPtr.Zero;
                sqlite3_blob_close(_blob2); _blob2 = IntPtr.Zero;

                // Close the target database connection
                sqlite3_close(_conn2); _conn2 = IntPtr.Zero;
            }
            finally
            {
                if (_blob1 != IntPtr.Zero)
                {
                    sqlite3_blob_close(_blob1);
                    _blob1 = IntPtr.Zero;
                }
                if (_blob2 != IntPtr.Zero)
                {
                    sqlite3_blob_close(_blob2);
                    _blob2 = IntPtr.Zero;
                }
                if (_conn2 != IntPtr.Zero)
                {
                    sqlite3_close(_conn2);
                    _conn2 = IntPtr.Zero;
                }
            } // finally
        }