Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to execute multiple SQL statements at once. #4

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion GRDB/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public final class Database {
/**
Executes an update statement.

db.excute("INSERT INTO persons (name) VALUES (?)", arguments: ["Arthur"])
db.execute("INSERT INTO persons (name) VALUES (?)", arguments: ["Arthur"])

This method may throw a DatabaseError.

Expand All @@ -91,7 +91,47 @@ public final class Database {
let statement = try updateStatement(sql)
return try statement.execute(arguments: arguments)
}


// MARK: - Multiple Statements

/**
Returns a MultipleStatement that can be reused.

let sql = "INSERT INTO persons (name) VALUES ('Harry');" +
"INSERT INTO persons (name) VALUES ('Ron')" +
"INSERT INTO persons (name) VALUES ('Hermione')"
let statement = try db.multipleStatement(sql)

This method may throw a DatabaseError.

- parameter sql: An SQL query.
- returns: A MultipleStatement.
- throws: A DatabaseError whenever a SQLite error occurs.
*/
public func multipleStatement(sql: String) throws -> MultipleStatement {
return try MultipleStatement(database: self, sql: sql)
}

/**
Executes raw SQL, which may include multiple statements separated by semi-colons.

let sql = "INSERT INTO persons (name) VALUES ('Harry');" +
"INSERT INTO persons (name) VALUES ('Ron')" +
"INSERT INTO persons (name) VALUES ('Hermione')"
executeMultiple(sql)

This method may throw a DatabaseError.

- parameter sql: SQL containing multiple statements separated by semi-colons.
- returns: A MultipleStatement.Changes.
- throws: A DatabaseError whenever a SQLite error occurs.
*/
public func executeMultiple(sql: String) throws -> MultipleStatement.Changes {
let statement = try multipleStatement(sql)
return try statement.execute()
}


// MARK: - Transactions

Expand Down
73 changes: 73 additions & 0 deletions GRDB/MultipleStatement.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// GRDB.swift
// https://github.com/groue/GRDB.swift
// Copyright (c) 2015 Gwendal Roué
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.


/**
A subclass of Statement that executes Multiple SQL statements in a single sqlite call.

You create MultipleStatement with the Database.multipleStatement() method:

try dbQueue.inTransaction { db in
let sql = "INSERT INTO persons (name) VALUES ('Harry');" +
"INSERT INTO persons (name) VALUES ('Ron')" +
"INSERT INTO persons (name) VALUES ('Hermione')"
let statement = try db.multipleStatement(sql)
return .Commit
}
*/
public final class MultipleStatement : Statement {

/// The changes performed by an MultipleStatement.
public struct Changes {
/// The number of rows changed by SQL executed.
public let changedRowCount: Int
}

/**
Executes the SQL query.

- parameter arguments: Optional query arguments.
- throws: A DatabaseError whenever a SQLite error occurs.
*/
public func execute() throws -> Changes {
reset()

if let trace = database.configuration.trace {
trace(sql: sql, arguments: nil)
}

let changedRowsBefore = sqlite3_total_changes(database.sqliteConnection)

var errMsg:UnsafeMutablePointer<Int8> = nil
let code = sqlite3_exec(database.sqliteConnection, sql, nil, nil, &errMsg)
guard code == SQLITE_OK else {
throw DatabaseError(code: code, message: database.lastErrorMessage, sql: sql, arguments: nil)
}

let changedRowsAfter = sqlite3_total_changes(database.sqliteConnection)

return Changes(changedRowCount: changedRowsAfter - changedRowsBefore)
}

}