Dynamic SQL Set Golang - sqlite

I have a doubt about the structure of a SQLite query. I'm trying to update a user-selected value in the table referencing the row by the username.
The table is called Data and has these columns: USERNAME,PASSWORD,ADDRESS,NOTES.
I'm using SQL drivers for GO (_ "github.com/mattn/go-sqlite3"), here's my query:
...
stmt, err := db.Prepare("UPDATE Data SET ?=? WHERE USERNAME=?")
check(err)
res, err := stmt.Exec(splittedQuery[0], splittedQuery[1],splittedQuery[2])
...
From this sequence I can only get a syntax error: near "?": syntax error.
How should I manage this? If it's a trivial question I'm sorry, I'm just new to GO and trying to learn something out of it.
Thanks

You cannot do that in SQL. It's not specific to sqlite either. Parameterized placeholder are only for value, you cannot change the structure of the query with that. Here are some documentation links for your reference:
https://jmoiron.github.io/sqlx/#bindvars
https://use-the-index-luke.com/sql/where-clause/bind-parameters
What you are trying to do is building a dynamic query. You can do that by building your query string yourself:
query := "UPDATE Data SET " + col_name + "=? WHERE USERNAME=?"
But depending from the source of your data for the column_name you need to be cautious of sql injection (this is a whole other topic, for fun you can look at that https://imgs.xkcd.com/comics/exploits_of_a_mom.png).
There are also a few library available to help you with that. For example to name one, you can check this one https://github.com/Masterminds/squirrel

Related

Need to get data from a table using database link where database name is dynamic

I am working on a system where I need to create a view.I have two databases
1.CDR_DB
2.EMS_DB
I want to create the view on the EMS_DB using table from CDR_DB. This I am trying to do via dblink.
The dblink is created at the runtime, i.e. DB Name is decided at the time user installs the database, based on the dbname dblink is decided.
My issue is I am trying to create a query like below to create a view from a table which name is decided at run time. Please see below query :
select count(*)
from (SELECT CONCAT('cdr_log#', alias) db_name
FROM ems_dbs a,
cdr_manager b
WHERE a.db_type = 'CDR'
and a.ems_db_id = b.cdr_db_id
and b.op_state = 4 ) db_name;
In this query cdr_log#"db_name" is the runtime table name(db_name get's created at runtime).
When I'm trying to run above query, I'm not getting the desired result. The result of the above query is '1'.
When running only the sub-query from the above query :
SELECT CONCAT('cdr_log#', alias) db_name
FROM ems_dbs a,
cdr_manager b
WHERE a.db_type = 'CDR'
and a.ems_db_id = b.cdr_db_id
and b.op_state = 4;
i'm getting the desired result, i.e. cdr_log#cdrdb01
but when i'm trying to run the full query, getting result as '1'.
Also, when i'm trying to run as
select count(*) from cdr_log#cdrdb01;
I'm getting the result as '24' which is correct.
Expected Result is that I should get the same output similar to the query :
select count(*) from cdr_log#cdrdb01;
---24
But the desired result is coming as '1' using the full query mentioned initially.
Please let me know a way to solve the above problem. I found a way to do it via a procedure, but i'm not sure how can I invoke this procedure.
Can this be done as part of sub query as I have used above?
You're not going to be able to create a view that will dynamically reference an object over a database link unless you do something like create a pipelined table function that builds the SQL dynamically.
If the database link is created and named dynamically at installation time, it would probably make the most sense to create any objects that depend on the database link (such as the view) at installation time too. Dynamic SQL tends to be much harder to write, maintain, and debug than static SQL so it would make sense to minimize the amount of dynamic SQL you need. If you can dynamically create the view at installation time, that's likely the easiest option. Even better than directly referencing the remote object in the view, particularly if there are multiple objects that need to reference the remote object, would probably be to have the view reference a synonym and create the synonym at install time. Something like
create synonym cdr_log_remote
for cdr#<<dblink name>>
create or replace view view_name
as
select *
from cdr_log_remote;
If you don't want to create the synonym/ view at installation time, you'd need to use dynamic SQL to reference the remote object. You can't use dynamic SQL as the SELECT statement in a view so you'd need to do something like have a view reference a pipelined table function that invokes dynamic SQL to call the remote object. That's a fair amount of work but it would look something like this
-- Define an object that has the same set of columns as the remote object
create type typ_cdr_log as object (
col1 number,
col2 varchar2(100)
);
create type tbl_cdr_log as table of typ_cdr_log;
create or replace function getAllCDRLog
return tbl_cdr_log
pipelined
is
l_rows typ_cdr_log;
l_sql varchar(1000);
l_dblink_name varchar(100);
begin
SELECT alias db_name
INTO l_dblink_name
FROM ems_dbs a,
cdr_manager b
WHERE a.db_type = 'CDR'
and a.ems_db_id = b.cdr_db_id
and b.op_state = 4;
l_sql := 'SELECT col1, col2 FROM cdr_log#' || l_dblink_name;
execute immediate l_sql
bulk collect into l_rows;
for i in 1 .. l_rows.count
loop
pipe row( l_rows(i) );
end loop;
return;
end;
create or replace view view_name
as
select *
from table( getAllCDRLog );
Note that this will not be a particularly efficient way to structure things if there are a large number of rows in the remote table since it reads all the rows into memory before starting to return them back to the caller. There are plenty of ways to make the pipelined table function more efficient but they'll tend to make the code more complicated.

Error with SQLite query, What am I missing?

I've been attempting to increase my knowledge and trying out some challenges. I've been going at this for a solid two weeks now finished most of the challenge but this one part remains. The error is shown below, what am i not understanding?
Error in sqlite query: update users set last_browser= 'mozilla' + select sql from sqlite_master'', last_time= '13-04-2019' where id = '14'
edited for clarity:
I'm trying a CTF challenge and I'm completely new to this kind of thing so I'm learning as I go. There is a login page with test credentials we can use for obtaining many of the flags. I have obtained most of the flags and this is the last one that remains.
After I login on the webapp with the provided test credentials, the following messages appear: this link
The question for the flag is "What value is hidden in the database table secret?"
So from the previous image, I have attempted to use sql injection to obtain value. This is done by using burp suite and attempting to inject through the user-agent.
I have gone through trying to use many variants of the injection attempt shown above. Im struggling to find out where I am going wrong, especially since the second single-quote is added automatically in the query. I've gone through the sqlite documentation and examples of sql injection, but I cannot sem to understand what I am doing wrong or how to get that to work.
A subquery such as select sql from sqlite_master should be enclosed in brackets.
So you'd want
update user set last_browser= 'mozilla' + (select sql from sqlite_master''), last_time= '13-04-2019' where id = '14';
Although I don't think that will achieve what you want, which isn't clear. A simple test results in :-
You may want a concatenation of the strings, so instead of + use ||. e.g.
update user set last_browser= 'mozilla' || (select sql from sqlite_master''), last_time= '13-04-2019' where id = '14';
In which case you'd get something like :-
Thanks for everyone's input, I've worked this out.
The sql query was set up like this:
update users set last_browser= '$user-agent', last_time= '$current_date' where id = '$id_of_user'
edited user-agent with burp suite to be:
Mozilla', last_browser=(select sql from sqlite_master where type='table' limit 0,1), last_time='13-04-2019
Iterated with that found all tables and columns and flags. Rather time consuming but could not find a way to optimise.

RJDBC: R to Oracle cannot DELETE or DROP TABLE

I'm using RJDBC to connect to a local database. This allows me to make SELECT queries easily using dbGetQuery, and CREATE TABLE using dbWriteTable.
However, I cannot figure out a method to DROP TABLE or DELETE or SELECT INTO directly from my R console. These things work when I do it directly in SQL Developer, but not when I pass the query onto the database from R.
How do I perform database record manipulations which are not SELECT statements using R?
I'd try using a different type instead.
dbGetQuery bases itself on finding and iterating over the DB rather than manipulating it's records.
Similar questions were asked before;
I couldn't find a nice R example, but if it helps, A nice java example could be found here:
EDIT:
I found the type I was talking about! Took me a while, anyhow - sqlQuery allows you to run pretty much any query, that is - a change in the DB records. Example I modified from this source:
res <- sqlQuery(con1,"DELETE TABLE TESTDATA", errors=FALSE)
# res will now hold the result of the query.
# -1 means error, otherwise iteration is sucessful, and it will hold the number of rows affected.
if (res == -1){ #if something messed up
cat ("An error has occurred.\n")
msg <- odbcGetErrMsg(con1) #Use your connection for this.
print (msg)
} else {
cat ("Table was deleted successfully.\n")
}
EDIT 2:
I got it confused with RODBC, however there's no reason to worry, since I found the RJDBC alternative as well! It's called, dbSendUpdate. Example:
# Assuming you have the connection saved as conn; these example shows how to use dbSendUpdate to create tables and insert values.
# You could use it with every non-selective query, that is, which manipulates the record (update,delete,insert,drop etc.)
# create table, with dbSendUpdate:
dbSendUpdate(conn, "CREATE TABLE foo(a INT,b VARCHAR(100))")
# insert value, bind parameters to placeholders in statement:
dbSendUpdate(conn, "INSERT INTO foo VALUES(?,?)", 42, "bar")
# feel free to modify the query itself, these are just example values.
this is similar to another answered question here
basically dbGetQuery() as it name implies is used to send queries and recive their result.
if you want to send a general statement to the db like 'drop table' etc.
you can use:
dbSendUpdate(connection_object, "drop table table_name")

Sqlite auto timestamp - insert then display on DB aware grid

I have some experince with MySql, and am moving to Sqlite for the first time.
The Sqlite documentation for data types, section 1.2 states that
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values
I would prefer an auto timestamp, but will live with having to pass it in every time if it will get my code working.
Followinf this question, I have declared my field as
`time_stamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
However, it is not displaying anything on a DB ware grid.
I added an OnDrawCell() and thought that this might help:
var cellText : String;
cellValue : String;
dateTime : TDateTime;
begin
if ARow = 0 then
Exit;
cellValue := myGrid.Cells[ACol, ARow];
case ACol of
0: ; // invisibe column, do nothing
1: cellText := cellValue;
2: begin
dateTime := StrToDateTime(cellValue);
cellText := DateTimeToStr(dateTime);
end;
3: cellText := cellValue;
4: cellText := cellValue;
end;
myGrid.Canvas.FillRect(Rect);
myGrid.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, cellText);
where column 2 is my timestamp, but is apparently empty.
So, my question is, can anyone correct this code snippet, or show me a code example of how to declare an Sqlite column which defaults to the current timestamp and how to display that in a DB aware grid? I am happy enough to store a Unix timestamp, if that would help.
Btw, I am using XE7, FireDac with a TMS TAdvDbGrid.
[Update] As mentioned it a comment thread below (and as perhaps ought to have been mentioned originally), in this case I am generating some dummy data for testing porpoises using a TDateTime and IncSecond(startTime, delay * i). So, effectively, I am writing a TDateTime to that field, then I close/open the datasource and all other fields of the new row are shown, but not that one.
But, that actually digresses from my original, "please provide an example" question and turns it into a "please fix my code" question. An answer to either will make me very happy.
You are looking in the wrong place, your problem is in the dataset. It is a generic problem for all datasets that get their data from an external database.
Your query/dataset has a copy of the data in your database. It gets that copy from the database when it is opened or when you use it to update/insert records into the database. If the data in the database is changed some other way, your dataset will not have those changes until the changed record(s) are re-read. This applies to you, because the timestamp value is being set in database, not through the dataset. This can be accomplished by closing then opening the dataset.
With FireDAC, try setting the query's UpdateOptions .RefreshMode := rmAll. It has worked for me when there is a single table in the query, i.e. no joins.

SQL Server 2005 - Pass In Name of Table to be Queried via Parameter

Here's the situation. Due to the design of the database I have to work with, I need to write a stored procedure in such a way that I can pass in the name of the table to be queried against if at all possible. The program in question does its processing by jobs, and each job gets its own table created in the database, IE table-jobid1, table-jobid2, table-jobid3, etc. Unfortunately, there's nothing I can do about this design - I'm stuck with it.
However, now, I need to do data mining against these individualized tables. I'd like to avoid doing the SQL in the code files at all costs if possible. Ideally, I'd like to have a stored procedure similar to:
SELECT *
FROM #TableName AS tbl
WHERE #Filter
Is this even possible in SQL Server 2005? Any help or suggestions would be greatly appreciated. Alternate ways to keep the SQL out of the code behind would be welcome too, if this isn't possible.
Thanks for your time.
best solution I can think of is to build your sql in the stored proc such as:
#query = 'SELECT * FROM ' + #TableName + ' as tbl WHERE ' + #Filter
exec(#query)
not an ideal solution probably, but it works.
The best answer I can think of is to build a view that unions all the tables together, with an id column in the view telling you where the data in the view came from. Then you can simply pass that id into a stored proc which will go against the view. This is assuming that the tables you are looking at all have identical schema.
example:
create view test1 as
select * , 'tbl1' as src
from job-1
union all
select * , 'tbl2' as src
from job-2
union all
select * , 'tbl3' as src
from job-3
Now you can select * from test1 where src = 'tbl3' and you will only get records from the table job-3
This would be a meaningless stored proc. Select from some table using some parameters? You are basically defining the entire query again in whatever you are using to call this proc, so you may as well generate the sql yourself.
the only reason I would do a dynamic sql writing proc is if you want to do something that you can change without redeploying your codebase.
But, in this case, you are just SELECT *'ing. You can't define the columns, where clause, or order by differently since you are trying to use it for multiple tables, so there is no meaningful change you could make to it.
In short: it's not even worth doing. Just slop down your table specific sprocs or write your sql in strings (but make sure it's parameterized) in your code.

Resources