MariaDB --init-command when invoking mysql from a BASH script - mysql

I am a new user on Stack Overflow, so I apologize in advance for any potential breaches of site etiquette.
I am attempting to create a BASH script that will generate a command to invoke the MariaDB monitor, i.e. mysql. I want this mysql command to include the --init-command option. I want the --init-command option to set a list of user variables to a their values, as specified in a configuration file.
The script builds a string that appears to be correct for my purpose but, when it invokes mysql, an error is generated. If I print out the generated string from the script, it appears to be exactly what I was attempting to create.
I have boiled it down to the following code example:
#!/bin/sh
declare foo="name"
declare bar="value"
declare invoke="mysql -p -D information_schema"
declare opts=" --init-command='SET #$foo:=\"$bar\"'"
invoke+=$opts
echo $invoke
$invoke
When I execute this script, the result looks like:
$ example.sh
mysql -p -D information_schema --init-command='SET #name:="value"'
Enter password:
ERROR 1044 (42000): Access denied for user 'Bill'#'%' to database '#name:="value"''
This error message doesn't even seem to make sense.
However, if I copy the generated command, and paste it back into the command prompt, it requests my password, and proceeds as I would expect, as follows:
$ mysql -p -D information_schema --init-command='SET #name:="value"'
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 171
Server version: 10.3.11-MariaDB Source distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [information_schema]> SELECT #name;
+-------+
| #name |
+-------+
| value |
+-------+
1 row in set (0.000 sec)
MariaDB [information_schema]>
Demonstrating that the SET command in the --init-command option was successfully passed to the MariaDB monitor, and executed.
I do not know whether this is a Linux issue, a BASH issue, or a MariaDB issue. So, while I have spent a good amount of time trying to find the answer, I really don't know where the problem originates, and therefore, where to focus my research.
Please note: I only used the information_schema database in my example because I expect that anyone attempting to recreate this problem would have that database available to them.
Thank you in advance for your assistance.

Some options:
Option 1:
#!/bin/sh
# USING BASH
# FILE: bash_mariadb.sh
foo="\`name\`"
bar="value"
mysql -p -D information_schema --init-command="SET #$foo:='$bar';"
Option 2:
#!/bin/sh
# USING BASH
# FILE: bash_mariadb.sh
foo="\`name\`"
bar="value"
opts=(--init-command="SET #$foo:='$bar';")
invoke=(mysql -p -D information_schema "$opts")
"${invoke[#]}"
Option 3:
#!/bin/sh
# USING BASH
# FILE: bash_mariadb.sh
foo="\`name\`"
bar="value"
#define
invoke() {
opts=(--init-command="SET #$foo:='$bar'")
if [[ -v opts ]]; then
invoke=(mysql -p -D information_schema "$opts")
else
invoke=(mysql -p -D information_schema)
fi
"${invoke[#]}"
}
#call
invoke
Option 4: DANGER, option not recommended for safety reasons.
#!/bin/sh
# USING BASH
# FILE: bash_mariadb.sh
foo="\`name\`"
bar="value"
invoke="mysql -p -D information_schema"
opts=" --init-command='SET #$foo:=\"$bar\"'"
invoke+=$opts
eval $invoke
In all cases:
$ ./bash_mariadb.sh
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 1
Server version: 10.3.11-MariaDB Source distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [information_schema]> SELECT #`name`;
+---------+
| #`name` |
+---------+
| value |
+---------+
1 row in set (0.000 sec)

Welcome to SO.
From a script you have to indicate the password you want to use.
The option -p force it for a interactive introduction of the password, wich don't works from a script.
If you instead use -ppassword (notice that you still write the "p", only that you write it next to the password, without spaces), your connection will work.
So, you just have to modify the line:
declare invoke="mysql -ppassword -D information_schema"
(Don't forget to write your password where I wrote "password", of course :) )

Related

Can't pass input from SQL dump file via arrow to mysql command within docker

I have MariaDB (foobar_db) running in local environment in Docker. I have a SQL file some_sql_dump.sql that I want to run on this database. This is what I tried:
docker exec -t container_id_here mysql -u root -prootpass foobar_db < some_sql_dump.sql
This takes me into MariaDB's monitor:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.4.13-MariaDB-1:10.4.13+maria~bionic mariadb.org binary distribution
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [foobar_db]>
It seems like using the arrow (<) to pass in input from some_sql_dump.sql did not work correctly. Why did the arrow not work, and how can I make it run the SQL from the file?
I have just used the "--interactive , -i" option and it seems to work.
$ docker exec -i {container_id} mysql -u root -prootpass foobar_db < some_sql_dump.sql

Connect to remote mysql database from within a container

From my local computer, I can easily connect to a remote instance of mysql database using the mysql cli command (assuming environment variables are set):
# mysql -u root -p$DB_PASSWORD -h $DB_HOST --port=$DB_PORT
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 7365
Server version: 5.7.14-google (Google)
Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.05 sec)
However, using docker it just hangs:
docker run --rm -it --name mysql -e MYSQL_RANDOM_ROOT_PASSWORD=yes mysql \
mysql -u root -p$DB_PASSWORD -h $DB_HOST --port=$DB_PORT
mysql: [Warning] Using a password on the command line interface can be insecure.
show databases;
^C
^C
exit
exit
^C
and have to docker container stop mysql from another terminal window for it to exit the mysql container.
I tried even attaching to the container and run the same command to no avail. Tried connecting to an AWS MySQL instance and Google Cloud SQL instance, also tried to enter variables directly in the command line all with the same result. Why is it hanging and how can I make it work? Thanks!
Try expose the default port for MySQL
docker run -p 3306:3306 ...
I was using Google Cloud SQL and the IP address needed to be whitelisted for it to allow access. So adding that solved the connection issue.
I tried all the ways but below step has resolved my issue.
run command inside container
dpkg-reconfigure tzdata
it will ask you to select for Geographical area and Time zone, then you are done.

Inserting user defined variable in mysql CREATE USER

I would like to create a shell script to run in docker CLI and create a MySQL user with the host IP passed as a command line variable.
So with my script it would be ./create_user.sh 172.17.0.1
I tried starting with inserting variable only in the sql statements part and using something like this:
#!/bin/sh
docker exec -i atb-mariadb bash <<'EOF'
mysql -uroot -pmypass
set #ip='172.17.0.1';
CREATE USER 'exporter'##ip IDENTIFIED BY 'mypass';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'exporter'#'172.17.0.1';
GRANT SELECT ON performance_schema.* TO 'exporter'#'172.17.0.1';
SELECT user, host FROM mysql.user;
exit
EOF
This results in syntax error, along with some others i tried :
CREATE USER CONCAT_WS('exporter','#',#ip) IDENTIFIED BY 'mypass';
CREATE USER 'exporter'#CONCAT_WS('',#ip) IDENTIFIED BY 'mypass';
This is of course only the variable within the sql statements part of the script. Using a variable in the overall shell script and passing that into the sql bash is a problem that I have not even been able to come to yet.
Thanks in advance for any help!
UPDATED
I tried Raymond Nijland's solution and it worked for the sql variable part. However, trying to pass the variable value through the command line is still failing for the following script:
#!/bin/sh
echo script received $1
docker exec -e ipa=$1 -i atb-mariadb bash <<'EOF'
echo exec received $ipa
mysql -uroot -pmypass -e "
SET #ip='${ipa}';
SET #createUser = 'CONCAT("CREATE USER exporter#",#ip,"IDENTIFIED BY'mypass'")';
PREPARE smtpCreateUser FROM #createUser;
EXECUTE smtpCreateUser;";
exit
EOF
with the output
$ ./create_user.sh 172.18.0.5
script received 172.18.0.5
exec received 172.18.0.5
mysql Ver 15.1 Distrib 10.2.9-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.
Usage: mysql [OPTIONS] [database]
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf
The following groups are read: mysql client client-server client-mariadb
The following options may be given as the first argument:
--print-defaults Print the program argument list and exit.
......and so on
I understad the usual approach is to run a separate .sql script file with the -e handle but unfortunately bind-mounting this file into the default mariadb container or creating a custom image are both not possible appraoches given the current requirements.
You should be able to generate dynamic SQL statements with CONCAT, PREPARE and execute them.
Query
SET #ip = '172.17.0.1';
SET #createUser = CONCAT(
"CREATE USER exporter#",#ip, " IDENTIFIED BY 'mypass'"
);
PREPARE smtpCreateUser FROM #createUser;
EXECUTE smtpCreateUser;
You need to grab the variable from the shell before it can be used in the query. I think you are looking for something like (make sure to remove the quotes from EOF):
#!/bin/sh
docker exec -i atb-mariadb bash <<EOF
ip="${1:-127.0.0.1}"
echo mysql -uroot -pmypass
echo CREATE USER 'exporter'#'${ip}' IDENTIFIED BY 'mypass';
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'exporter'#'172.17.0.1';
GRANT SELECT ON performance_schema.* TO 'exporter'#'172.17.0.1';
SELECT user, host FROM mysql.user;
exit
EOF

On MySql Is it possible to GRANT Select to ALL users?

My question is simple, can I GRANT permission to ALL (as in any user with any pwd coming from any machine) users ?
I know it COULD BE problematic in some cases. But ours is a demo database, with users unknown. So please spare us the rod.
From what I know and what I have tried the Answer is NO, we can not do it. I am posting this question to confirm my understanding.
AFAIK, we can't. Is there a way to hack around this ?
As people have said in the comments - this is probably a bad idea. But, I thought, why not have a crack and see how it can be done.
The most simple place to start would be to create a MySQL user without a username:
GRANT ALL ON *.* TO ''#'%' IDENTIFIED BY '';
This will let you login with any username - and a blank password. This might be what some people are looking for - but it sounds like you want any username any password.
To do that - I suggest using mysql-proxy. I would download the source code. If you're on Ubuntu then you will need the following packages to build it:
apt-get install libmysqlclient-dev \
pkg-config \
lua5.1 liblua5.1-0-dev liblua5.1-0 \
libglib2.0-dev \
libevent-1.4-2 libevent1-dev
If you do compile it then you'll need to run /sbin/ldconfig afterwards as root.
Then we can write a lua script to set the username and password for every connection. The mysql-proxy client has some example scripts, but the relevant examples/tutorial-scramble.lua file is old and doesn't work with the current version. You can use the following script:
local CLIENT_PROTOCOL_41 = 512 -- New 4.1 protocol
local CLIENT_SECURE_CONNECTION = 32768 -- New 4.1 authentication
local MYSQL_AUTH_CAPABILITIES = ( CLIENT_PROTOCOL_41 + CLIENT_SECURE_CONNECTION )
local password = assert(require("mysql.password"))
local proto = assert(require("mysql.proto"))
function read_auth()
local c = proxy.connection.client
local s = proxy.connection.server
local challenge = (s.scramble_buffer):sub(1,20)
local default_username = "foo"
local default_password = "bar"
proxy.queries:append(1,
proto.to_response_packet({
username = default_username,
response = password.scramble(challenge, password.hash(default_password)),
charset = 8, -- default charset
database = c.default_db,
max_packet_size = 1 * 1024 * 1024,
server_capabilities = MYSQL_AUTH_CAPABILITIES
})
)
return proxy.PROXY_SEND_QUERY
end
Save this as any-user-any-pass.lua or something. Then you will need to create the user in the database which I refer to in the script (username foo, password bar):
GRANT ALL ON *.* TO 'foo'#'localhost' IDENTIFIED BY 'bar';
Then we can start up mysql-proxy - we will connect it to the local mysql server on port 3306 and it will listen on port 3307. Use a command similar to this:
mysql-proxy --proxy-lua-script=`pwd`/any-user-any-pass.lua \
--proxy-backend-addresses=localhost:3306 \
--proxy-address=localhost:3307
Test it out in a different terminal:
ubuntu#test:~$ mysql -h 127.0.0.1 -P 3306 -u ANYTHING -pSOMETHING
ERROR 1045 (28000): Access denied for user 'ANYTHING'#'localhost' (using password: YES)
ubuntu#test:~$ mysql -h 127.0.0.1 -P 3307 -u ANYTHING -pSOMETHING
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 752
Server version: 5.5.29-0ubuntu1 (Ubuntu)
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> SELECT CURRENT_USER();
+----------------+
| CURRENT_USER() |
+----------------+
| foo#localhost |
+----------------+
1 row in set (0.00 sec)
mysql>
As you can see - first I test connecting straight to MySQL - it rejects the ANYTHING/SOMETHING credentials. Then I connect to the MySQL proxy on 3307 and it lets me straight in because the lua script is changing the username and password the connection is using.

mysql command line to vertical output

I'd like to get the result of a mysql query with a vertical output.
My problem when using --vertical (or G) is the starred lines.
$mysql -N -e 'select filed1, field2 from db.tlb\G'
*************************** 1. row ***************************
value1_field1
value1_field2
*************************** 2. row ***************************
value2_field1
value2_field2
...
Is there an option I didn't find to get rid of the lines ***[...] x. row [...]*** ?
At the moment, I'm using a egrep -v '^\*.*\*$', but I'm sure a better solution exists.
I'm not sure this is a good solution, but if explicitly using egrep is annoying, you could define a shell function to launch mysql with the desired pager. Assuming you're using a bash (or compatible):
# define a shell function to launch mysql with the required _pager_
sh$ mysql() { `which mysql` $* --pager="egrep -v '^\*.*\*$'" ; }
[ ... ]
# launch mysql "as usual" (in reality, this is the shell function that is invoked)
sh$ mysql -u user -p -h mysql-host mydb
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 67
Server version: 5.1.49-3 (Debian)
-- Use mysql normally -- but the "egrep pager" will remove the "star lines"
mysql> select * from T\G
col1: w
col2: x
col3: 0.4
1 row in set (0.00 sec)
As I said before, this is not a perfect solution since egrep will blindly remove from output any "star line" -- not only the one from an ego (\G) command.
try this (but I can not imagine why you need such an output)
mysql -N -B -e 'select * from db' mysql | tr "\t" "\n"
First Option
would be to change the MySQL pager like so:
test.sh
#!/usr/bin/env bash
# Some Basic Configuration
db="homestead"
dbuser="homestead"
dbhost="127.0.0.1"
# Executes the MySQL command using the basic configuration
# This also sets the MySql Pager to less -Sin to enable
# it also removes all lines starting with "*"
mysql -h $dbhost -u $dbuser -p --pager="grep -Ev '(^\*.*$)|(^$)' | less -Sin" $db
Usage
Firstly Edit the Config variables:
$ nano ./test.sh
Secondly Run the script
$ bash ./test.sh
Second Option
Change the pager after you're already in the MySQL CLI
$ mysql -u root -p -h 127.0.0.1 somedatabase
enter password:
mysql> pager grep -Ev '(^\*.*$)|(^$)' | less -Sin