ADOSQL v6

Post your working scripts, libraries and tools.
Ruevil2
Posts: 173
Joined: 14 Jul 2014, 10:39

ADOSQL v6

Post by Ruevil2 » 29 Jan 2024, 22:19

ADOSQL v6
Last Updated - 2024-02-08
Originally written by [VXE]
Rewritten for V2 by Ruevil2

If you have questions I can be reached on reddit, u/ThrottleMunky

All usage is identical to the original. Please refer here for details.
viewtopic.php?f=6&t=74

Code: Select all

/*
###############################################################################################################
######                         ADOSQL v6 - By [VxE], Modified for V2 by Ruevil2                          ######
###############################################################################################################

	Wraps the utility of ADODB to connect to a database, submit a query, and read the resulting recordset.
	Returns the result as a new object (or array of objects, if the query has multiple statements).
	To instead have this function return a string, include a delimiter option in the connection string.

	IMPORTANT! Before you can use this library, you must have access to a database AND know the connection
	string to connect to your database.

	Varieties of databases will have different connection string formats, and different drivers (providers).
	Use the mighty internet to discover the connection string format and driver for your type of database.

	Example connection string for SQLServer (2005) listening on port 1234 and with a static IP:
	DRIVER={SQL SERVER};SERVER=192.168.0.12,3456;DATABASE=mydb;UID=admin;PWD=12345;APP=AHK
*/

Global ADOSQL_LastError := "", ADOSQL_LastQuery := "" ; These super-globals are for debugging your SQL queries.

ADOSQL( Connection_String, Query_Statement ) {
; Uses an ADODB object to connect to a database, submit a query and read the resulting recordset.
; By default, this function returns an object. If the query generates exactly one result set, the object is
; a 2-dimensional array containing that result (the first row contains the column names). Otherwise, the
; returned object is an array of all the results. To instead have this function return a string, append either
; ";RowDelim=`n" or ";ColDelim=`t" to the connection string (substitute your preferences for "`n" and "`t").
; If there is more than one table in the output string, they are separated by 3 consecutive row-delimiters.
; ErrorLevel is set to "Error" if ADODB is not available, or the COM error code if a COM error is encountered.
; Otherwise ErrorLevel is set to zero.

	coer := "",	txtout := 0, rd := "`n", cd := "CSV", str := Connection_String, o3DA := []

	; Examine the connection string for output formatting options.
	If ( 9 < oTbl := 9 + InStr(";" str, ";RowDelim=") ){
		rd := SubStr(str, (oTbl)<1 ? (oTbl)-1 : (oTbl), 0 - oTbl + oRow := InStr(str ";", ";", 0, (oTbl)<1 ? (oTbl)-1 : (oTbl)))
		str := SubStr(str, 1, oTbl - 11) SubStr(str, (oRow)<1 ? (oRow)-1 : (oRow))
		txtout := 1
	}
	If ( 9 < oTbl := 9 + InStr(";" str, ";ColDelim=") ){
		cd := SubStr(str, (oTbl)<1 ? (oTbl)-1 : (oTbl), 0 - oTbl + oRow := InStr(str ";", ";", 0, (oTbl)<1 ? (oTbl)-1 : (oTbl)))
		str := SubStr(str, 1, oTbl - 11) SubStr(str, (oRow)<1 ? (oRow)-1 : (oRow))
		txtout := 1
	}

	; Create a connection object. > https://www.w3schools.com/asp/ado_ref_connection.asp
	; If something goes wrong here, return empty array and set the error message.
	;Try catches all returned error messages and handles them all via catch
	;Catch is jumped to as soon as an error message occurs
	Try{
		oCon := ComObject("ADODB.Connection")	; Create ADOSQL Object
		oCon.ConnectionTimeout := 9 			; Allow 9 seconds to connect to the server.
		oCon.CursorLocation := 3 				; Use a client-side cursor server.
		oCon.CommandTimeout := 1800 			; A generous 30 minute timeout on the actual SQL statement.
		oCon.Open( str ) 						; open the connection.
		oRec := oCon.execute( ADOSQL_LastQuery := Query_Statement )

		While IsObject( oRec ){
			If !oRec.State ; Recordset.State is zero if the recordset is closed, so we skip it.
				oRec := oRec.NextRecordset()
			Else{ ; A row-returning operation returns an open recordset
				oFld := oRec.Fields
				o3DA.Push( oTbl := [] )
				oTbl.Push( oRow := [] )

				Loop oFld.Count ; Put the column names in the first row.
					oRow.Push(oFld.Item[ A_Index - 1 ].Name)
				
				While !oRec.EOF{ ; While the record pointer is not at the end of the recordset...
					oTbl.Push( oRow := [] )
					Loop oFld.Count
						oRow.Push(oFld.Item[ A_Index - 1 ].Value)
					oRec.MoveNext() ; move the record pointer to the next row of values
				}
				oRec := oRec.NextRecordset() ; Get the next recordset.
			}
		}
		If (txtout){ ; If the user wants plaintext output, copy the results into a string
			Query_Statement := "x"
			Loop o3DA.Length{
				Query_Statement .= rd rd
				oTbl := o3DA[ A_Index ]
				Loop oTbl.Length{
					oRow := oTbl[ A_Index ]
					Loop oRow.Length
						If ( cd = "CSV" ){
							str := oRow[ A_Index ]
							str := StrReplace(str, "`"", "`"`"")
							If !ErrorLevel || InStr(str, ",") || InStr(str, rd)
								str := "'" str "'"
							Query_Statement .= ( A_Index = 1 ? rd : "," ) str
						}
						Else
							Query_Statement .= ( A_Index = 1 ? rd : cd ) oRow[ A_Index ]
				}
			}
			Query_Statement := SubStr(Query_Statement, (2 + 3 * StrLen( rd ))<1 ? (2 + 3 * StrLen( rd ))-1 : (2 + 3 * StrLen( rd )))
		}

		; Close the connection and return the result. Local objects are cleaned up as the function returns.
		oCon.Close()
		ErrorLevel := coer
		Return txtout ? Query_Statement : o3DA.Length = 1 ? o3DA[1] : o3DA
	}
	catch as e{ ; Oh NOES!! Put a description of each error in 'ADOSQL_LastError'.
		;MsgBox("Exception thrown!`n`nwhat: " e.what "`n`nfile: " e.file "`n`nline: " e.line "`n`nmessage: " e.message "`n`nextra: " e.extra,, 16)
		
		oErr := oCon.Errors ; > https://www.w3schools.com/asp/ado_ref_error.asp
		Query_Statement := "x"
		Loop oErr.Count
		{
			oFld := oErr.Item( A_Index - 1 )
			str := oFld.Description
			Query_Statement .= "`n`n`n" SubStr(str, (1 + InStr(str, "]", 0, (2 + InStr(str, "][", 0, -1))<1 ? (2 + InStr(str, "][", 0, -1))-1 : (2 + InStr(str, "][", 0, -1))))<1 ? (1 + InStr(str, "]", 0, (2 + InStr(str, "][", 0, -1))<1 ? (2 + InStr(str, "][", 0, -1))-1 : (2 + InStr(str, "][", 0, -1))))-1 : (1 + InStr(str, "]", 0, (2 + InStr(str, "][", 0, -1))<1 ? (2 + InStr(str, "][", 0, -1))-1 : (2 + InStr(str, "][", 0, -1))))) . "`n   Number: " oFld.Number . ", NativeError: " oFld.NativeError . ", Source: " oFld.Source . ", SQLState: " oFld.SQLState . ", User: " A_UserName . ", Date: " FormatTime(A_Now)
		}
		ADOSQL_LastError := SubStr(Query_Statement, 4)
		FileAppend(ADOSQL_LastError, "ADOSQLErrorLog.txt")
		Query_Statement := ""
		txtout := 1
		Return o3DA
	}
}
Usage:

Code: Select all

#Requires AutoHotkey v2.0
#Include ADOSQL.ahk

ConnectString := "Provider=SQLOLEDB.1;Password=password;Persist Security Info=True;User ID=User;Initial Catalog=InstanceName;Data Source=Server\DatabaseName;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Use Encryption for Data=False;Tag with column collation when possible=False"

Query := "SELECT customer_number FROM customers WHERE record_status = 'A';"
CustomerSelectList := ADOSQL(ConnectString ";coldelim=   `t", Query)

MsgBox(CustomerSelectList)
Last edited by Ruevil2 on 08 May 2024, 14:07, edited 3 times in total.

User avatar
boiler
Posts: 17180
Joined: 21 Dec 2014, 02:44

Re: ADOSQL v6

Post by boiler » 04 Feb 2024, 08:36

Thanks for sharing this. Just about a week ago, I was looking for a v2 version of this, and there was none.

Thalon
Posts: 12
Joined: 24 Nov 2016, 04:55

Re: ADOSQL v6

Post by Thalon » 05 Feb 2024, 08:17

Works like a charm!
It needed just small changes, but I couldn't figure them out myself.
Now I can finally convert my most used script to V2!

Ruevil2
Posts: 173
Joined: 14 Jul 2014, 10:39

Re: ADOSQL v6

Post by Ruevil2 » 08 Feb 2024, 19:54

@boiler
@Thalon

Hey I uploaded a new version. Realized I hadn't properly handled SQL error reporting so I changed that up. All SQL related errors are dumped to an errorlog in the same folder as the script. Let me know if you run into any issues.

Thalon
Posts: 12
Joined: 24 Nov 2016, 04:55

Re: ADOSQL v6

Post by Thalon » 12 Feb 2024, 04:06

Ruevil2 wrote:
08 Feb 2024, 19:54
Hey I uploaded a new version. Realized I hadn't properly handled SQL error reporting so I changed that up. All SQL related errors are dumped to an errorlog in the same folder as the script. Let me know if you run into any issues.
Didn't have problems so far with the first version, but I've not encountered errors yet. I've compared your first and your second version and you did change quite a lot. Thanks for all the effort! :bravo:
This helps me out a lot in my every day work.

Currently I'm rewriting a helper tool from scratch that I had created back in 2015. I've switched work recently and still use it, but it needs some refactoring. SQL is a core functionality in it.

Ruevil2
Posts: 173
Joined: 14 Jul 2014, 10:39

Re: ADOSQL v6

Post by Ruevil2 » 13 Feb 2024, 10:03

Thalon wrote:
12 Feb 2024, 04:06
Ruevil2 wrote:
08 Feb 2024, 19:54
Hey I uploaded a new version. Realized I hadn't properly handled SQL error reporting so I changed that up. All SQL related errors are dumped to an errorlog in the same folder as the script. Let me know if you run into any issues.
Didn't have problems so far with the first version, but I've not encountered errors yet. I've compared your first and your second version and you did change quite a lot. Thanks for all the effort! :bravo:
This helps me out a lot in my every day work.

Currently I'm rewriting a helper tool from scratch that I had created back in 2015. I've switched work recently and still use it, but it needs some refactoring. SQL is a core functionality in it.
The V1 script used ComObjError() to suppress and capture the returned com errors. Since that command is no longer in V2 I used Try/Catch to grab all returned errors and reroute them to the log file. They were causing a hard crash of the script otherwise. All other error messages remain unaffected.

Virlix
Posts: 7
Joined: 17 Oct 2019, 04:21

Re: ADOSQL v6

Post by Virlix » 25 Feb 2024, 13:53

hello,

Please, could you help me with an example with several csv ? i want to use it for to join several tables (inner join or left join) thanks for your help.

hisrRB57
Posts: 67
Joined: 13 Jan 2019, 11:43

Re: ADOSQL v6

Post by hisrRB57 » 28 Feb 2024, 01:53

Here is an example that displays the content in a listview:

Code: Select all

#Requires AutoHotkey v2.0
#Include <ADOSQL>

#SingleInstance Force
ConnectString := "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="  . A_ScriptDir . "\Test\TestDB.accdb;Persist Security Info=False;"

Query := "SELECT * from test;"
aList := ADOSQL(ConnectString ";coldelim=   `t", Query)

for xIndex, xval in aList[1] {
    if (xIndex = 1) {                ; the first array contains the field names
        oGui := Gui()
        oLV := oGui.Add("Listview",,xval)
    } else {                        ; the other arrays contains the values
        oLV.Add("",xval*)
    }
}

oGui.Show()

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 05 May 2024, 22:27

Can someone please help? Thanks!
I'm missing something in my understanding...

I get this error:
This value of type "String" has no property named "_item"

Thanks Ruevil2 for the script.
The new v2 script "works" to list the MsgBox but I want to output the specific fields and not the header.

The old script:

Code: Select all

objReturn := ADOSQL(ConnectString, Query)
taxfile := objReturn[2, 1]
also:

Code: Select all

objReturn := ADOSQL(ConnectString, Query)
Loop, % objReturn.MaxIndex()
 row .= objReturn[2, A_Index] " "
msgbox, % row

hisrRB57 - your script didn't work for me.
I also get the same error


[Mod edit: Added [code][/code] tags. Please use them yourself when posting code.]

User avatar
boiler
Posts: 17180
Joined: 21 Dec 2014, 02:44

Re: ADOSQL v6

Post by boiler » 05 May 2024, 22:46

@alnz123 — Your code is for AHK v1, and this library is for v2. You cannot mix the two. There is a link to the v1 version in the first post.

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 05 May 2024, 22:54

Hi Boiler

This is intended to be in v2.

I am trying to get a v2 script working

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 05 May 2024, 23:43

for v2, I can't seem to get the right syntax to extract the field text.
I keep getting the error
This value of type "String" has no property named "__Item"

User avatar
boiler
Posts: 17180
Joined: 21 Dec 2014, 02:44

Re: ADOSQL v6

Post by boiler » 06 May 2024, 01:50

Then post your v2 code and the full error message you get when you run it. And use [code][/code] tags when you post your code.

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 06 May 2024, 02:40

sorry ...
here's the error

Code: Select all

Error: This value of type "String" has no property named "__Item".

	015: Query := "SELECT * FROM dbo.CLIENT;"
	017: aList := ADOSQL(ConnectString ";coldelim=   	", Query)
▶	018: For xIndex, xval in aList[1]
	018: {
	019: If (xIndex = 1)

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 06 May 2024, 02:49

This code works but I want select specific field and no header

the Password, User, IP and Catalog have been changed

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
#Include ADOSQL.ahk

ConnectString := "Provider=MSOLEDBSQL.1;Password=Password1;Persist Security Info=True;User ID=user;Initial Catalog=Database;Data Source=127.0.0.1\SQLEXPRESS;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Use Encryption for Data=False;Tag with column collation when possible=False"

Query := "SELECT * FROM dbo.CLIENT;"
aList := ADOSQL(ConnectString ";coldelim=   `t", Query)
MsgBox(AList)

User avatar
boiler
Posts: 17180
Joined: 21 Dec 2014, 02:44

Re: ADOSQL v6

Post by boiler » 06 May 2024, 06:01

One last time: Post the code that produced the error.

And it’s starting to look like the issue has nothing to do with the library but just your attempted use of a two-dimensional array, so it’s likely that I’ll move all these posts out of this thread and into its own “Ask for Help (v2)” thread.

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 06 May 2024, 09:44

Hi Boiler, the code that caused the error is line 18 in the code one above. I used the "same" code that hisrRB57 provided.

You're right it might be to do with array, but it's also sourced from the SQL code. I'm not sure if which is creating the issue.

The SQL script extracts the data I need but I can't break out the field data and also without the header.

I had v1 script working but can't get v2.

Thanks

User avatar
boiler
Posts: 17180
Joined: 21 Dec 2014, 02:44

Re: ADOSQL v6

Post by boiler » 06 May 2024, 09:56

alnz123 wrote: the code that caused the error is line 18 in the code one above. I used the "same" code that hisrRB57 provided.
hisrRB57’s code has 19 lines total in it, and line 18 is just a blank line followed by one other line of code, not anywhere close to the lines of code the error message you posted from your script is showing. If you run a different script than what was posted and get an error but won’t post what you actually ran, then I can’t help you. I don’t know why you are so reluctant to just post your actual script, but I’m done asking.

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 06 May 2024, 10:24

Sorry if I wasn't clear. The code I'm referring to is in my post. The error line is marked.
I'm not not posting the code. It is there. I was testing a small SQL query.

According to the guys on Discord, it is probably due to me calling ADOSQL incorrectly and getting text rather than an array.
Anyway, will post when it works as expected

alnz123
Posts: 12
Joined: 31 Jan 2021, 22:01

Re: ADOSQL v6

Post by alnz123 » 06 May 2024, 21:12

ok - so I finally got it working.
The SQL connect was getting a string instead of an array.
The array syntax is different in v2 (no surprise, but wasn't easy for me to figure out)

1. The SQL connect needed to omit the ";ColDelim=`t" so it should be

Code: Select all

aList := ADOSQL(ConnectString, Query)
2. The element extraction from the array should look something like:

Code: Select all

test := aList[2].__Item[2]
MsgBox(test)
Hope this helps others

Post Reply

Return to “Scripts and Functions (v2)”