311 lines
8.2 KiB
AutoHotkey
311 lines
8.2 KiB
AutoHotkey
|
|
; namespace DBA
|
|
|
|
class SQLite
|
|
{
|
|
GetVersion(){
|
|
return SQLite_LibVersion()
|
|
}
|
|
|
|
SQLiteExe(dbFile, commands, ByRef output){
|
|
return SQLite_SQLiteExe(dbFile, commands, output)
|
|
}
|
|
|
|
__New(){
|
|
throw Exception("This is a static Class. Don't create Instances from it!",-1)
|
|
}
|
|
}
|
|
|
|
/*
|
|
Represents a Connection to a SQLite Database
|
|
*/
|
|
class DataBaseSQLLite extends DBA.DataBase
|
|
{
|
|
_handleDB := 0
|
|
|
|
__New(handleDB){
|
|
this._handleDB := handleDB
|
|
if(!this.IsValid())
|
|
{
|
|
throw Exception("Can not create a DataBaseSQLLite instance, because the connection handle is not valid!")
|
|
}
|
|
}
|
|
|
|
|
|
Close(){
|
|
return SQLite_CloseDB(this._handleDB)
|
|
}
|
|
|
|
IsValid(){
|
|
return (this._handleDB != 0)
|
|
}
|
|
|
|
GetLastError(){
|
|
code := 0
|
|
SQLite_ErrCode(this._handleDB, code)
|
|
return code
|
|
}
|
|
|
|
GetLastErrorMsg(){
|
|
msg := ""
|
|
SQLite_ErrMsg(this._handleDB, msg)
|
|
return msg
|
|
}
|
|
|
|
SetTimeout(timeout = 1000){
|
|
return SQLite_SetTimeout(this._handleDB, timeout)
|
|
}
|
|
|
|
|
|
ErrMsg() {
|
|
if (RC := DllCall("SQLite3\sqlite3_errmsg", "UInt", this._handleDB, "Cdecl UInt"))
|
|
return StrGet(RC, "UTF-8")
|
|
return ""
|
|
}
|
|
|
|
ErrCode() {
|
|
return DllCall("SQLite3\sqlite3_errcode", "UInt", this._handleDB, "Cdecl UInt")
|
|
}
|
|
|
|
Changes() {
|
|
return DllCall("SQLite3\sqlite3_changes", "UInt", this._handleDB, "Cdecl UInt")
|
|
}
|
|
|
|
|
|
/*
|
|
Querys the DB and returns a RecordSet
|
|
*/
|
|
OpenRecordSet(sql, editable = false){
|
|
return new DBA.RecordSetSqlLite(this, SQlite_Query(this._handleDB, sql))
|
|
}
|
|
|
|
/*
|
|
Querys the DB and returns a ResultTable or true/false
|
|
*/
|
|
Query(sql){
|
|
|
|
ret := null
|
|
|
|
if (RegExMatch(sql, "i)^\s*SELECT\s")){ ; check if this is a selection query
|
|
|
|
try
|
|
{
|
|
ret := this._GetTableObj(sql)
|
|
} catch e
|
|
throw Exception("Select Query failed.`n`n" sql "`n`nChild Exception:`n" e.What "`n" e.Message "`n" e.File "@" e.Line, -1)
|
|
} else {
|
|
|
|
try
|
|
{
|
|
ret := SQLite_Exec(this._handleDB, sql)
|
|
} catch e
|
|
throw Exception("Non Selection Query failed.`n`n" sql "`n`nChild Exception:`n" e.What " `n" e.Message, -1)
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
EscapeString(str){
|
|
StringReplace, str, str, ', '', All ; replace all single quotes with double single-quotes. pascal escape'
|
|
return 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("BEGIN TRANSACTION;")
|
|
}
|
|
|
|
EndTransaction(){
|
|
this.Query("COMMIT TRANSACTION;")
|
|
}
|
|
|
|
Rollback(){
|
|
this.Query("ROLLBACK TRANSACTION;")
|
|
}
|
|
|
|
InsertMany(records, tableName){
|
|
if(!is(records, Collection) || records.IsEmpty())
|
|
return false
|
|
|
|
colString := ""
|
|
valString := ""
|
|
columns := {}
|
|
|
|
for column, value in records.First()
|
|
{
|
|
colString .= "," this.QuoteIdentifier(column)
|
|
valString .= ",?"
|
|
columns[column] := A_Index
|
|
}
|
|
sql := "INSERT INTO " this.QuoteIdentifier(tableName) "`n(" SubStr(colstring, 2) ")`nVALUES`n(" SubStr(valString, 2) ")"
|
|
|
|
types := []
|
|
for i,row in this._GetTableObj("PRAGMA table_info(" this.QuoteIdentifier(tableName) ")").Rows
|
|
{
|
|
if columns.HasKey(row.name)
|
|
types[columns[row.name]] := row.types
|
|
}
|
|
|
|
this.BeginTransaction()
|
|
|
|
query := SQLite_Query(this._handleDB, sql) ;prepare the query
|
|
if ErrorLevel
|
|
msgbox % errorlevel
|
|
|
|
try
|
|
{
|
|
for i, record in records
|
|
{
|
|
for col, val in record
|
|
{
|
|
if (!columns.HasKey(col) || !types.HasKey(columns[col]))
|
|
throw "Irregular params"
|
|
SQLite_bind(query, columns[col], val, types[columns[col]])
|
|
}
|
|
SQLite_Step(query)
|
|
SQLite_Reset(query)
|
|
}
|
|
}
|
|
catch e
|
|
{
|
|
this.Rollback()
|
|
throw Exception("InsertMany failed.`n`nChild Exception:`n" e.What " `n" e.Message, -1)
|
|
}
|
|
SQLite_QueryFinalize(query)
|
|
this.EndTransaction()
|
|
return True
|
|
}
|
|
|
|
Insert(record, tableName){
|
|
col := new Collection()
|
|
col.Add(record)
|
|
return this.InsertMany(col, tableName)
|
|
}
|
|
|
|
|
|
|
|
_GetTableObj(sql, maxResult = -1) {
|
|
|
|
err := 0, rc := 0, GetRows := 0
|
|
i := 0
|
|
rows := cols := 0
|
|
names := new Collection()
|
|
dbh := this._handleDB
|
|
|
|
SQLite_LastError(" ")
|
|
|
|
if(!_SQLite_CheckDB(dbh)) {
|
|
SQLite_LastError("ERROR: Invalid database handle " . dbh)
|
|
ErrorLevel := _SQLite_ReturnCode("SQLITE_ERROR")
|
|
return False
|
|
}
|
|
if maxResult Is Not Integer
|
|
maxResult := -1
|
|
if (maxResult < -1)
|
|
maxResult := -1
|
|
mytable := ""
|
|
Err := 0
|
|
|
|
_SQLite_StrToUTF8(SQL, UTF8)
|
|
RC := DllCall("SQlite3\sqlite3_get_table", "Ptr", dbh, "Ptr", &UTF8, "Ptr*", mytable
|
|
, "Ptr*", rows, "Ptr*", cols, "Ptr*", err, "Cdecl Int")
|
|
If (ErrorLevel) {
|
|
SQLite_LastError("ERROR: DLLCall sqlite3_get_table failed!")
|
|
Return False
|
|
}
|
|
If (rc) {
|
|
SQLite_LastError(StrGet(err, "UTF-8"))
|
|
DllCall("SQLite3\sqlite3_free", "Ptr", err, "cdecl")
|
|
ErrorLevel := rc
|
|
return false
|
|
}
|
|
|
|
|
|
|
|
if (maxResult = 0) {
|
|
DllCall("SQLite3\sqlite3_free_table", "Ptr", mytable, "Cdecl")
|
|
If (ErrorLevel) {
|
|
SQLite_LastError("ERROR: DLLCall sqlite3_close failed!")
|
|
Return False
|
|
}
|
|
Return True
|
|
}
|
|
|
|
if (maxResult = 1)
|
|
GetRows := 0
|
|
else if (maxResult > 1) && (maxResult < rows)
|
|
GetRows := MaxResult
|
|
else
|
|
GetRows := rows
|
|
Offset := 0
|
|
|
|
Loop, % cols
|
|
{
|
|
names.Add(StrGet(NumGet(mytable+0, Offset), "UTF-8"))
|
|
Offset += A_PtrSize
|
|
}
|
|
|
|
myRows := new Collection()
|
|
Loop, %GetRows% {
|
|
i := A_Index
|
|
fields := new Collection()
|
|
Loop, % Cols
|
|
{
|
|
fields.Add(StrGet(NumGet(mytable+0, Offset), "UTF-8"))
|
|
Offset += A_PtrSize
|
|
}
|
|
myRows.Add(new DBA.Row(Names, fields))
|
|
}
|
|
tbl := new DBA.Table(myRows, Names)
|
|
|
|
; Free Results Memory
|
|
DllCall("SQLite3\sqlite3_free_table", "Ptr", mytable, "Cdecl")
|
|
if (ErrorLevel) {
|
|
SQLite_LastError("ERROR: DLLCall sqlite3_close failed!")
|
|
return false
|
|
}
|
|
return tbl
|
|
}
|
|
|
|
|
|
ReturnCode(RC) {
|
|
static RCODE := {SQLITE_OK: 0 ; Successful result
|
|
, SQLITE_ERROR: 1 ; SQL error or missing database
|
|
, SQLITE_INTERNAL: 2 ; NOT USED. Internal logic error in SQLite
|
|
, SQLITE_PERM: 3 ; Access permission denied
|
|
, SQLITE_ABORT: 4 ; Callback routine requested an abort
|
|
, SQLITE_BUSY: 5 ; The database file is locked
|
|
, SQLITE_LOCKED: 6 ; A table in the database is locked
|
|
, SQLITE_NOMEM: 7 ; A malloc() failed
|
|
, SQLITE_READONLY: 8 ; Attempt to write a readonly database
|
|
, SQLITE_INTERRUPT: 9 ; Operation terminated by sqlite3_interrupt()
|
|
, SQLITE_IOERR: 10 ; Some kind of disk I/O error occurred
|
|
, SQLITE_CORRUPT: 11 ; The database disk image is malformed
|
|
, SQLITE_NOTFOUND: 12 ; NOT USED. Table or record not found
|
|
, SQLITE_FULL: 13 ; Insertion failed because database is full
|
|
, SQLITE_CANTOPEN: 14 ; Unable to open the database file
|
|
, SQLITE_PROTOCOL: 15 ; NOT USED. Database lock protocol error
|
|
, SQLITE_EMPTY: 16 ; Database is empty
|
|
, SQLITE_SCHEMA: 17 ; The database schema changed
|
|
, SQLITE_TOOBIG: 18 ; String or BLOB exceeds size limit
|
|
, SQLITE_CONSTRAINT: 19 ; Abort due to constraint violation
|
|
, SQLITE_MISMATCH: 20 ; Data type mismatch
|
|
, SQLITE_MISUSE: 21 ; Library used incorrectly
|
|
, SQLITE_NOLFS: 22 ; Uses OS features not supported on host
|
|
, SQLITE_AUTH: 23 ; Authorization denied
|
|
, SQLITE_FORMAT: 24 ; Auxiliary database format error
|
|
, SQLITE_RANGE: 25 ; 2nd parameter to sqlite3_bind out of range
|
|
, SQLITE_NOTADB: 26 ; File opened that is not a database file
|
|
, SQLITE_ROW: 100 ; sqlite3_step() has another row ready
|
|
, SQLITE_DONE: 101} ; sqlite3_step() has finished executing
|
|
return RCODE.HasKey(RC) ? RCODE[RC] : ""
|
|
}
|
|
}
|