In an unit test, I need to verify that the program skip locked records when processing a table.
I have been unable to setup a locked records because the test can't lock itself which make a lot of sense.
Here is a sample of what I'm trying to achieve.
DEV VAR v_isCommitted AS LOGI NO-UNDO.
DEF VAR hl AS HANDLE NO-UNDO.
DEF BUFFER bufl FOR tablename.
hl = BUFFER bufl:HANDLE.
LOCKED_RECORDS:
DO TRANSACTION ON ERROR UNDO, LEAVE LOCKED_RECORDS:
/*Setup : Create record not committed yet*/
CREATE tablename.
ASSIGN tablename.fields = fieldsvalue.
/*ACT : Code I'm trying to test*/
/*...some code...*/
v_isCommitted = hl:FIND-BY-ROWID(ROWID(tablename), EXCLUSIVE-LOCK, NO-WAIT)
AND AVAILABLE(bufl)
AND NOT LOCKED(bufl).
/*...some code touching the record if it is commited...*/
/*ASSERT : program left new record tablename AS IS.*/
END.
The problem is that the record is available and not locked to the test because it was created by it.
Is there a way I could have the test lock a record from itself so the act part can actually skip the record like it was created by someone else?
Progress: 11.7.1
A session can not lock itself. So you will need to start a second session. For example:
/* code to set things up ... */
/* spawn a sub process to try to lock the record */
os-command silent value( substitute( '_progres -b -db &1 -p lockit.p -param "&2" && > logfile 2>&&1', dbname, "key" )).
In lockit.p use session:parameter to get the key for the record to test (or hard code it I suppose).
Or, as mentioned in the comments below:
/* locktest.p
*/
define variable lockStatus as character no-undo format "x(20)".
find first customer exclusive-lock.
input through value( "_progres /data/sports120/sports120 -b -p ./lockit.p" ).
repeat:
import unformatted lockStatus.
end.
display lockStatus.
and:
/* lockit.p
*/
find first customer exclusive-lock no-wait no-error.
if locked( customer ) then
put "locked".
else
put "not locked".
quit.
I'm using System.Data.SQLite ADO.NET provider for SQLite and the following Powershell code to execute queries (and nonqueries) against a Sqlite3 DB:
Function Invoke-SQLite ($DBFile,$Query) {
try {
Add-Type -Path ".\System.Data.SQLite.dll"
}
catch {
write-warning "Unable to load System.Data.SQLite.dll"
return
}
if (!$DBFile) {
throw "DB Not Found" R
Sleep 5
Exit
}
$conn = New-Object System.Data.SQLite.SQLiteConnection
$conn.ConnectionString="Data Source={0}" -f $DBFile
$conn.Open()
$cmd = $Conn.CreateCommand()
$cmd.CommandText = $Query
#$cmd.CommandTimeout = 10
$ds = New-Object system.Data.DataSet
$da = New-Object System.Data.SQLite.SQLiteDataAdapter($cmd)
[void]$da.fill($ds)
$cmd.Dispose()
$conn.Close()
write-host ("{0} Row(s) returned " -f ($ds.Tables[0].Rows|Measure-Object|Select -ExpandProperty Count))
return $ds.Tables[0]
}
The problem is: while it is trivial to know how many rows have been SELECTed in a query operation, the same is not true if the operation is an INSERT,DELETE or UPDATE (nonqueries)
I know I could use the ExecuteNonQuery method, but i need a generic wrapper which returns number of affected rows while being agnostic about the query it executed (as Invoke-SQLCmd would do, for example)
Is that possible?
Thanks!
A few comments before the answer:
System.data.Sqlite supports executing multiple SQL statements for one command, as long as the CommandText has each valid statements delimited by a semicolon (;). This means that there could be a mixture of queries and DML statements (i.e. INSERT, UPDATE, DELETE). The fact that you do not want to distinguish between the type of statement in $Query tells me that you are likely just passing statements blindly, so it could contain any combination of statements. Simply getting only one value (whether from a query or DML) seems too limiting.
Using a DataAdapter to fill a dataset just to get counts is inefficient. Instead, it may be better to just get a DataReader object and count the returned rows. This also allows a separate count for each query statement to be retrieved, something that gets obscured by using the DataAdapter object. (Perhaps enumerating all tables in the resultant dataset could get the same number, but I'm not certain that would always be equivalent.)
One good thing is that if you insist on using a DataAdapter, it will still execute DML statements (even though the expected result is query that returns rows). The dataset will not be changed (filled), but all statements in the command text will still affect changes in the database, so the following solution will still be useful.
Even if the code had works, I assume that the line which prints "{0} Rows returned" is meant to get a simple count, but $ds.Tables[0].Rows needs to be $ds.Tables[0].Rows.Count.
Notes about this particular solution:
The key is to call either of the sqlite SQL functions changes() or total_changes(). These can be retrieved using SQL: SELECT total_changes();. I recommend getting total_changes() before and after a command, then subtracting the difference. That will get changes for multiple statements executed by one command.
I'm not a PowerShell guru, so I tested everything in C#. Treat the code below more as pseudo code since it may need tweaking.
The code:
$conn = New-Object System.Data.SQLite.SQLiteConnection
try {
$conn.ConnectionString="Data Source={0}" -f $DBFile
$conn.Open()
$cmdCount = $Conn.CreateCommand()
$cmd = $Conn.CreateCommand()
try {
$cmdCount.CommandText = "SELECT total_changes();"
$beforeChanges = $cmdcount.ExecuteScalar()
$cmd.CommandText = $Query
$ds = New-Object System.Data.DataSet
$da = New-Object System.Data.SQLite.SQLiteDataAdapter($cmd)
$rows = 0
try {
[void]$da.fill($ds)
foreach ($tbl in $ds.Tables) {
$rows += $tbl.Rows.Count;
}
} catch {}
$afterChanges = $cmdcount.ExecuteScalar()
$DMLchanges = $afterChanges - $beforeChanges
$totalRowAndChanges = $rows + $DMLchanges
# $ds.Tables[0] may or may not be valid here.
# If query returned no data, no tables will exist.
} finally {
$cmdCount.Dispose()
$cmd.Dispose()
}
} finally {
$conn.Dispose()
}
Alternatively, you could eliminate the DataAdapter:
$cmd.CommandText = $Query
$rdr = $cmd.ExecuteReader()
$rows = 0
do {
while ($rdr.Read()) {
$rows++
}
} while ($rdr.NextResult())
$rdr.Close();
I have a need to crawl a set of data of indeterminate size and build a table key/value index of it. Since I don't know the dimensions in advance, seems I have to use a recursive function. My Lua skills are very new and superficial. I'm having difficulty understanding how to deal with returning a table from the function call.
Note this is for a Lua 5.1 script processor
API = function(tbl)
local table_api = {}
-- do stuff here with target data and add to table_api
table_api["key"] = value
-- then later there is a need to recurse deeper into target data
table_api["lower"] = API(var)
return table_api
end
result = API(source_data)
In most every other language I know there would be some way to make the recurse line table_api["lower"] = API(var) work but since Lua does table variables by reference, my return sub-table just keeps getting overwritten and my result is a tiny last bit of what it should be.
Just for background on my purpose: there's a commercial application I'm working with that has a weakly documented Lua scripting interface. It's running Lua 5.1 and the API is not well documented and frequently updated. As I understand it, everything is stored in _G, so I wanted to write something to reverse engineer the API. I have a working recursive function (not shown here) that enumerates all of _G. For that return value, it just builds up an annotated string and progressively builds on the string. That all works fine and is really useful, but it shows much more that the API interface; all the actual data elements are included, so I have to sift through like 30,000 records to determine an API set of about 500 terms. In order to determine the API, I am trying to use this sub-table return value recursive function being discussed in this question. The code I'm showing here is just a small distilled subset of the larger function.
I'll go ahead and include the full code here. I was hoping to incrementally build a large'ish table of each API level, any sublevels, and finally whatever keys used at the lowest level.
In the end, I was expecting to have a table that I could address like this:
result["api"]["label"]["api"]["sublabel"]["value"]["valuename"]
Full code:
tableAPIShow = function(tbl, table_track)
table_track = table_track or {}
local table_api = {}
if type(tbl) == 'table' then
-- Check if values are tables.
local parent_table_flag = true
for ind,val in pairs(tbl) do
if type(val) ~= 'table' then
parent_table_flag = false
break
end
end
-- If all children are table type, check each of them for subordinate commonality
local api_flag = false
if parent_table_flag == true then
local child_table = {}
local child_table_flag = false
api_flag = true
for ind,val in pairs(tbl) do
-- For each child table, store the names of the indexes.
for sub_ind,sub_val in pairs(val) do
if child_table_flag == false then -- First time though, create starting template view of typical child table.
child_table[sub_ind] = true -- Store the indexes as a template table.
elseif child_table[sub_ind] == nil then -- Otherwise, test this child table compared to the reference template.
api_flag = false
break
end
end
if api_flag == false then -- need to break out of nested loop
break
end
child_table_flag = true
end
end
if api_flag == true then
-- If everything gets to here, then this level is an API with matching child tables below.
for ind,val in pairs(tbl) do
if table_api["api"] == nil then
table_api["api"] = {}
end
table_api["api"][ind] = tableAPIShow(val, table_track)
end
else
-- This level is not an API level, determine how to process otherwise.
for ind,val in pairs(tbl) do
if type(val) == 'table' then
if table_track[val] ~= nil then -- Have we already recursed this table?
else
table_track[val] = true
if table_api["table"] == nil then
table_api["table"] = {}
end
table_api["table"][ind] = tableAPIShow(val, table_track)
end
else -- The children are not tables, they are values
if table_api["value"] == nil then
table_api["value"] = {}
end
table_api["value"][ind] = val
end
end
end
else
-- It's not a table, just return it.
-- Probably never use this portion because it's caught on upper level recurse and not called
return tbl
end
return table_api
end
And I was calling this function in the main script like this:
local str = tableAPIShow(_G)
I've got another function that recursively shows a table so I can look inside my results and see I only get a return value that contains only the values of the top-level of _G (I have it excluded built-in Lua functions/values because I'm only interested in the Application API):
{
[value] = table: 00000000F22CB700 {
[value][_VERSION] = Application/5.8.1 (x86_64; Windows NT 10.0.16299),
[value][tableAPIShow] = "function: 00000000F22C6DE0, defined in (121-231) C:\\Users\\user\\AppData\\Local\\Temp\\APP\\/~mis00002690 ",
[value][_FINAL_VERSION] = true,
[value][Path] = ./Scripts/Database/elements/,
[value][class] = "function: 00000000F1953C40, defined in (68-81) Scripts/Common/Class.lua ",
[value][db_path] = ./Scripts/Database/,
[value][merge_all_units] = "function: 00000000F20D20C8, defined in (2242-2250) Scripts/Database/db_merge.lua ",
}
You just need to localize the variable you store your table in and it will work as you expect:
local table_api = {}
(note that you are passing table variable that conflicts with the global table variable and is not currently used in the function.)
I am inclined to believe that your tableAPIShow function code is working correctly and the
another function that recursively shows a table
fails to serialize your table fully. Hence you don't see the deeper levels of the table returned by tableAPIShow().
I got your initial and current code (tableAPIShow) to work with my simple table serialize function: the whole _Global table is exported completely and formatted as you implemented it in your tableAPIShow().
Code for testing:
apiMassiveTable = {
api = {
get = {
profile = {"profileID", "format"},
name = {"profileID", "encoding"},
number = {"profileID", "binary"}
},
set = {
name = {"apikey", "profileID", "encoding", "newname"},
number = {"apikey", "profileID", "binary", "newnumber"}
},
retrieve = {}
},
metadata = {version="1.4.2", build="nightly"}
}
-- tableAPIShow implemenation here
table.serialize = dofile("serialize.lua")
print(table.serialize("myNameForAHugeTable", tableAPIShow(_G)))
PS: Whatever serialize function you're using, it should enquote strings like Application/5.8.1 (x86_64; Windows NT 10.0.16299) which it does not.
Like #Paul Kulchenko said, you need to learn to use locals (https://www.lua.org/pil/4.2.html). Global variable post-exist until a new lua_State is loaded (a new environment, could be a new process depending on what interpreter you are using). So a tip is to always use local variables for anything you don't want to leave the function or leave the compilation unit.
Think of tables like dictionaries: a word is attached to a definition. Thusly the definition is the data.
What I think you are trying to do is serialization of a table of data. However, that isn't really necessary. You can either shadow copy or deep copy the given table. A shadow copy is when you don't delve into the depths of tables found in the keys, etc. A deep copy is when you copy tables in keys of tables in keys of tables... etc.
local shallow_copy = function(tab)
local rep_tab = {}
for index, value in pairs(tab)do
rep_tab[index] = value
end
return rep_tab
end
-- because local variable is not defined or declared immediately on a 1-liner,
-- a declaration has to exist so that deep_copy can be used
-- lets metatable execute functions
local deep_copy
deep_copy = function(tab)
local rep_tab = {}
for index, value in pairs(tab)do
if(type(value) == "table")then
rep_tab[index] = deep_copy(value)
else
rep_tab[index] = value
end
end
return rep_tab
end
Deco's deepcopy.lua
https://gist.github.com/Deco/3985043
You can also index tables using periods:
local tab = {}
tab.abc = 123
tab["def"] = 456
print(tab.abc, tab["def"])
To serialize the entire _G, you would just filter out the junk you don't need and recurse each table encountered. Watch out for _G, package, and _ENV because if defined it will recurse back to the start.
-- use cap as a whitelist
enumerate_dir = function(dir, cap)
local base = {}
for i, v in pairs(dir) do
-- skip trouble
if(i ~= "_G" and i ~= "_ENV" and i ~= "package")then
if(type(v) == "table")then -- if we have a table
base[i] = enumerate_dir(v, cap)
else
for k, n in pairs(cap) do
if(type(v) == n)then -- if whitelisted
base[i] = tostring(v)
end
end
end
end
end
return base
end
-- only functions and tables from _G please
local enumeration = enumerate_dir(_G, {"function", "table"})
-- do some cool quips to get a basic tree system
prefix = ""
recursive_print = function(dir)
for i, v in pairs(dir)do
if(type(v) == "table")then
print(prefix, i, v)
prefix = prefix .. ">"
recursive_print(v)
else
print(prefix, i, v)
end
end
if(#prefix > 0)then
prefix = prefix:sub(1, #prefix-1)
end
end
recursive_print(test)
I'm trying to use SQLitePCL package to develop a simple UWP app that executes database commands (create-select-update-delete). I created a database sql file that contains some sqlite commands and I'm trying to execute them in my code:
Uri appUri = new Uri("ms-appx:///Assets/db.sql");
StorageFile sFile = StorageFile.GetFileFromApplicationUriAsync(appUri).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
string sSQL = FileIO.ReadTextAsync(sFile).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
ISQLiteStatement cnStatement = dbConnection.Prepare(sSQL);
cnStatement.Step();
But when I run the program, it only executes the first statement in the sql file which is CREATE command and exit without executing the rest of the commands. Here is the sample content of the sql file:
CREATE TABLE Superhero (
Type TEXT PRIMARY KEY,
Picture TEXT
);
INSERT INTO Superhero (
Type,
Picture
)
VALUES (
'batman',
'batman.ico'
);
Anyone knows if there is a way in SQLitePCL to execute a sql file?
Any help would be very much appreciated!
Thanks!
According to the description of sqlite3_prepare interface:
These routines only compile the first statement in zSql, so *pzTail is left pointing to what remains uncompiled.
So that it seems like only the first statement in the commands is actually executed. The remainder is silently ignored. Since every command is ended up with symbol ";", for a quick and simple solution, you may just split the sql commands into single statements and then execute one by one. For example:
string sSQL = FileIO.ReadTextAsync(sFile).AsTask().ConfigureAwait(false).GetAwaiter().GetResult();
var dbConnection = new SQLiteConnection("sun.db", SQLiteOpen.READWRITE);
//using (ISQLiteStatement cnStatement = dbConnection.Prepare(sSQL))
//{
// var result = cnStatement.Step();
//}
var statements = sSQL.Split(new[] { ';' });
foreach (string onestate in statements)
{
using (ISQLiteStatement cnStatement = dbConnection.Prepare(onestate))
{
var result = cnStatement.Step();
}
}
Otherwise, you may need to update the SQLitePCL Nuget package.
I am trying to uninstall a program from add or remove programs via an AutoIt script.
*I dont want to uninstall via removing the registry keys.
* I dont want to uninstall via running an uninstaller.
I can open "add remove programs" by a appwiz.cpl command
However I am failing to recognize the correct program name from the list and invoke an uninstall.
All I want to do is recognize my program from the list, for example "Helloworld" and invoke an uninstall.
You can just loop through all your corresponding Registry Values of which your uninstall list in your "Add or remove programs" is made of... And then directly extract the command that you want to execute. I display it in a Message Box in this example, but you could directly compare the DisplayName to "Helloworld" and then execute the UninstallString with Run(...). This is the exact same as your "Add or remove programs" would invoke. It doesn't mean simply removing registry keys. And it doesn't mean just running "any" uninstaller but the proper one, needed to exactly uninstall this very program like clicking the "Uninstall" button in appwiz.cpl will invoke. So to perform what you asked for as a result, this solution works just fine. It does not acutally handle the appwiz.cpl and cycle through the list of programs...
$uninstall_path1 = "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall"
searchUninstallStrings($uninstall_path1)
$uninstall_path2 = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
searchUninstallStrings($uninstall_path2)
Func searchUninstallStrings($uninstall_path)
$i = 0
While True
$i += 1
Local $entry = RegEnumKey($uninstall_path, $i)
If #error <> 0 Then ExitLoop
$regPath = $uninstall_path & "\" & $entry
$DisplayName = RegRead($regPath, "DisplayName")
If $DisplayName <> "" Then
$message = $DisplayName & #CR
$UninstallString = RegRead($regPath, "UninstallString")
If $UninstallString <> "" Then
$message &= "Uninstall: '" & $UninstallString & "'"
MsgBox(4096, "SubKey #" & $i & ": " & $entry, $message)
EndIf
EndIf
WEnd
EndFunc
Good Luck!
I was able to successfully automate program uninstalls with the following command to open up the Programs and Features control panel menu followed by a series of keystrokes:
Run("C:\Windows\System32\control.exe appwiz.cpl")
WinWait("Programs and Features")
WinActivate("Programs and Features")
Send("ProgramNameHere")
Send("{Enter}")