WinBatch® Technical Support Forum

All Things WinBatch => WinBatch => Topic started by: cssyphus on June 19, 2024, 07:14:45 AM

Title: SQLite extender replacing advanced array functions - real world example
Post by: cssyphus on June 19, 2024, 07:14:45 AM
This post is a follow-up to the post SQLite extender to replace/augment array functions (https://forum.winbatch.com/index.php?topic=3088.0)

Here is my real-world example.

The use case is part of a script that automates logging into multiple switches and APs (approx 65 switches and 1500 APs), and finding the control IP used by the Auvik Collector (among many other tasks). Each device will have at least one IP, but each should have the control IP as one of the IPs. There may be other IPs that are repeated. Some devices do not have a control IP.

This was a challenge using arrays - *IF ONLY* we could schlep the info into a MySQL table and use its powerful functions... (And to have that SQL table only exist in memory... a masterstroke)

This demo is merely an expansion of the previous example posted above by Jim, using helpful commentary and tips provided by Stan and Tony. Of course, the demo requires the free WB SQLite extender.

This demo proves how easy it is to use in-memory SQLite tables instead of arrays to perform advanced array-like functions, like: sorting on multiple columns, identifying the most-repeated value, searching for partial cell data, etc.

Voila:

addExtender(`ilcsl44i.dll`)
goSub UDFs

_arrIn = udfCreateDummySampleDataArray()
_ctrlIP = udfGetControlIP(_arrIn)
message(`Control IP:`, _ctrlIP)
EXIT

:UDFs ;==================================================================================================
    #DEFINEFUNCTION udfGetControlIP(_arrIn) ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        _ctrlIP = ``
        _tmpDb = slConnect(':memory:')
        _SQL = 'CREATE TABLE "ips" ("id"    INTEGER NOT NULL, "ip"    TEXT NOT NULL, PRIMARY KEY("id" AUTOINCREMENT) );'
        slExecute(_tmpDb, _SQL)

        FOR _n = 0 to arrInfo(_arrIn, 1)-1
            _ln = _arrIn[_n]
            _arrLine = arrayize(_ln, `|`)
            _ipField = _arrLine[4]
            for _z = 1 to itemCount(_ipField, `,`)
                _ip = itemExtract(_z, _ipField, `,`)
                _SQL = "INSERT INTO `ips` (ip) VALUES ('%_ip%');"
                slExecute(_tmpDb, _SQL)
            next
        NEXT

        _SQL = "SELECT ip, COUNT(ip) AS `num_vals` FROM `ips` GROUP BY `ip` ORDER BY `num_vals` DESC" ; LIMIT 1"
        _result = slExecute(_tmpDb, _SQL)
        slClose(_tmpDb)
        _ctrlIP = _result[0,0]
        return _ctrlIP
    #ENDFUNCTION ;udfGetControlIP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #DEFINEFUNCTION udfCreateDummySampleDataArray() ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        debugTrace(22)
        _input  = `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.21|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.22|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.25|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.26|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.23|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.27,10.0.1.131|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.31|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.32|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.37|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|20.231.239.246|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.34|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|172.16.145.39,192.168.12.7,10.0.1.131|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.42|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.33|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.24|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|52.94.236.248|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|172.16.145.14,192.168.12.7|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.41|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.06|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|10.0.1.131,192.168.12.7,172.16.145.12|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.17|dummy` : @TAB
        _input := `dummy|dummy|dummy|dummy|192.168.12.7,172.16.145.08|dummy`
        _arr = arrayize(_input, @TAB)
        return _arr
    #ENDFUNCTION ;udfCreateDummySampleDataArray ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Return ;UDFs ============================================================================================

Title: Re: SQLite extender replacing advanced array functions - real world example
Post by: spl on June 19, 2024, 01:14:50 PM

and ignore if not relevant

Title: Re: SQLite extender replacing advanced array functions - real world example
Post by: td on June 19, 2024, 01:26:07 PM
The SQLite extender has a function that saves (persists in MSFT speak) a memory only DB to disk.
Title: Re: SQLite extender replacing advanced array functions - real world example
Post by: cssyphus on June 19, 2024, 02:14:11 PM
Appreciate the input Stan.


Did you have examples or sample code in mind for any of the above?

THANKS for the feedback / brainstorming -- iron sharpens iron.
Title: Re: SQLite extender replacing advanced array functions - real world example
Post by: JTaylor on June 19, 2024, 02:25:08 PM
If you are dealing with some large amounts of data and this process takes a long time you might consider some of the following.  If it is something that runs unattended and time really isn't an issue then ignore this.

This first part may or may not be better than the loop but a good chance it is. Load to Array from the file and use ArrayRemove() to leave only the IP Column. Save to file.  Do a FileGet() and then replace commas with @CRLF.   Then do a replace on @CRLF that generates the SQL for the insert.  Could do all in one go. See BEGIN TRANSACTION and COMMIT.

This next part will definitely improve performance.

During your insert Loop, save up the inserts and do 500 or so at a time.  May need to experiment to find the sweet spot.  Might look at BEGIN TRANSACTION and COMMIT.  Individual inserts are expensive.



Jim
Title: Re: SQLite extender replacing advanced array functions - real world example
Post by: spl on June 19, 2024, 02:25:31 PM
Quote from: td on June 19, 2024, 01:26:07 PMThe SQLite extender has a function that saves (persists in MSFT speak) a memory only DB to disk.

Excellent. I have read about using ATTACH to persist an in-memory to another db, but seemed a bit complicated.
Title: Re: SQLite extender replacing advanced array functions - real world example
Post by: td on June 20, 2024, 08:16:44 AM
The SQLite extender's slStmExecMany function loads the contents of a rank 2 array into a DB all at once. The user only needs a prepared and parameterized SQL statement and an array.  An SQL statement is prepared (compiled) using the slStatement function.