250 lines
6.1 KiB
AutoHotkey
250 lines
6.1 KiB
AutoHotkey
;namespace DBA
|
|
|
|
/*
|
|
Represents a Connection to a SQLite Database
|
|
*/
|
|
class DataBaseMySQL extends DBA.DataBase
|
|
{
|
|
_handleDB := 0
|
|
_connectionData := []
|
|
|
|
__New(connectionData){
|
|
if(!IsObject(connectionData))
|
|
throw Exception("Expected connectionData Array!")
|
|
this._connectionData := connectionData
|
|
|
|
this.Connect()
|
|
}
|
|
|
|
/*
|
|
(Re) Connects to the db with the given creditals
|
|
*/
|
|
Connect(){
|
|
connectionData := this._connectionData
|
|
|
|
if(!connectionData.Port){
|
|
dbHandle := MySQL_Connect(connectionData.Server, connectionData.Uid, connectionData.Pwd, connectionData.Database)
|
|
} else {
|
|
dbHandle := MySQL_Connect(connectionData.Server, connectionData.Uid, connectionData.Pwd, connectionData.Database, connectionData.Port)
|
|
}
|
|
this._handleDB := dbHandle
|
|
}
|
|
|
|
Close(){
|
|
/*
|
|
ToDo!
|
|
*/
|
|
}
|
|
|
|
IsValid(){
|
|
return (this._handleDB != 0)
|
|
}
|
|
|
|
GetLastError(){
|
|
return MySQL_GetLastErrorNo(this._handleDB)
|
|
}
|
|
|
|
GetLastErrorMsg(){
|
|
return MySQL_GetLastErrorMsg(this._handleDB)
|
|
}
|
|
|
|
SetTimeout(timeout = 1000){
|
|
/*
|
|
todo
|
|
*/
|
|
}
|
|
|
|
|
|
ErrMsg() {
|
|
return DllCall("libmySQL.dll\mysql_error", "UInt", this._handleDB, "AStr")
|
|
}
|
|
|
|
ErrCode() {
|
|
return DllCall("libmySQL.dll\mysql_errno", "UInt", this._handleDB) ; "Cdecl UInt"
|
|
}
|
|
|
|
Changes() {
|
|
/*
|
|
ToDo
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
Querys the DB and returns a RecordSet
|
|
*/
|
|
OpenRecordSet(sql, editable = false){
|
|
|
|
result := MySQL_Query(this._handleDB, sql)
|
|
|
|
if (result != 0) {
|
|
errCode := this.ErrCode()
|
|
if(errCode == 2003 || errCode == 2006 || errCode == 0){ ;// we've lost the connection
|
|
;// try reconnect
|
|
this.Connect()
|
|
result := MySQL_Query(this._handleDB, sql)
|
|
if (result != 0)
|
|
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query failed because of lost connection. Reconnect failed too." errCode, sql), -1)
|
|
} else {
|
|
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query Failed Error " errCode, sql), -1)
|
|
}
|
|
}
|
|
|
|
requestResult := MySQL_Use_Result(this._handleDB)
|
|
if(!requestResult)
|
|
return false
|
|
|
|
return new DBA.RecordSetMySQL(this._handleDB, requestResult)
|
|
}
|
|
|
|
/*
|
|
Querys the DB and returns a ResultTable or true/false
|
|
*/
|
|
Query(sql){
|
|
return this._GetTableObj(sql)
|
|
}
|
|
|
|
EscapeString(str){
|
|
return Mysql_escape_string(str)
|
|
}
|
|
|
|
QuoteIdentifier(identifier) {
|
|
; ` characters are actually valid. Technically everthing but a literal null U+0000.
|
|
; Everything else is fair game: http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
|
|
StringReplace, identifier, identifier, ``, ````, All
|
|
return "``" identifier "``"
|
|
}
|
|
|
|
BeginTransaction(){
|
|
this.Query("START TRANSACTION;")
|
|
}
|
|
|
|
EndTransaction(){
|
|
this.Query("COMMIT;")
|
|
}
|
|
|
|
Rollback(){
|
|
this.Query("ROLLBACK;")
|
|
}
|
|
|
|
InsertMany(records, tableName){
|
|
|
|
if(!is(records, Collection) || records.IsEmpty())
|
|
return false
|
|
|
|
sql := "INSERT INTO " tableName "`n"
|
|
colString := ""
|
|
|
|
for column, value in records.First()
|
|
{
|
|
colstring .= this.QuoteIdentifier(column) ","
|
|
}
|
|
StringTrimRight, colstring, colstring, 1
|
|
sql .= "(" colstring ")`nVALUES`n"
|
|
|
|
for each, record in records
|
|
{
|
|
valString := ""
|
|
for column, value in record
|
|
{
|
|
valString .= this.ToSqlLiteral(value) ","
|
|
}
|
|
StringTrimRight, valString, valString, 1
|
|
sql .= "(" valString "),`n"
|
|
}
|
|
StringTrimRight, colstring, colstring, 1
|
|
sql := Trim(sql," `t`r`n,") ";"
|
|
|
|
;FileAppend,`n---------`n%sql%`n, dba_sql.log
|
|
return this.Query(sql)
|
|
}
|
|
|
|
|
|
Insert(record, tableName){
|
|
records := new Collection()
|
|
records.Add(record)
|
|
return this.InsertMany(records, tableName)
|
|
}
|
|
|
|
Update(fields, constraints, tableName, safe = True) {
|
|
if (safe) ;limitation: information_schema doesn't work with temp tables
|
|
for k, row in this.Query("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_KEY = 'PRI' AND TABLE_NAME = " this.ToSqlLiteral(tableName)).Rows
|
|
if (!constraints.HasKey(row[1]))
|
|
return -1 ; error handling....
|
|
|
|
WHERE := ""
|
|
for col, val in constraints
|
|
WHERE .= ", " this.QuoteIdentifier(col) " = " this.ToSqlLiteral(val)
|
|
WHERE := SubStr(WHERE, 3)
|
|
|
|
SET := ""
|
|
for col, val in fields
|
|
SET .= "AND " this.QuoteIdentifier(col) " = " this.EscapeString(val)
|
|
SET := SubStr(SET, 5)
|
|
|
|
query := "UPDATE " this.QuoteIdentifier(tableName) " SET " SET " WHERE " WHERE
|
|
return db.Query(query)
|
|
}
|
|
|
|
_GetTableObj(sql, maxResult = -1) {
|
|
|
|
result := MySQL_Query(this._handleDB, sql)
|
|
|
|
/*
|
|
* Instant reconnect attempt
|
|
*/
|
|
if (result != 0) {
|
|
errCode := this.ErrCode()
|
|
if(errCode == 2003 || errCode == 2006 || errCode == 0){ ;// we've lost the connection
|
|
;// try reconnect
|
|
this.Connect()
|
|
result := MySQL_Query(this._handleDB, sql)
|
|
if (result != 0)
|
|
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query failed because of lost connection. Reconnect failed too." errCode, sql), -1)
|
|
} else {
|
|
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query Failed Error " errCode, sql), -1)
|
|
}
|
|
}
|
|
|
|
|
|
requestResult := MySql_Store_Result(this._handleDB)
|
|
|
|
if (!requestResult) ; the query was a non {SELECT, SHOW, DESCRIBE, EXPLAIN or CHECK TABLE} statement which doesn't yield any resultset
|
|
return
|
|
|
|
mysqlFields := MySQL_fetch_fields(requestResult)
|
|
colNames := new Collection()
|
|
columnCount := 0
|
|
for each, mysqlField in mysqlFields
|
|
{
|
|
colNames.Add(mysqlField.Name())
|
|
columnCount++
|
|
}
|
|
|
|
rowptr := 0
|
|
myRows := new Collection()
|
|
while((rowptr := MySQL_fetch_row(requestResult)))
|
|
{
|
|
rowIndex := A_Index
|
|
datafields := new Collection()
|
|
|
|
lengths := MySQL_fetch_lengths(requestResult)
|
|
Loop, % columnCount
|
|
{
|
|
length := GetUIntAtAddress(lengths, A_Index - 1)
|
|
fieldPointer := GetPtrAtAddress(rowptr, A_Index - 1)
|
|
if (fieldPointer != 0) ; "NULL values in the row are indicated by NULL pointers." See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html
|
|
fieldValue := StrGet(fieldPointer, length, "CP0")
|
|
else
|
|
fieldValue := "" ; Should use DBA.DataBase.NULL from database-types branch?
|
|
datafields.Add(fieldValue)
|
|
}
|
|
myRows.Add(new DBA.Row(colNames, datafields))
|
|
}
|
|
MySQL_free_result(requestResult)
|
|
|
|
tbl := new DBA.Table(myRows, colNames)
|
|
return tbl
|
|
}
|
|
}
|