Skip to content

Commit

Permalink
- Set UTF8 for connection
Browse files Browse the repository at this point in the history
- Add provisional fix for the bug in Perfect-MySQL processing TEXT fieldtype with prepared statement
  • Loading branch information
ucotta committed Nov 19, 2016
1 parent b42d0b3 commit 44e5b5b
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 49 deletions.
126 changes: 79 additions & 47 deletions Sources/MySQLConnectionPool/Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,32 @@
import Foundation
import MySQL

private class PreparedStatementResult {
let stmt: MySQLStmt
let fields: [String]
let results: MySQLStmt.Results

init(stmt: MySQLStmt, fields: [String]) {
self.stmt = stmt
self.fields = fields
self.results = stmt.results()
}

deinit {
stmt.freeResult()
stmt.close()
}
}

public class Connection: Equatable {
private var _lastError = (0, "")
public let mysql:MySQL
private let idConnection:Int
public let idConnection:Int

public init(_ idConnection:Int = -1, host:String, port:Int, user:String, pass:String, scheme:String?) {
self.idConnection = idConnection
mysql = MySQL()
_ = mysql.setOption(.MYSQL_SET_CHARSET_NAME, "utf8")

guard mysql.connect(host: host, user: user, password: pass, port: UInt32(port)) else {
lastError = (Int(mysql.errorCode()), "Can not connect \(mysql.errorCode()) \(mysql.errorMessage())")
Expand All @@ -37,10 +55,12 @@ public class Connection: Equatable {
}

public func returnToPool() {
//print("return to pool \(idConnection)")
MySQLConnectionPool.sharedInstance.returnConnection(conn: self)
}

deinit {
//print("DEINIT connection \(idConnection)")
mysql.close()
}

Expand Down Expand Up @@ -93,17 +113,20 @@ public class Connection: Equatable {
private func resetError() {
lastError = (0, "")
}

public func queryRow(_ query: String) throws -> [String: Any?]? {
resetError()
private func prepareStatement(_ query:String, args: [Any?]?) throws -> PreparedStatementResult {
lastError = (0, "")

let stmt:MySQLStmt = MySQLStmt(mysql)
defer { stmt.close() }

guard stmt.prepare(statement: query) else {
lastError = (Int(stmt.errorCode()), "Cannot create statement \(stmt.errorCode()) \(stmt.errorMessage())")
lastError = (Int(stmt.errorCode()), "Cannot create statement \(stmt.errorCode()) \(stmt.errorMessage())")
throw ConnectionError.errorPrepareStatement(errorCode: Int(mysql.errorCode()), errorMessage: mysql.errorMessage())
}

if let parameters = args {
try addParams(stmt, args: parameters)
}

var keys = [String]()
for index in 0..<Int(stmt.fieldCount()) {
Expand All @@ -112,66 +135,75 @@ public class Connection: Equatable {
}

if !stmt.execute() {
lastError = (Int(stmt.errorCode()), "Cannot execute statement \(stmt.errorCode()) \(stmt.errorMessage())")
throw ConnectionError.errorExecute(errorCode: Int(mysql.errorCode()), errorMessage: mysql.errorMessage())
}
let datos = stmt.results()
defer { stmt.freeResult() }

var result:[String: Any?] = [:]

_ = datos.forEachRow { row in
// return just the first record.
if result.isEmpty {
for (key, value) in zip(keys, row) {
result[key] = value
}
}
}

return result.isEmpty ? nil : result }
return PreparedStatementResult(stmt: stmt, fields: keys)
}

/*
public func queryRow(_ query: String) throws -> [String: Any?]? {
guard mysql.query(statement: query) else {
return nil

public func queryRow(_ query: String, args: Any...) throws -> [String: Any?]? {
resetError()
}

let stmt:MySQLStmt = MySQLStmt(mysql)
defer { stmt.close() }
//store complete result set
let storeResults = dataMysql.storeResults()
var result:[String: Any?] = [:]

guard stmt.prepare(statement: query) else {
lastError = (Int(stmt.errorCode()), "Cannot create statement \(stmt.errorCode()) \(stmt.errorMessage())")
throw ConnectionError.errorPrepareStatement(errorCode: Int(mysql.errorCode()), errorMessage: mysql.errorMessage())
if let row = storeResults?.next() {
for (key, value) in zip(stmt.fields, row) {
result[key] = correctData(data: value)
}
return result
}

try addParams(stmt, args: args)
return nil
}
*/

var keys = [String]()
for index in 0..<Int(stmt.fieldCount()) {
let fieldInfo = stmt.fieldInfo(index: index)
keys.append(fieldInfo?.name ?? "?")
}

if !stmt.execute() {
lastError = (Int(stmt.errorCode()), "Cannot execute statement \(stmt.errorCode()) \(stmt.errorMessage())")
throw ConnectionError.errorExecute(errorCode: Int(mysql.errorCode()), errorMessage: mysql.errorMessage())
private func correctData(data: Any?) -> Any? {
guard data != nil else {
return data
}
if data! is [UInt8] {
return String(bytes: data as! [UInt8], encoding: String.Encoding.utf8)
}
let datos = stmt.results()
defer { stmt.freeResult() }
return data
}


public func queryRow(_ query: String, args: Any...) throws -> [String: Any?]? {
let stmt = try prepareStatement(query, args: args)

var result:[String: Any?] = [:]

_ = datos.forEachRow { row in
_ = stmt.results.forEachRow { row in
// return just the first record.
if result.isEmpty {
for (key, value) in zip(keys, row) {
result[key] = value
for (key, value) in zip(stmt.fields, row) {
result[key] = correctData(data: value)
}
}
}

return result.isEmpty ? nil : result
}


public func queryAll(_ query:String) throws -> [[String: Any?]] {
let stmt = try prepareStatement(query, args: nil)

var result:[[String: Any?]] = []

_ = stmt.results.forEachRow { row in
var dic = [String: Any?]()
for (key, value) in zip(stmt.fields, row) {
dic[key] = correctData(data: value)
}
result.append(dic)
}
return result
}

public func queryAll(_ query:String, closure: (_ row: [String: Any?])->()) throws {
resetError()
Expand Down Expand Up @@ -201,7 +233,7 @@ public class Connection: Equatable {
var dic = [String: Any?]()

for (key, value) in zip(keys, row) {
dic[key] = value
dic[key] = correctData(data: value)
}

closure(dic)
Expand Down Expand Up @@ -238,7 +270,7 @@ public class Connection: Equatable {
var dic = [String: Any?]()

for (key, value) in zip(keys, row) {
dic[key] = value
dic[key] = correctData(data: value)
}

closure(dic)
Expand Down
4 changes: 2 additions & 2 deletions Sources/MySQLConnectionPool/MySQLConnectionPool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class MySQLConnectionPool {
private var port:Int = 3306, scheme:String?, database:String?

// Pool management settins and max wait until throw an exception for timeout.
private var initialSize = 2, maxActive = 10, maxIdle = 4, getTimeout = 20
private var initialSize = 2, maxActive = 20, maxIdle = 4, getTimeout = 5

// Pool data
private var totalConnections = 0
Expand Down Expand Up @@ -59,6 +59,7 @@ public class MySQLConnectionPool {
}
Threading.sleep(seconds: 0.50)
}
print("timeout getconnnection")
throw ConnectionPoolError.timeoutWaitingForFreeConnections
}

Expand Down Expand Up @@ -113,7 +114,6 @@ public class MySQLConnectionPool {
} else {
totalConnections -= 1
}

}

private func isAlive(conn:Connection) -> Bool {
Expand Down

1 comment on commit 44e5b5b

@ucotta
Copy link
Owner Author

@ucotta ucotta commented on 44e5b5b Nov 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+private class PreparedStatementResult {
this is test to be removed

Please sign in to comment.