Page 1 of 1

Need help with db put/get

PostPosted: Wed Nov 13, 2019 1:41 am
by Silverthorn
I have an indicator that I wrote some years ago and am now trying to finish.

I am having trouble saving and retreating values to a db.

My code I am struggling with is

function Init()
indicator:type(core.Indicator);
indicator:name("BAHA");
indicator:description("BAHA");
indicator:setTag("group", "BAHA");
indicator:setTag("replaceSource","t");
indicator:requiredSource(core.Bar);
indicator.parameters:addString ("dbManager", "Database", "", "UseSaved");
indicator.parameters:addStringAlternative ("dbManager", "UseSaved", "", "UseSaved");
indicator.parameters:addStringAlternative ("dbManager", "UseLocal", "", "UseLocal");
indicator.parameters:addStringAlternative ("dbManager", "Save", "", "Save");
end

function Prepare()
instance:ownerDrawn(true);
source = instance.source;

local dbname = "BAHADB" .. source:name() .. instance.source:barSize ();
require("storagedb")
db = storagedb.get_db(dbname);
local dbManager = instance.parameters.dbManager;
if dbManager == "Save" then
db:put(tostring("SR_Offset"),tostring(SR_Offset));
db:put(tostring("SR_Confirmation"),tostring(SR_Confirmation));
db:put(tostring("Speed"),tostring(Speed));
end
if dbManager == "UseSaved" then
SR_Offset = tonumber(db:get (tostring("SR_Offset"), 0));
SR_Confirmation = tonumber(db:get (tostring("SR_Confirmation"), 0));
Speed = tonumber(db:get (tostring("Speed"), 0));
else
SR_Confirmation = instance.parameters.SR_Confirmation;
SR_Offset = instance.parameters.SR_Offset;
Speed = instance.parameters.Speed;
end

When I run UseLocal no problem.
When I save everything is fine.
When I try to UseSaved I get an error saying that I am attempting to perform arithmetic on upvalue "SR_Confirmation" (a nil value)

I'm not really understanding what makes it an upvalue but I think my problem is that I am using strings and numbers incorrectly.
Can anybody give me some help?

Re: Need help with db put/get

PostPosted: Wed Nov 13, 2019 3:15 am
by Silverthorn
Well I found the problem myself.

I was trying to load the db with values that I only populated afterwards.

SR_Confirmation = instance.parameters.SR_Confirmation;
SR_Offset = instance.parameters.SR_Offset;
Speed = instance.parameters.Speed;

needs to be before

db:put(tostring("SR_Offset"),tostring(SR_Offset));
db:put(tostring("SR_Confirmation"),tostring(SR_Confirmation));
db:put(tostring("Speed"),tostring(Speed));

Re: Need help with db put/get

PostPosted: Sat Jan 02, 2021 7:40 am
by Loggy48
You don't need the tostring() for the first parameter anyway as it is already a character string.

TS uses SQLite so you can see what is in the database by using the DB Broswer for SQLite (once the program has finished of course). The Indicore debugger will show you the structure of the sytem offer etc tables. The database is stored in persistent/luastorage.db, not in a file specified.

All the binding does is to store data as strings so if you want to store a whole Lua table, this must be written into a lua-readable string to start with. Therefore numbers are still stored as text and functions in tables cannot be stored (they appear to be stored but cannot be reused). Functions in text can of course be stored.

Don't forget that SQLite cannot by default store binary data - you have to encode the number as a blob but I doubt it is ever worth it. A useful feature is the open_memory() command which will store data in memory but that of course is lost when the program closes and if you use Linux you can store files in memory anyway using tmpfs etc in /run/user/<userid> which stays until you remove it or reboot the computer. TS runs in a Windoze environment... :(

You can write out a simple lua file and read it in using dofile but then remember that such a chunk has its own scope so you need to return the data either functions or values into local functions or values [ie local v1,v2,v3 = dofile("myfile") where myfile that specifies v1 etc as functions, variables or tables ends with return v1,v2,v3]

For more extensive database storage it may be better to use SQLite3 as in http://lua.sqlite.org. Here is a simple example modified from the examples directory (using UPDATE or repeated runs will insert additional rows):
Code: Select all
local sqlite3 = require("lsqlite3complete")
local db = sqlite3.open("/my/file/testall.db")
db:exec[[
  UPDATE TABLE test (id INTEGER PRIMARY KEY, content);
  INSERT INTO test VALUES (NULL, 'Hello World');
  INSERT INTO test VALUES (NULL, 'Hello Lua');
  INSERT INTO test VALUES (NULL, 'Hello Sqlite3')
]]
for row in db:nrows("SELECT * FROM test") do
  print(row.id, row.content)
end
db:exec[[
  UPDATE TABLE test1 (col1, col2);
  INSERT INTO test1 VALUES (1, 2);
  INSERT INTO test1 VALUES (2, 4);
  INSERT INTO test1 VALUES (3, 6);
  INSERT INTO test1 VALUES (4, 8);
  INSERT INTO test1 VALUES (5, 10)
]]
do
  local square_error_sum = 0
  local function step(ctx, a, b)
    square_error_sum   = square_error_sum + (a - b)^2
  end
  local function final(ctx)
    ctx:result_number( square_error_sum / ctx:aggregate_count() )
  end
  db:create_aggregate("my_stats", 2, step, final)
end

for my_stats in db:urows("SELECT my_stats(col1, col2) FROM test1")
do print("my_stats:", my_stats) end

for a,b in db:urows("SELECT col1, col2 FROM test1")
do print("a b: ", a, b) end