1 /* 2 * Copyright (C) 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "modules/webdatabase/SQLStatementSync.h" 32 33 #include "bindings/v8/ExceptionState.h" 34 #include "core/dom/ExceptionCode.h" 35 #include "core/platform/sql/SQLValue.h" 36 #include "core/platform/sql/SQLiteDatabase.h" 37 #include "core/platform/sql/SQLiteStatement.h" 38 #include "modules/webdatabase/DatabaseSync.h" 39 #include "modules/webdatabase/SQLError.h" 40 #include "modules/webdatabase/SQLResultSet.h" 41 #include "wtf/PassRefPtr.h" 42 #include "wtf/RefPtr.h" 43 44 namespace WebCore { 45 46 SQLStatementSync::SQLStatementSync(const String& statement, const Vector<SQLValue>& arguments, int permissions) 47 : m_statement(statement) 48 , m_arguments(arguments) 49 , m_permissions(permissions) 50 { 51 ASSERT(!m_statement.isEmpty()); 52 } 53 54 PassRefPtr<SQLResultSet> SQLStatementSync::execute(DatabaseSync* db, ExceptionState& es) 55 { 56 db->setAuthorizerPermissions(m_permissions); 57 58 SQLiteDatabase* database = &db->sqliteDatabase(); 59 60 SQLiteStatement statement(*database, m_statement); 61 int result = statement.prepare(); 62 if (result != SQLResultOk) { 63 if (result == SQLResultInterrupt) 64 es.throwDOMException(SQLDatabaseError); 65 else 66 es.throwDOMException(SyntaxError, SQLError::syntaxErrorMessage); 67 db->setLastErrorMessage("could not prepare statement", result, database->lastErrorMsg()); 68 return 0; 69 } 70 71 if (statement.bindParameterCount() != m_arguments.size()) { 72 if (db->isInterrupted()) 73 es.throwDOMException(SQLDatabaseError); 74 else 75 es.throwDOMException(SyntaxError, SQLError::syntaxErrorMessage); 76 db->setLastErrorMessage("number of '?'s in statement string does not match argument count"); 77 return 0; 78 } 79 80 for (unsigned i = 0; i < m_arguments.size(); ++i) { 81 result = statement.bindValue(i + 1, m_arguments[i]); 82 if (result == SQLResultFull) { 83 es.throwDOMException(QuotaExceededError, SQLError::quotaExceededErrorMessage); 84 db->setLastErrorMessage("there was not enough remaining storage space"); 85 return 0; 86 } 87 88 if (result != SQLResultOk) { 89 es.throwDOMException(SQLDatabaseError); 90 db->setLastErrorMessage("could not bind value", result, database->lastErrorMsg()); 91 return 0; 92 } 93 } 94 95 RefPtr<SQLResultSet> resultSet = SQLResultSet::create(); 96 97 // Step so we can fetch the column names. 98 result = statement.step(); 99 if (result == SQLResultRow) { 100 int columnCount = statement.columnCount(); 101 SQLResultSetRowList* rows = resultSet->rows(); 102 103 for (int i = 0; i < columnCount; i++) 104 rows->addColumn(statement.getColumnName(i)); 105 106 do { 107 for (int i = 0; i < columnCount; i++) 108 rows->addResult(statement.getColumnValue(i)); 109 110 result = statement.step(); 111 } while (result == SQLResultRow); 112 113 if (result != SQLResultDone) { 114 es.throwDOMException(SQLDatabaseError); 115 db->setLastErrorMessage("could not iterate results", result, database->lastErrorMsg()); 116 return 0; 117 } 118 } else if (result == SQLResultDone) { 119 // Didn't find anything, or was an insert. 120 if (db->lastActionWasInsert()) 121 resultSet->setInsertId(database->lastInsertRowID()); 122 } else if (result == SQLResultFull) { 123 // Quota error, the delegate will be asked for more space and this statement might be re-run. 124 es.throwDOMException(QuotaExceededError, SQLError::quotaExceededErrorMessage); 125 db->setLastErrorMessage("there was not enough remaining storage space"); 126 return 0; 127 } else if (result == SQLResultConstraint) { 128 es.throwDOMException(ConstraintError, "A constraint was violated."); 129 db->setLastErrorMessage("statement failed due to a constraint failure"); 130 return 0; 131 } else { 132 es.throwDOMException(SQLDatabaseError); 133 db->setLastErrorMessage("could not execute statement", result, database->lastErrorMsg()); 134 return 0; 135 } 136 137 resultSet->setRowsAffected(database->lastChanges()); 138 return resultSet.release(); 139 } 140 141 } // namespace WebCore 142