How to switch between databases using GORM in golang? - mysql

I'm new to GORM in golang. I'm stuck at a point. Generally we select the database like this:
DBGorm, err = gorm.Open("mysql", user:password#tcp(host:port)/db_name)
But my problem is I'll get the 'db_name' in the request, which means I don't know which db_name might come and I'll have to query according to that db_name.
So now, I'll create the database pointer in the init function like this:
DBGorm, err = gorm.Open("mysql", user:password#tcp(host:port)/) which is without the db_name.
Now how will I switch to db_name coming to me in request. Because when I try to do DBGorm.Create(&con), it shows No database selected.
If I use 'database/sql', then I can make raw queries like this: "SELECT * FROM db_name.table_name", this can solve my problem. But how to do this in gorm?

You can explicitly specify db_name and table_name using .Table() when doing query or other operation on table.
DBGorm.Table("db_name.table_name").Create(&con)

I saw a related article on Github. https://github.com/go-sql-driver/mysql/issues/173#issuecomment-427721651
All you need to do is
start a transaction,
set you database
run your desired query.
and switch back to your desired DB
commit once you are done.
below is an example
tx := db.Begin() // start transaction
tx.Exec("use " + userDB) // switch to tenant db
tx.Exec("insert into ....") // do some work
tx.Exec("use `no-op-db`") // switch away from tenant db (there is no unuse, so I just use a dummy)
tx.Commit() // end transaction

Related

how to excute conjunctive query crossing two mysql databases with gorm?

code like:
addr:=fmt.Sprintf(`%v:%v#tcp(%v:%v)/(%v,%v)?charset=utf8`, dbuser, dbpassword, dbhost, dbport, dbdatabase)
DB, err = gorm.Open("mysql", addr)
sql := "select * from db1.user join db2.salary"
rows, err := DB.Raw(sql).Rows()
it seems the method gorm.Open() only accept one source parameter, and it run error "unknown table name 'db1.user'"
is there a correct way to init the DB to excute the sql or other way to solve the problem?
many thanks
sovled by setting dbdatabase="" , which it means giving null database name connecting to the mysql instance. And database name shoud be presented as prefix on table name in sql.

Parse SQL query before it goes to MySQL

In my Go app I want to be able to analyze a SQL query before to execute it.
I want to get:
type (update, insert, delete etc). This is easy, but next steps not.
table to be affected,
columns to be updated (on insert/update)
most important - condition, list of columns and values.
Is there any go library for this?
Something to pass a sql query and get back some structure with info about this query
Yes, you have sqlparser for golang.
Note that the sqlparser is been pulled out from the database clustering system vitess
You can use the sql parser like,
reader := strings.NewReader("INSERT INTO table1 VALUES (1, 'a');")
tokens := sqlparser.NewTokenizer(reader)
for {
stmt, err := sqlparser.ParseNext(tokens)
if err == io.EOF {
break
}
// Do your logics with the statements.
}

How to update a row in a MySQL database using Ruby's Sequel toolkit?

This should be the simplest thing but for some reason it's eluding me completely.
I have a Sequel connection to a database named DB. It's using the Mysql2 engine if that's important.
I'm trying to update a single record in a table in the database. The short loop I'm using looks like this:
dataset = DB["SELECT post_id, message FROM xf_post WHERE message LIKE '%#{match}%'"]
dataset.each do |row|
new_message = process_message(row[:message])
# HERE IS WHERE I WANT TO UPDATE THE ROW IN THE DATABASE!
end
I've tried:
dataset.where('post_id = ?', row[:post_id]).update(message: new_message)
Which is what the Sequel cheat sheet recommends.
And:
DB["UPDATE xf_post SET message = ? WHERE post_id = ?", new_message, row[:post_id]]
Which should be raw SQL executed by the Sequel connector. Neither throws an error or outputs any error message (I'm using a logger with the Sequel connection). But both calls fail to update the records in the database. The data is unchanged when I query the database after running the code.
How can I make the update call function properly here?
Your problem is you are using a raw SQL dataset, so the where call isn't going to change the SQL, and update is just going to execute the raw SQL. Here's what you want to do:
dataset = DB[:xf_post].select(:post_id, :message).
where(Sequel.like(:message, "%#{match}%"))
That will make the where/update combination work.
Note that your original code has a trivial SQL injection vulnerability if match depends on user input, which this new code avoids. You may want to consider using Dataset#escape_like if you want to escape metacharacters inside match, otherwise if match depends on user input, it's possible for users to use very complex matching syntax that the database may execute slowly or not handle properly.
Note that the reason that
DB["UPDATE xf_post SET message = ? WHERE post_id = ?", new_message, row[:post_id]]
doesn't work is because it only creates a dataset, it doesn't execute it. You can actually call update on that dataset to run the query and return number of affected rows.

Delphi ListBox to a Text file with a specific string

I am still fairly new to Delphi and learning new things every day.
What I am trying to do is generate multiple MySQL queries into a .txt that I can have backed up for when I need them.
Basically I have the following setup.
A VCL program that currently at the click of a button captures the list of tables that exist on my one database.
The tables are listed into a ListBox and gives me a count of the total tables that I have.
Now how would I go about doing the following:
I want it to capture the name of the first item in the ListBox and then create a .txt file and insert the name of the item into a specific text string, eg:
mysqldump -uroot -pxxxx -D[]database [tablename] > [tablename]
The sections where it is in [] I need the item from the ListBox being inserted there and need this to repeat onto the next time.
I have 249 tables that I need to generate these queries for and someone suggested that I can do a Delphi app that can do this pretty quickly and automated for me. It is basically for a large scale table dump and then import.
I know this is really long winded and just looking for some guidelines and tips on how I can do this.
I am doing this locally and I do not wish to use myDAC or FireDAC I would like it to be done locally without needed to access the database through MySQL or anything of the such. Just want it to generate my queries to a .txt file.
Try something like this:
var
DBName, TableName: string;
SL: TStringList;
begin
DBName := 'yourdbname';
TableName := ListBox1.Items[0];
SL := TStringList.Create;
try
SL.Add(Format('mysqldump -uroot -pxxxx -D%s %s > %1:s', [DBName, TableName]));
SL.SaveToFile('c:\folder\query.txt');
finally
SL.Free;
end;
end;
IF I understood you right, you have a TListBox with table names from which you want to create queries. You did not
In that case, you need something like this:
var F : TexFile;
I : integer;
begin
AssignFile(F, 'queries.txt');
Rewrite(F);
for I := 0 to ListBox1.Items.Count - 1 do
Writeln(F, 'mysqldump -uroot -pxxxx -D[database] ['+ListBox1.Items[I]+'] > ['+ListBox1.Items[I]+']');
CloseFile(F);
end;
To make strings like that I would suggest using the format function.
All you'll need is the SysUtils unit.
It would make your code look like this:
Table1 := 'FirstTable';
Table2 := 'SecondTable';
Format('mysqldump -uroot -pxxxx -D[]database %s > %s', [Table1, Table2]);
//Results in mysqldump -uroot -pxxxx -D[]database FirstTable > SecondTable
Just simply replace the Table1 and Table2 with the text of the selected item in your listbox.
Hope this helped you in any way :)

store mysql query information chef

I am trying to query my mysql database. I am using the database cookbook and can setup a connection with my database. I trying to query my database for information so now the question is how do I store than information so I can access it in another resource. Where do the results of the query get stored? This is my recipe:
mysql_database "Get admin users" do
connection mysql_connection_info
sql "Select * from #{table_name}"
action :query
end
Thanks in advance
If you don't have experience with Ruby, this might be really confusing. There's no way to "return" the result of a provider from a Chef resource. The mysql_database is a Chef::Recipe DSL method that gets translated to Chef::Provider::Database::Mysql at runtime. This provider is defined in the cookbook.
If you take some time to dive into that provider, you'll can see how it executes queries, using the db object. In order to get the results of a query, you'll need to create your own connection object in the recipe and execute a command against it. For example
require 'mysql'
db = ::Mysql.new('host', 'username', 'password', nil, 'port', 'socket') # varies with setup
users = db.query('SELECT * FROM users')
#
# You might need to manipulate the result into a more manageable data
# structure by splitting on a carriage return, etc...
#
# Assume the new object is an Array where each entry is a username.
#
file '/etc/group' do
contents users.join("\n")
end
I find using good old Chef::Mixin:ShellOut / shell_out() fairly sufficient for this job and it's DB agnostic (assuming you know your SQL :) ). It works particularly well if all you are querying is one value; for multiple rows/columns you will need to parse the SQL query results. You need to hide row counts, column headers, eat preceding white-space, etc. from your result set to just get the query results you want. For example, below works on SQL Server :
Single item
so = shell_out!("sqlcmd ... -Q \"set nocount on; select file_name(1)\" -h-1 -W")
db_logical_name = so.stdout.chop
Multiple rows/columns (0-based position of a value within a row tells you what this column is)
so = shell_out!("sqlcmd ... -Q \"set nocount on; select * from my_table\" -h-1 -W")
rows_column_data = so.stdout.chop
# columns within rows are space separated, so can be easily parsed