Commit f5409f08 authored by darin@apple.com's avatar darin@apple.com

WebCore:

        Reviewed by Anders.

        - fix <rdar://problem/5691072> ASSERTION FAILED: isPrepared() when executing an empty statement

        For empty statements, SQLite returns 0 for the statement. We have to cope with that.

        Test: storage/empty-statement.html

        * platform/sql/SQLiteStatement.cpp:
        (WebCore::sqlite3_prepare16_v2): Added overload so we don't need an #if inside the prepare
        function.
        (WebCore::SQLiteStatement::SQLiteStatement): Initialize the m_isPrepared boolean. Removed
        the code to add a null character to the end of the string; instead we will use
        charactersWithNullTermination.
        (WebCore::SQLiteStatement::prepare): Set m_isPrepared based on the error value returned.
        Use the error value from sqlite3_prepare16_v2, not from lastError().
        (WebCore::SQLiteStatement::step): Assert that the statement is prepared rather than checking
        it at runtime. However, in the case where this is called with m_statement of 0, return
        success rather than an error. That's needed for empty statements.
        (WebCore::SQLiteStatement::finalize): Use early return idiom for clarity. When there is no
        statement, return SQLITE_OK instead of calling lastError().
        (WebCore::SQLiteStatement::reset): Use early return idiom for clarity. When there is no
        statement, return SQLITE_OK rather than SQLITE_ERROR, but assert the statement is prepared.
        (WebCore::SQLiteStatement::executeCommand): Adjust the code that does a prepare so that it
        will work for empty statements. Do we really need to allow calling this without prepare?
        It would be simpler to just be able to assert that it's prepared.
        (WebCore::SQLiteStatement::returnsAtLeastOneResult): Ditto.
        (WebCore::SQLiteStatement::bindBlob): Added some assertions. Return SQLITE_ERROR if this
        is called with m_statement of 0 (should not be possible without assertions firing first).
        Return the actual error code rather than lastError().
        (WebCore::SQLiteStatement::bindText): Ditto. Also simplified the special case for empty
        strings, since it requires any non-null pointer, not a pointer to a global zero character.
        (WebCore::SQLiteStatement::bindInt64): Ditto.
        (WebCore::SQLiteStatement::bindDouble): Ditto.
        (WebCore::SQLiteStatement::bindNull): Ditto.
        (WebCore::SQLiteStatement::bindValue): Moved default case out of the switch to take
        advantage of the gcc compiler warning for unhandled enum values in a switch.
        (WebCore::SQLiteStatement::bindParameterCount): Added assertion and code to handle the
        empty statement case.
        (WebCore::SQLiteStatement::columnCount): Added assertion and changed the code to use
        the early-return idiom.
        (WebCore::SQLiteStatement::getColumnName): Removed getColumnName16 -- we always use 16-bit
        characters and have no reason to ever use the 8-bit function. Added assertions about the
        passed-in column number. It's a little strange that this function checks the column number
        for too-large column numbers, but not for negative ones. I didn't change that for now.
        (WebCore::SQLiteStatement::getColumnText): Ditto.
        (WebCore::SQLiteStatement::getColumnDouble): Ditto.
        (WebCore::SQLiteStatement::getColumnInt): Ditto.
        (WebCore::SQLiteStatement::getColumnInt64): Ditto.
        (WebCore::SQLiteStatement::getColumnBlobAsVector): Ditto.
        (WebCore::SQLiteStatement::getColumnBlob): Tightened up function a bit, including use of
        the early-return idiom and replacing the multiple "size = 0" with a single one at the
        start of the function.
        (WebCore::SQLiteStatement::returnTextResults): Added a failure case when the prepare
        call doesn't work. Cleared the vector earlier to make the failure code simpler. Moved
        the declaration of the result boolean down lower to make it clearer what it's for.
        Changed use of lastError() to call on the database, to make it clearer that there's
        no per-statement last error kept around. It'd be even better to not use lastError() here.
        (WebCore::SQLiteStatement::returnIntResults): Ditto.
        (WebCore::SQLiteStatement::returnInt64Results): Ditto.
        (WebCore::SQLiteStatement::returnDoubleResults): Ditto.
        (WebCore::SQLiteStatement::isExpired): Changed to use || rather than ?: because I think
        it's slightly easier to read that way.

        * platform/sql/SQLiteStatement.h: Removed unneeded includes and forward declarations.
        Also removed unnneeded functions isPrepared, getColumnName16, getColumnText16,
        returnTextResults16, lastError, and lastErrorMsg. Changed prepareAndStep so that it
        checks the result of prepare before callling step. Added a debug-only m_isPrepared boolean.

        * loader/icon/IconDatabase.cpp:
        (WebCore::IconDatabase::checkIntegrity): Remove 16 suffix from text-related function names.
        (WebCore::IconDatabase::performURLImport): Ditto.
        (WebCore::IconDatabase::pruneUnretainedIcons): Ditto.
        * platform/sql/SQLiteDatabase.cpp:
        (WebCore::SQLiteDatabase::clearAllTables): Ditto.
        * storage/Database.cpp:
        (WebCore::retrieveTextResultFromDatabase): Ditto.
        (WebCore::Database::performGetTableNames): Ditto.
        * storage/DatabaseTracker.cpp:
        (WebCore::DatabaseTracker::fullPathForDatabase): Ditto.
        (WebCore::DatabaseTracker::populateOrigins): Ditto.
        (WebCore::DatabaseTracker::databaseNamesForOrigin): Ditto.
        (WebCore::DatabaseTracker::addDatabase): Ditto.
        * storage/SQLStatement.cpp:
        (WebCore::SQLStatement::execute): Ditto.

        * platform/sql/SQLiteDatabase.h: Removed unneeded includes.
        * storage/SQLResultSet.h: Ditto.
        * storage/SQLResultSetRowList.h: Ditto.

LayoutTests:

        Reviewed by Anders.

        - test for <rdar://problem/5691072> ASSERTION FAILED: isPrepared() when executing an empty statement

        * storage/empty-statement-expected.txt: Added.
        * storage/empty-statement.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@29797 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 85814089
2008-01-25 Darin Adler <darin@apple.com>
Reviewed by Anders.
- test for <rdar://problem/5691072> ASSERTION FAILED: isPrepared() when executing an empty statement
* storage/empty-statement-expected.txt: Added.
* storage/empty-statement.html: Added.
2008-01-25 Antti Koivisto <antti@apple.com>
Reviewed by Darin.
......
Executed an empty statement. If you didn't see a crash or assertion, the test passed.
<html>
<head>
<script>
function writeMessageToLog(message)
{
document.getElementById("console").innerText += message + "\n";
}
function executeEmptyStatement(transaction)
{
transaction.executeSql("");
writeMessageToLog("Executed an empty statement. If you didn't see a crash or assertion, the test passed.");
if (window.layoutTestController)
layoutTestController.notifyDone();
}
function runTest() {
if (window.layoutTestController) {
layoutTestController.dumpAsText();
layoutTestController.waitUntilDone();
}
var db = openDatabase("EmptyStatementTest", "1.0", "Database for an empty statement test", 1);
db.transaction(executeEmptyStatement);
}
</script>
</head>
<body onload="runTest()">
<pre id="console"></pre>
</body>
</html>
2008-01-25 Darin Adler <darin@apple.com>
Reviewed by Anders.
- fix <rdar://problem/5691072> ASSERTION FAILED: isPrepared() when executing an empty statement
For empty statements, SQLite returns 0 for the statement. We have to cope with that.
Test: storage/empty-statement.html
* platform/sql/SQLiteStatement.cpp:
(WebCore::sqlite3_prepare16_v2): Added overload so we don't need an #if inside the prepare
function.
(WebCore::SQLiteStatement::SQLiteStatement): Initialize the m_isPrepared boolean. Removed
the code to add a null character to the end of the string; instead we will use
charactersWithNullTermination.
(WebCore::SQLiteStatement::prepare): Set m_isPrepared based on the error value returned.
Use the error value from sqlite3_prepare16_v2, not from lastError().
(WebCore::SQLiteStatement::step): Assert that the statement is prepared rather than checking
it at runtime. However, in the case where this is called with m_statement of 0, return
success rather than an error. That's needed for empty statements.
(WebCore::SQLiteStatement::finalize): Use early return idiom for clarity. When there is no
statement, return SQLITE_OK instead of calling lastError().
(WebCore::SQLiteStatement::reset): Use early return idiom for clarity. When there is no
statement, return SQLITE_OK rather than SQLITE_ERROR, but assert the statement is prepared.
(WebCore::SQLiteStatement::executeCommand): Adjust the code that does a prepare so that it
will work for empty statements. Do we really need to allow calling this without prepare?
It would be simpler to just be able to assert that it's prepared.
(WebCore::SQLiteStatement::returnsAtLeastOneResult): Ditto.
(WebCore::SQLiteStatement::bindBlob): Added some assertions. Return SQLITE_ERROR if this
is called with m_statement of 0 (should not be possible without assertions firing first).
Return the actual error code rather than lastError().
(WebCore::SQLiteStatement::bindText): Ditto. Also simplified the special case for empty
strings, since it requires any non-null pointer, not a pointer to a global zero character.
(WebCore::SQLiteStatement::bindInt64): Ditto.
(WebCore::SQLiteStatement::bindDouble): Ditto.
(WebCore::SQLiteStatement::bindNull): Ditto.
(WebCore::SQLiteStatement::bindValue): Moved default case out of the switch to take
advantage of the gcc compiler warning for unhandled enum values in a switch.
(WebCore::SQLiteStatement::bindParameterCount): Added assertion and code to handle the
empty statement case.
(WebCore::SQLiteStatement::columnCount): Added assertion and changed the code to use
the early-return idiom.
(WebCore::SQLiteStatement::getColumnName): Removed getColumnName16 -- we always use 16-bit
characters and have no reason to ever use the 8-bit function. Added assertions about the
passed-in column number. It's a little strange that this function checks the column number
for too-large column numbers, but not for negative ones. I didn't change that for now.
(WebCore::SQLiteStatement::getColumnText): Ditto.
(WebCore::SQLiteStatement::getColumnDouble): Ditto.
(WebCore::SQLiteStatement::getColumnInt): Ditto.
(WebCore::SQLiteStatement::getColumnInt64): Ditto.
(WebCore::SQLiteStatement::getColumnBlobAsVector): Ditto.
(WebCore::SQLiteStatement::getColumnBlob): Tightened up function a bit, including use of
the early-return idiom and replacing the multiple "size = 0" with a single one at the
start of the function.
(WebCore::SQLiteStatement::returnTextResults): Added a failure case when the prepare
call doesn't work. Cleared the vector earlier to make the failure code simpler. Moved
the declaration of the result boolean down lower to make it clearer what it's for.
Changed use of lastError() to call on the database, to make it clearer that there's
no per-statement last error kept around. It'd be even better to not use lastError() here.
(WebCore::SQLiteStatement::returnIntResults): Ditto.
(WebCore::SQLiteStatement::returnInt64Results): Ditto.
(WebCore::SQLiteStatement::returnDoubleResults): Ditto.
(WebCore::SQLiteStatement::isExpired): Changed to use || rather than ?: because I think
it's slightly easier to read that way.
* platform/sql/SQLiteStatement.h: Removed unneeded includes and forward declarations.
Also removed unnneeded functions isPrepared, getColumnName16, getColumnText16,
returnTextResults16, lastError, and lastErrorMsg. Changed prepareAndStep so that it
checks the result of prepare before callling step. Added a debug-only m_isPrepared boolean.
* loader/icon/IconDatabase.cpp:
(WebCore::IconDatabase::checkIntegrity): Remove 16 suffix from text-related function names.
(WebCore::IconDatabase::performURLImport): Ditto.
(WebCore::IconDatabase::pruneUnretainedIcons): Ditto.
* platform/sql/SQLiteDatabase.cpp:
(WebCore::SQLiteDatabase::clearAllTables): Ditto.
* storage/Database.cpp:
(WebCore::retrieveTextResultFromDatabase): Ditto.
(WebCore::Database::performGetTableNames): Ditto.
* storage/DatabaseTracker.cpp:
(WebCore::DatabaseTracker::fullPathForDatabase): Ditto.
(WebCore::DatabaseTracker::populateOrigins): Ditto.
(WebCore::DatabaseTracker::databaseNamesForOrigin): Ditto.
(WebCore::DatabaseTracker::addDatabase): Ditto.
* storage/SQLStatement.cpp:
(WebCore::SQLStatement::execute): Ditto.
* platform/sql/SQLiteDatabase.h: Removed unneeded includes.
* storage/SQLResultSet.h: Ditto.
* storage/SQLResultSetRowList.h: Ditto.
2008-01-25 Adele Peterson <adele@apple.com>
Reviewed by Sam.
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
*
* Redistribution and use in source and binary forms, with or without
......@@ -1151,7 +1151,7 @@ bool IconDatabase::checkIntegrity()
return false;
}
String resultText = integrity.getColumnText16(0);
String resultText = integrity.getColumnText(0);
// A successful, no-error integrity check will be "ok" - all other strings imply failure
if (resultText == "ok")
......@@ -1178,8 +1178,8 @@ void IconDatabase::performURLImport()
int result = query.step();
while (result == SQLResultRow) {
String pageURL = query.getColumnText16(0);
String iconURL = query.getColumnText16(1);
String pageURL = query.getColumnText(0);
String iconURL = query.getColumnText(1);
{
MutexLocker locker(m_urlAndIconLock);
......@@ -1575,7 +1575,7 @@ void IconDatabase::pruneUnretainedIcons()
int result;
while ((result = pageSQL.step()) == SQLResultRow) {
MutexLocker locker(m_urlAndIconLock);
if (!m_pageURLToRecordMap.contains(pageSQL.getColumnText16(1)))
if (!m_pageURLToRecordMap.contains(pageSQL.getColumnText(1)))
pageIDsToDelete.append(pageSQL.getColumnInt64(0));
}
......
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
*
* Redistribution and use in source and binary forms, with or without
......@@ -196,7 +196,7 @@ void SQLiteDatabase::clearAllTables()
{
String query = "SELECT name FROM sqlite_master WHERE type='table';";
Vector<String> tables;
if (!SQLiteStatement(*this, query).returnTextResults16(0, tables)) {
if (!SQLiteStatement(*this, query).returnTextResults(0, tables)) {
LOG(SQLDatabase, "Unable to retrieve list of tables from database");
return;
}
......
......@@ -29,14 +29,12 @@
#include "PlatformString.h"
#include "Threading.h"
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
#if COMPILER(MSVC)
#pragma warning(disable: 4800)
#endif
typedef struct sqlite3 sqlite3;
struct sqlite3;
namespace WebCore {
......
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -33,12 +33,24 @@
namespace WebCore {
#if SQLITE_VERSION_NUMBER < 3003009
// FIXME: This overload helps us compile with older versions of SQLite 3, but things like quotas will not work.
static inline int sqlite3_prepare16_v2(sqlite3* db, const void* zSql, int nBytes, sqlite3_stmt** ppStmt, const void** pzTail)
{
return sqlite3_prepare16(db, zSql, nBytes, ppStmt, pzTail);
}
#endif
SQLiteStatement::SQLiteStatement(SQLiteDatabase& db, const String& sql)
: m_database(db)
, m_query(sql)
, m_statement(0)
#ifndef NDEBUG
, m_isPrepared(false)
#endif
{
m_query.append(UChar(0));
}
SQLiteStatement::~SQLiteStatement()
......@@ -47,24 +59,24 @@ SQLiteStatement::~SQLiteStatement()
}
int SQLiteStatement::prepare()
{
{
ASSERT(!m_isPrepared);
const void* tail;
LOG(SQLDatabase, "SQL - prepare - %s", m_query.ascii().data());
#if SQLITE_VERSION_NUMBER >= 3003009
if (sqlite3_prepare16_v2(m_database.sqlite3Handle(), m_query.characters(), -1, &m_statement, &tail) != SQLITE_OK) {
#else
if (sqlite3_prepare16(m_database.sqlite3Handle(), m_query.characters(), -1, &m_statement, &tail) != SQLITE_OK) {
int error = sqlite3_prepare16_v2(m_database.sqlite3Handle(), m_query.charactersWithNullTermination(), -1, &m_statement, &tail);
if (error != SQLITE_OK)
LOG(SQLDatabase, "sqlite3_prepare16 failed (%i)\n%s\n%s", error, m_query.ascii().data(), sqlite3_errmsg(m_database.sqlite3Handle()));
#ifndef NDEBUG
m_isPrepared = error == SQLITE_OK;
#endif
LOG(SQLDatabase, "sqlite3_prepare16 failed (%i)\n%s\n%s", lastError(), m_query.ascii().data(), sqlite3_errmsg(m_database.sqlite3Handle()));
m_statement = 0;
}
return lastError();
return error;
}
int SQLiteStatement::step()
{
if (!isPrepared())
return SQLITE_ERROR;
ASSERT(m_isPrepared);
if (!m_statement)
return SQLITE_OK;
LOG(SQLDatabase, "SQL - step - %s", m_query.ascii().data());
int error = sqlite3_step(m_statement);
if (error != SQLITE_DONE && error != SQLITE_ROW) {
......@@ -76,29 +88,31 @@ int SQLiteStatement::step()
int SQLiteStatement::finalize()
{
if (m_statement) {
LOG(SQLDatabase, "SQL - finalize - %s", m_query.ascii().data());
int result = sqlite3_finalize(m_statement);
m_statement = 0;
return result;
}
return lastError();
#ifndef NDEBUG
m_isPrepared = false;
#endif
if (!m_statement)
return SQLITE_OK;
LOG(SQLDatabase, "SQL - finalize - %s", m_query.ascii().data());
int result = sqlite3_finalize(m_statement);
m_statement = 0;
return result;
}
int SQLiteStatement::reset()
{
if (m_statement) {
LOG(SQLDatabase, "SQL - reset - %s", m_query.ascii().data());
return sqlite3_reset(m_statement);
}
return SQLITE_ERROR;
ASSERT(m_isPrepared);
if (!m_statement)
return SQLITE_OK;
LOG(SQLDatabase, "SQL - reset - %s", m_query.ascii().data());
return sqlite3_reset(m_statement);
}
bool SQLiteStatement::executeCommand()
{
if (!isPrepared())
if (prepare() != SQLITE_OK)
return false;
if (!m_statement && prepare() != SQLITE_OK)
return false;
ASSERT(m_isPrepared);
if (step() != SQLITE_DONE) {
finalize();
return false;
......@@ -109,9 +123,9 @@ bool SQLiteStatement::executeCommand()
bool SQLiteStatement::returnsAtLeastOneResult()
{
if (!isPrepared())
if (prepare() != SQLITE_OK)
return false;
if (!m_statement && prepare() != SQLITE_OK)
return false;
ASSERT(m_isPrepared);
if (step() != SQLITE_ROW) {
finalize();
return false;
......@@ -123,44 +137,61 @@ bool SQLiteStatement::returnsAtLeastOneResult()
int SQLiteStatement::bindBlob(int index, const void* blob, int size)
{
ASSERT(m_isPrepared);
ASSERT(index > 0);
ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
ASSERT(blob);
ASSERT(size > -1);
ASSERT(size >= 0);
sqlite3_bind_blob(m_statement, index, blob, size, SQLITE_TRANSIENT);
if (!m_statement)
return SQLITE_ERROR;
return lastError();
return sqlite3_bind_blob(m_statement, index, blob, size, SQLITE_TRANSIENT);
}
int SQLiteStatement::bindText(int index, const String& text)
{
static const UChar emptyString[1] = { 0 };
ASSERT(m_isPrepared);
ASSERT(index > 0);
ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
// String::characters() returns 0 for the empty string, which SQLite
// treats as a null, so we supply a non-null pointer for that case.
UChar anyCharacter = 0;
const UChar* characters;
// String::characters() returns 0 for the empty string
// which SQLite treats as a null string so we translate it to a
// "real" empty string here.
if (!text.isNull() && text.isEmpty())
characters = emptyString;
if (text.isEmpty() && !text.isNull())
characters = &anyCharacter;
else
characters = text.characters();
sqlite3_bind_text16(m_statement, index, characters, sizeof(UChar) * text.length(), SQLITE_TRANSIENT);
return lastError();
return sqlite3_bind_text16(m_statement, index, characters, sizeof(UChar) * text.length(), SQLITE_TRANSIENT);
}
int SQLiteStatement::bindInt64(int index, int64_t integer)
{
ASSERT(m_isPrepared);
ASSERT(index > 0);
ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
return sqlite3_bind_int64(m_statement, index, integer);
}
int SQLiteStatement::bindDouble(int index, double number)
{
ASSERT(m_isPrepared);
ASSERT(index > 0);
ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
return sqlite3_bind_double(m_statement, index, number);
}
int SQLiteStatement::bindNull(int index)
{
ASSERT(m_isPrepared);
ASSERT(index > 0);
ASSERT(static_cast<unsigned>(index) <= bindParameterCount());
return sqlite3_bind_null(m_statement, index);
}
......@@ -173,69 +204,53 @@ int SQLiteStatement::bindValue(int index, const SQLValue& value)
return bindDouble(index, value.number());
case SQLValue::NullValue:
return bindNull(index);
default:
ASSERT_NOT_REACHED();
// To keep the compiler happy
return SQLITE_ERROR;
}
ASSERT_NOT_REACHED();
return SQLITE_ERROR;
}
unsigned SQLiteStatement::bindParameterCount() const
{
ASSERT(isPrepared());
ASSERT(m_isPrepared);
if (!m_statement)
return 0;
return sqlite3_bind_parameter_count(m_statement);
}
int SQLiteStatement::columnCount()
{
if (m_statement)
return sqlite3_data_count(m_statement);
return 0;
}
String SQLiteStatement::getColumnName(int col)
{
ASSERT(m_isPrepared);
if (!m_statement)
if (prepareAndStep() != SQLITE_ROW)
return String();
if (columnCount() <= col)
return String();
return String(sqlite3_column_name(m_statement, col));
return 0;
return sqlite3_data_count(m_statement);
}
String SQLiteStatement::getColumnName16(int col)
String SQLiteStatement::getColumnName(int col)
{
ASSERT(col >= 0);
if (!m_statement)
if (prepareAndStep() != SQLITE_ROW)
return String();
if (columnCount() <= col)
return String();
return String((const UChar*)sqlite3_column_name16(m_statement, col));
return String(reinterpret_cast<const UChar*>(sqlite3_column_name16(m_statement, col)));
}
String SQLiteStatement::getColumnText(int col)
{
ASSERT(col >= 0);
if (!m_statement)
if (prepareAndStep() != SQLITE_ROW)
return String();
if (columnCount() <= col)
return String();
return String((const char*)sqlite3_column_text(m_statement, col));
}
String SQLiteStatement::getColumnText16(int col)
{
if (!m_statement)
if (prepareAndStep() != SQLITE_ROW)
return String();
if (columnCount() <= col)
return String();
return String((const UChar*)sqlite3_column_text16(m_statement, col));
return String(reinterpret_cast<const UChar*>(sqlite3_column_text16(m_statement, col)));
}
double SQLiteStatement::getColumnDouble(int col)
{
ASSERT(col >= 0);
if (!m_statement)
if (prepareAndStep() != SQLITE_ROW)
return 0.0;
......@@ -246,6 +261,7 @@ double SQLiteStatement::getColumnDouble(int col)
int SQLiteStatement::getColumnInt(int col)
{
ASSERT(col >= 0);
if (!m_statement)
if (prepareAndStep() != SQLITE_ROW)
return 0;
......@@ -256,6 +272,7 @@ int SQLiteStatement::getColumnInt(int col)
int64_t SQLiteStatement::getColumnInt64(int col)
{
ASSERT(col >= 0);
if (!m_statement)
if (prepareAndStep() != SQLITE_ROW)
return 0;
......@@ -266,6 +283,8 @@ int64_t SQLiteStatement::getColumnInt64(int col)
void SQLiteStatement::getColumnBlobAsVector(int col, Vector<char>& result)
{
ASSERT(col >= 0);
if (!m_statement && prepareAndStep() != SQLITE_ROW) {
result.clear();
return;
......@@ -276,7 +295,6 @@ void SQLiteStatement::getColumnBlobAsVector(int col, Vector<char>& result)
return;
}
const void* blob = sqlite3_column_blob(m_statement, col);
if (!blob) {
result.clear();
......@@ -291,58 +309,47 @@ void SQLiteStatement::getColumnBlobAsVector(int col, Vector<char>& result)
const void* SQLiteStatement::getColumnBlob(int col, int& size)
{
ASSERT(col >= 0);
size = 0;
if (finalize() != SQLITE_OK)
LOG(SQLDatabase, "Finalize failed");
if (prepare() != SQLITE_OK)
if (prepare() != SQLITE_OK) {
LOG(SQLDatabase, "Prepare failed");
if (step() != SQLITE_ROW)
{LOG(SQLDatabase, "Step wasn't a row");size=0;return 0;}
if (columnCount() <= col) {
size = 0;
return 0;
}
if (step() != SQLITE_ROW) {
LOG(SQLDatabase, "Step wasn't a row");
return 0;
}
if (columnCount() <= col)
return 0;
const void* blob = sqlite3_column_blob(m_statement, col);
if (blob) {
size = sqlite3_column_bytes(m_statement, col);
return blob;
}
size = 0;
return 0;
if (!blob)
return 0;
size = sqlite3_column_bytes(m_statement, col);
return blob;
}
bool SQLiteStatement::returnTextResults(int col, Vector<String>& v)
{
bool result = true;
if (m_statement)
finalize();
prepare();
ASSERT(col >= 0);
v.clear();
while (step() == SQLITE_ROW) {
v.append(getColumnText(col));
}
if (lastError() != SQLITE_DONE) {
result = false;
LOG(SQLDatabase, "Error reading results from database query %s", m_query.ascii().data());
}
finalize();
return result;
}
bool SQLiteStatement::returnTextResults16(int col, Vector<String>& v)
{
bool result = true;
if (m_statement)
finalize();
prepare();
v.clear();
while (step() == SQLITE_ROW) {
v.append(getColumnText16(col));
}
if (lastError() != SQLITE_DONE) {
if (prepare() != SQLITE_OK)
return false;
while (step() == SQLITE_ROW)
v.append(getColumnText(col));
bool result = true;
if (m_database.lastError() != SQLITE_DONE) {
result = false;
LOG(SQLDatabase, "Error reading results from database query %s", m_query.ascii().data());
}
......@@ -352,16 +359,17 @@ bool SQLiteStatement::returnTextResults16(int col, Vector<String>& v)
bool SQLiteStatement::returnIntResults(int col, Vector<int>& v)
{
bool result = true;
v.clear();
if (m_statement)
finalize();
prepare();
if (prepare() != SQLITE_OK)
return false;