432 lines
11 KiB
AutoHotkey
432 lines
11 KiB
AutoHotkey
/*============================================================
|
||
mysql.ahk
|
||
Provides a set of functions to connect and query a mysql database
|
||
|
||
Based upon the published lib of panofish
|
||
http://www.autohotkey.com/forum/topic67280.html
|
||
|
||
|
||
Offical Documentation of the C-API
|
||
http://dev.mysql.com/doc/refman/5.0/en/c.html
|
||
============================================================
|
||
*/
|
||
|
||
|
||
/*
|
||
Parses the given Connectionstring to a ConnectionData
|
||
|
||
An typical Connectionstring looks like:
|
||
Server=myServerAddress;Port=1234;Database=myDataBase;Uid=myUsername;Pwd=myPassword;
|
||
|
||
Further Info: http://www.connectionstrings.com/mysql
|
||
*/
|
||
MySQL_CreateConnectionData(connectionString){
|
||
connectionData := {}
|
||
StringSplit, connstr, connectionString, `;
|
||
Loop, % connstr0
|
||
{
|
||
StringSplit, segment, connstr%a_index%, =
|
||
connectionData[segment1] := segment2
|
||
}
|
||
return connectionData
|
||
}
|
||
|
||
|
||
|
||
MySQL_StartUp(){
|
||
global MySQL_ExternDir
|
||
MySQL_ExternDir := A_WorkingDir
|
||
|
||
libDllpath := MySQL_DLLPath()
|
||
|
||
if(!FileExist(libDllpath))
|
||
{
|
||
msg := "MySQL Libaray not found!`n" libDllpath " (file missing)"
|
||
OutputDebug, %msg%
|
||
throw Exception(msg,-1)
|
||
}
|
||
|
||
|
||
hModule := DllCall("LoadLibrary", "Str", libDllpath)
|
||
|
||
if (hModule == 0)
|
||
{
|
||
msg := "LoadLibrary failed, can't load module:`n" libDllpath
|
||
OutputDebug, %msg%
|
||
throw Exception(msg, -1)
|
||
}else
|
||
return hModule
|
||
}
|
||
|
||
MySQL_DLLPath(forcedPath = "") {
|
||
static DLLPath := ""
|
||
static dllname := "libmySQL.dll"
|
||
|
||
if(DLLPath == ""){
|
||
; search the dll
|
||
prefix := (A_PtrSize == 8) ? "x64\" : ""
|
||
dllpath := prefix . dllname
|
||
|
||
if (FileExist(A_ScriptDir . "\" . dllpath))
|
||
DLLPath := A_ScriptDir . "\" . dllpath
|
||
else
|
||
DLLPath := A_ScriptDir . "\Lib\" . dllpath
|
||
}
|
||
|
||
if (forcedPath != "")
|
||
DLLPath := forcedPath
|
||
|
||
return DLLPath
|
||
}
|
||
|
||
|
||
/*****************************************************************
|
||
Connect to mysql database and return db handle
|
||
|
||
host:
|
||
user:
|
||
password:
|
||
database:
|
||
port: 3306(default)
|
||
******************************************************************
|
||
*/
|
||
MySQL_Connect(host, user, password, database, port = 3306){
|
||
|
||
|
||
db := DllCall("libmySQL.dll\mysql_init", "ptr", 0)
|
||
|
||
if (db = 0)
|
||
throw Exception("MySQL Error 445, Not enough memory to connect to MySQL", -1)
|
||
|
||
connection := DllCall("libmySQL.dll\mysql_real_connect"
|
||
, "ptr", db
|
||
, "AStr", host ; host name
|
||
, "AStr", user ; user name
|
||
, "AStr", password ; password
|
||
, "AStr", database ; database name
|
||
, "UInt", port ; port
|
||
, "UInt", 0 ; unix_socket
|
||
, "UInt", 0) ; client_flag
|
||
|
||
If (connection == 0)
|
||
throw Exception(BuildMySQLErrorStr(db, "Cannot connect to database"), -1)
|
||
|
||
;debugging only:
|
||
;MsgBox % "Ping database: " . MySQL_Ping(db) . "`nServer version: " . MySQL_GetVersion(db)
|
||
|
||
return db
|
||
}
|
||
|
||
MySQL_Close(db){
|
||
DllCall("libmySQL.dll\mysql_close", "ptr", db)
|
||
}
|
||
|
||
|
||
|
||
MySQL_GetVersion(db){
|
||
serverVersion := DllCall("libmySQL.dll\mysql_get_server_info", "ptr", db, "AStr")
|
||
return serverVersion
|
||
}
|
||
MySQL_Ping(db){
|
||
return DllCall("libmySQL.dll\mysql_ping", "ptr", db)
|
||
}
|
||
|
||
MySQL_GetLastErrorNo(db){
|
||
return DllCall("libmySQL.dll\mysql_errno", "ptr", db)
|
||
}
|
||
|
||
MySQL_GetLastErrorMsg(db){
|
||
return DllCall("libmySQL.dll\mysql_error", "ptr", db, "AStr")
|
||
}
|
||
|
||
/*
|
||
Retrieves a complete result set to the client.
|
||
*/
|
||
MySQL_Store_Result(db) {
|
||
return DllCall("libmySQL.dll\mysql_store_result", "ptr", db)
|
||
}
|
||
|
||
/*
|
||
Retrieves the resultset row-by-row
|
||
*/
|
||
MySQL_Use_Result(db) {
|
||
return DllCall("libmySQL.dll\mysql_use_result", "ptr", db)
|
||
}
|
||
|
||
/*
|
||
Returns a requestResult for the given query
|
||
*/
|
||
MySQL_Query(db, query){
|
||
return DllCall("libmySQL.dll\mysql_query", "ptr", db , "AStr", query)
|
||
}
|
||
|
||
MySQL_free_result(requestResult){
|
||
return DllCall("libmySQL.dll\mysql_free_result", "ptr", requestResult)
|
||
}
|
||
|
||
/*
|
||
Returns the number of columns in a result set.
|
||
*/
|
||
MySQL_num_fields(requestResult) {
|
||
Return DllCall("libmySQL.dll\mysql_num_fields", "ptr", requestResult)
|
||
}
|
||
|
||
/*
|
||
Returns the lengths of all columns in the current row.
|
||
*/
|
||
MySQL_fetch_lengths(requestResult) {
|
||
Return , DllCall("libmySQL.dll\mysql_fetch_lengths", "ptr", requestResult)
|
||
}
|
||
|
||
|
||
/*
|
||
Fetches the next row from the result set.
|
||
*/
|
||
MySQL_fetch_row(requestResult) {
|
||
Return , DllCall("libmySQL.dll\mysql_fetch_row", "ptr", requestResult)
|
||
}
|
||
|
||
|
||
/*
|
||
Fetches given Field
|
||
*/
|
||
Mysql_fetch_field_direct(requestResult, fieldnum) {
|
||
return DllCall("libmySQL.dll\mysql_fetch_field_direct", "ptr", requestResult, "Uint", fieldnum)
|
||
}
|
||
|
||
/*
|
||
Fetches the next field from the result set.
|
||
*/
|
||
Mysql_fetch_field(requestResult) {
|
||
return DllCall("libmySQL.dll\mysql_fetch_field", "ptr", requestResult)
|
||
}
|
||
|
||
/*
|
||
Fetches all fields of the resultSet
|
||
*/
|
||
MySQL_fetch_fields(requestResult){
|
||
global MySQL_Field
|
||
|
||
fields := []
|
||
fieldCount := MySQL_num_fields(requestResult)
|
||
|
||
Loop, % fieldCount
|
||
{
|
||
fptr := Mysql_fetch_field(requestResult)
|
||
fields[A_index] := new MySQL_Field(fptr)
|
||
}
|
||
return fields
|
||
}
|
||
|
||
|
||
/*
|
||
; mysql error handling
|
||
*/
|
||
BuildMySQLErrorStr(db, message, query="") {
|
||
errorCode := DllCall("libmySQL.dll\mysql_errno", "UInt", db)
|
||
errorStr := DllCall("libmySQL.dll\mysql_error", "UInt", db, "AStr")
|
||
Return, "MySQL Error: " message "Error " errorCode ": " errorStr "`n`n" query
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
;============================================================
|
||
; mysql get address
|
||
;============================================================
|
||
|
||
|
||
GetUIntAtAddress(_addr, _offset)
|
||
{
|
||
return NumGet(_addr+0,_offset * 4, "uint")
|
||
}
|
||
|
||
GetPtrAtAddress(_addr, _offset)
|
||
{
|
||
return NumGet(_addr+0,_offset * A_PtrSize, "ptr")
|
||
}
|
||
|
||
|
||
;============================================================
|
||
; internal: dump resultset from given Query to string
|
||
;============================================================
|
||
__MySQL_Query_Dump(_db, _query)
|
||
{
|
||
local resultString, result, requestResult, fieldCount
|
||
local row, lengths, length, fieldPointer, field
|
||
|
||
|
||
result := DllCall("libmySQL.dll\mysql_query", "UInt", _db , "AStr", _query)
|
||
|
||
If (result != 0)
|
||
throw new Exception(BuildMySQLErrorStr(_db, "dbQuery Fail", RegExReplace(_query , "\t", " ")), -1)
|
||
|
||
|
||
requestResult := MySql_Store_Result(_db)
|
||
|
||
if (requestResult = 0) { ; call must have been an insert or delete ... a select would return results to pass back
|
||
return
|
||
}
|
||
|
||
fieldCount := MySQL_num_fields(requestResult)
|
||
|
||
|
||
myfields := MySQL_fetch_fields(requestResult)
|
||
for each, fifi in myfields
|
||
{
|
||
MsgBox % "name: " fifi.Name() "`n org name: " fifi.OrgName() "`ntable: " fifi.Table() "`norg table: " fifi.OrgTable()
|
||
}
|
||
|
||
Loop
|
||
{
|
||
row := MySQL_fetch_row(requestResult)
|
||
if (!row)
|
||
break
|
||
|
||
; Get a pointer on a table of lengths (unsigned long)
|
||
lengths := MySQL_fetch_lengths(requestResult)
|
||
|
||
Loop %fieldCount%
|
||
{
|
||
length := GetUIntAtAddress(lengths, A_Index - 1)
|
||
fieldPointer := GetPtrAtAddress(row, A_Index - 1)
|
||
field := StrGet(fieldPointer, length, "CP0")
|
||
resultString := resultString . field
|
||
if (A_Index < fieldCount)
|
||
resultString := resultString . "|" ; seperator for fields
|
||
}
|
||
resultString := resultString . "`n" ; seperator for records
|
||
}
|
||
MySQL_free_result(requestResult)
|
||
resultString := RegExReplace(resultString , "`n$", "")
|
||
|
||
return resultString
|
||
}
|
||
|
||
|
||
|
||
;============================================================
|
||
; Escape mysql special characters
|
||
; This must be done to sql insert columns where the characters might contain special characters, such as user input fields
|
||
;
|
||
; Escape Sequence Character Represented by Sequence
|
||
; \' A single quote (<28>'<27>) character.
|
||
; \" A double quote (<28>"<22>) character.
|
||
; \n A newline (linefeed) character.
|
||
; \r A carriage return character.
|
||
; \t A tab character.
|
||
; \\ A backslash (<28>\<5C>) character.
|
||
; \% A <20>%<25> character. Usually indicates a wildcard character
|
||
; \_ A <20>_<EFBFBD> character. Usually indicates a wildcard character
|
||
; \b A backspace character.
|
||
;
|
||
; these 2 have not yet been included yet
|
||
; \Z ASCII 26 (Control+Z). Stands for END-OF-FILE on Windows
|
||
; \0 An ASCII NUL (0x00) character.
|
||
;
|
||
; example call:
|
||
; description := mysql_escape_string(description)
|
||
;============================================================
|
||
|
||
Mysql_escape_string(unescaped_string)
|
||
{
|
||
escaped_string := RegExReplace(unescaped_string, "\\", "\\") ; \
|
||
escaped_string := RegExReplace(escaped_string, "'", "\'") ; '
|
||
|
||
escaped_string := RegExReplace(escaped_string, "`t", "\t") ; \t
|
||
escaped_string := RegExReplace(escaped_string, "`n", "\n") ; \n
|
||
escaped_string := RegExReplace(escaped_string, "`r", "\r") ; \r
|
||
escaped_string := RegExReplace(escaped_string, "`b", "\b") ; \b
|
||
|
||
; these characters appear to insert fine in mysql
|
||
;escaped_string := RegExReplace(escaped_string, "%", "\%") ; %
|
||
;escaped_string := RegExReplace(escaped_string, "_", "\_") ; _
|
||
;escaped_string := RegExReplace(escaped_string, """", "\""") ; "
|
||
|
||
return escaped_string
|
||
}
|
||
|
||
|
||
/*
|
||
typedef struct st_mysql_field {
|
||
char *name; /* Name of column */
|
||
char *org_name; /* Original column name, if an alias */
|
||
char *table; /* Table of column if column was a field */
|
||
char *org_table; /* Org table name, if table was an alias */
|
||
char *db; /* Database for table */
|
||
char *catalog; /* Catalog for table */
|
||
char *def; /* Default value (set by mysql_list_fields) */
|
||
unsigned long length; /* Width of column (create length) */
|
||
unsigned long max_length; /* Max width for selected set */
|
||
unsigned int name_length;
|
||
unsigned int org_name_length;
|
||
unsigned int table_length;
|
||
unsigned int org_table_length;
|
||
unsigned int db_length;
|
||
unsigned int catalog_length;
|
||
unsigned int def_length;
|
||
unsigned int flags; /* Div flags */
|
||
unsigned int decimals; /* Number of decimals in field */
|
||
unsigned int charsetnr; /* Character set */
|
||
enum enum_field_types type; /* Type of field. See mysql_com.h for types */
|
||
void *extension;
|
||
} MYSQL_FIELD;
|
||
*/
|
||
|
||
/*
|
||
'mysql_port is a long
|
||
'mysql_unix port is a long (pointer)
|
||
'sizeof(MYSQL_FIELD)=32
|
||
Public Type API_MYSQL_FIELD
|
||
name As Long
|
||
table As Long
|
||
def As Long
|
||
type As API_enum_field_types
|
||
length As Long
|
||
max_length As Long
|
||
flags As Long
|
||
decimals As Long
|
||
End Type
|
||
*/
|
||
class MySQL_Field
|
||
{
|
||
ptr := 0
|
||
|
||
__new(ptr){
|
||
this.ptr := ptr
|
||
}
|
||
|
||
Name(){
|
||
adr := GetPtrAtAddress(this.ptr, 0)
|
||
return StrGet(adr, 255, "CP0")
|
||
}
|
||
|
||
OrgName(){
|
||
adr := GetPtrAtAddress(this.ptr, 4)
|
||
return StrGet(adr, 255, "CP0")
|
||
}
|
||
|
||
Table(){
|
||
adr := GetPtrAtAddress(this.ptr, 8)
|
||
return StrGet(adr, 255, "CP0")
|
||
}
|
||
|
||
OrgTable(){
|
||
adr := GetPtrAtAddress(this.ptr, 12)
|
||
return StrGet(adr, 255, "CP0")
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|