I'm in the process of upgrading our in-house applications from MySQL 5.0.45 to 5.1.41. In the old environment we had mirrored some tables using symlinks from one DB to another. For a few reasons, current versions of MySQL block that completely.
What seemed like the best replacement was using a view instead, but I'm having a problem. A few old tables have column names that are capitalized. However some of our application code (PHP) does a SELECT with the capitalized name and also some SELECTs with lower case column names. Which normally works fine because MySQL returns tables with a column name capitalized as you referenced it in the SELECT. However, with a view that doesn't seem to be the case. See the following:
create table t(A int);
Query OK, 0 rows affected (0.18 sec)
> create view v as select A from t;
Query OK, 0 rows affected (0.00 sec)
> insert into t values(47);
Query OK, 1 row affected (0.01 sec)
> select a from t;
+------+
| a |
+------+
| 47 |
+------+
1 row in set (0.00 sec)
> select a from v;
+------+
| A |
+------+
| 47 |
+------+
1 row in set (0.00 sec)
Notice that the capitalization of the column name returned in the SELECT queries is different whether or not you select from the table or the view. The table returns the capitalization as specified in your query at runtime; the view returns the capitalization when the view was created. This seems to be consistent through both versions of MySQL, both the command-line client and through the PHP library client.
One trick I discovered is that if you add a GROUP BY to the SELECT in the view it will use the capitalization in your query at runtime. Unfortunately that breaks updating through the view, which I need.
Is there any way to make the column name capitalization match the query at runtime, which doesn't involve going back and changing all of our application code?
I have to say I'm not 100 % sure, but I strongly suspect you can't get a matching case in your views without modifying the application code. Have a look at how the view is defined (I'm using MySQL 5.1.56):
mysql> show create view v;
+------+-----------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| View | Create View | character_set_client | collation_connection |
+------+-----------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| v | CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`localhost` SQL SECURITY DEFINER VIEW `v` AS select `t`.`A` AS `A` from `t` | utf8 | utf8_general_ci |
+------+-----------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
1 row in set (0.00 sec)
As you can see, MySQL adds a column alias (AS), and AFAIK there's no way to make it behave differently. Defining a column name explicitly has the same result:
mysql> create view v2 (viewa) as select A from t;
Query OK, 0 rows affected (0.02 sec)
mysql> select Viewa from v2;
+-------+
| viewa |
+-------+
| 47 |
+-------+
1 row in set (0.00 sec)
mysql> show create view v2;
+------+----------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| View | Create View | character_set_client | collation_connection |
+------+----------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| v2 | CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t`.`A` AS `viewa` from `t` | utf8 | utf8_general_ci |
+------+----------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
1 row in set (0.00 sec)
Adding a (somewhat funny-looking) column alias in all your SQL queries would obviously fix the issue:
mysql> select a as a from v;
+------+
| a |
+------+
| 47 |
+------+
1 row in set (0.00 sec)
instead of,
mysql> select a from v;
use this (with an alias),
mysql> select a as a from v;
+------+
| a |
+------+
| 47 |
+------+
1 row in set (0.00 sec)
you must be use Mysql column alias like this:
select a as a from v;
Related
I am running MySQL in Ubuntu. I getting this error while running specific set of queries.
The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
When I did SELECT ##secure_file_priv; in my mysql server I got /var/lib/mysql-files/. I think I need to make this to NULL.
This is the query I am running:
LOAD DATA INFILE :file INTO TABLE test_files
COLUMNS TERMINATED BY ',' ENCLOSED BY '\"'
LINES TERMINATED BY '\n';
Now the question is how to make this NULL?
Try:
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.7.12-0 |
+-----------+
1 row in set (0.00 sec)
mysql> SELECT ##GLOBAL.secure_file_priv;
+---------------------------+
| ##GLOBAL.secure_file_priv |
+---------------------------+
| /var/lib/mysql-files/ |
+---------------------------+
1 row in set (0.00 sec)
Change file: /etc/mysql/my.cnf
[mysqld]
.
.
.
secure_file_priv=NULL
.
.
.
Restart MySQL.
mysql> SELECT ##GLOBAL.secure_file_priv;
+---------------------------+
| ##GLOBAL.secure_file_priv |
+---------------------------+
| NULL |
+---------------------------+
1 row in set (0.00 sec)
UPDATE
mysql> SELECT ##GLOBAL.secure_file_priv;
+---------------------------+
| ##GLOBAL.secure_file_priv |
+---------------------------+
| /var/lib/mysql-files/ |
+---------------------------+
1 row in set (0.00 sec)
File: /var/lib/mysql-files/myfile.csv
1,"Row 1"
2,"Row 2"
3,"Row 3"
mysql> DROP TABLE IF EXISTS `test_files`;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> CREATE TABLE IF NOT EXISTS `test_files` (
-> `col0` INT,
-> `col1` VARCHAR(20)
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> LOAD DATA INFILE '/var/lib/mysql-files/myfile.csv'
-> INTO TABLE `test_files`
-> COLUMNS TERMINATED BY ',' ENCLOSED BY '\"'
-> LINES TERMINATED BY '\n';
Query OK, 3 rows affected (0.01 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0
mysql> SELECT
-> `col0`,
-> `col1`
-> FROM
-> `test_files`;
+------+-------+
| col0 | col1 |
+------+-------+
| 1 | Row 1 |
| 2 | Row 2 |
| 3 | Row 3 |
+------+-------+
3 rows in set (0.00 sec)
Thank you wchiquito for your solution, which has led me in the right direction.
I would like to add a solution for MySQL 8 under Windows 10. In which a few points differ.
The my.ini file can be found in a different location:
C:\ProgramData\MySQL\MySQL Server 8.x\my.ini
A longer description can be found here: https://stackoverflow.com/a/20136523/1316649
The variable to be changed is called secure-file-priv and it must be unset.
[mysqld]
...
secure-file-priv=
...
After restarting MySQL under services you can check with
SELECT LOAD_FILE ('C:\\path\\to\\file\\content.txt');
SELECT LOAD_FILE ('C:/path/to/file/content.txt');
whether the file is loaded. The content should be visible here, not NULL. A simple backslash doesn't work for me.
I'm trying to use PHP instead of MYSQL to add key values in database
select unhex(md5('google.com')) from x;
Output
HVkg9LRLJ6gCvXfE8FNvWg==
however using PHP
echo hex2bin((md5("google.com")));
Output
Y ��K'��w��SoZ
I'm not sure what is going wrong here, any help ?
Edit1
Joachim Isaksson
I'm not sure how you're getting that value, however doing your select at a MySQL prompt gives the same value as in PHP;
mysql> select unhex(md5('google.com'));
+--------------------------+
| unhex(md5('google.com')) |
+--------------------------+
| Y �K'��w��SoZ |
+--------------------------+
1 row in set (0.00 sec)
What you're displaying is the base64 encoded value of the same thing;
mysql> select to_base64(unhex(md5('google.com')));
+-------------------------------------+
| to_base64(unhex(md5('google.com'))) |
+-------------------------------------+
| HVkg9LRLJ6gCvXfE8FNvWg== |
+-------------------------------------+
1 row in set (0.00 sec)
How your value gets base64 encoded I'm not sure, however it seems to have nothing to do with the MySQL query you're showing. It may be caused by how you're fetching the value in PHP.
I have a problem, I'm using mysql with PHP and I have in my database timestamp columns that are automatically set on update by the current timestamp. But when I'm trying to insert rows into the table the rows are added with timestamp different from my current time (before two hours) I have the EST timezone.
I've checked the timezone for the database and it is System and when I searched for that I read that it depeneds on the machine that is connecting, but my machine has EST time, so can anyone explain why I'm having this? and what can I do to set the current timestamp for my database to EST?
I've personally found it to be a lot more reliable to set the timezone in PHP, then grab the timestamp there and pass this to your MySQL query.
Something like:
date_default_timezone_set('America/New_York');
$curtimestamp = date('Y-m-d G:i:s', time());
Then use the value of $curtimestamp in your queries.
The documentation may have been unclear.
time_zone=SYSTEM means that the MySQL Server time zone is derived from the host that the MySQL Server is running on, not the client system.
So, if the time zone on the MySQL server host is different from the time zone of the client host, that explains the behavior that you observe.
Each client (database session) has its own time_zone setting. When the connection is established, the setting is derived from the "default" time zone for the MySQL server.
The setting of this variable determines how DATETIME and TIMESTAMP values are interpreted, when values are sent to the database from the client, AND when existing values are pulled from the database.
A client can issue a SET time_zone statement to change the time_zone for the database session, e.g.
SET time_zone=CST6CDT
(Note that to use named values for time zones, the time_zone% tables in the mysql database must be populated.)
To set the "default" time_zone that will be used for new database connections, you can set the "global" time_zone variable:
SET GLOBAL time_zone=
(This change requires SUPER privilege, and it impacts ALL new database connections to the entire instance. Normally, this value is set in the MySQL server configuration file.)
For TIMESTAMP columns, MySQL stores those as UTC. The values returned to the client depend on the setting of the client time_zone. As a simple demonstration:
mysql> CREATE TABLE mytest
-> ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
-> , ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-> );
Query OK, 0 rows affected (0.11 sec)
mysql> SHOW VARIABLES LIKE 'time_zone';
+---------------+--------+
| Variable_name | Value |
+---------------+--------+
| time_zone | +00:00 |
+---------------+--------+
1 row in set (0.00 sec)
mysql> INSERT INTO mytest (id) VALUES (NULL);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM mytest;
+----+---------------------+
| id | ts |
+----+---------------------+
| 1 | 2015-01-09 15:41:25 |
+----+---------------------+
1 row in set (0.00 sec)
mysql> SET time_zone = 'CST6CDT';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM mytest;
+----+---------------------+
| id | ts |
+----+---------------------+
| 1 | 2015-01-09 09:41:25 |
+----+---------------------+
1 row in set (0.00 sec)
mysql> INSERT INTO mytest (id) VALUES (NULL);
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM mytest;
+----+---------------------+
| id | ts |
+----+---------------------+
| 1 | 2015-01-09 09:41:25 |
| 2 | 2015-01-09 09:41:25 |
+----+---------------------+
2 rows in set (0.00 sec)
mysql> SET time_zone = 'EST5EDT';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM mytest;
+----+---------------------+
| id | ts |
+----+---------------------+
| 1 | 2015-01-09 10:41:25 |
| 2 | 2015-01-09 10:41:25 |
+----+---------------------+
2 rows in set (0.00 sec)
I have a MySQL table like that is structured like this:
| uri | title |
_________________ _____________
Latest-Update Latest Update
Latest Update
where the uri column is an INDEX. I have occassional injections I perform into a mysql table, and the ERROR Duplicate Entry appears if i have 1 or more URI's with the same name. So i use PHP for the inejction, and want to append a date("m-d-y") to the end of the variable $uri when being inserted. My INSERT statement INSERT INTO table(uri,title) values('$uri', '$title'). I want to see if in the table that is being inserted to, before the INSERT happens, if i can tell if the $uri value already exists in the uri table, and if so, that variable will become $uri = $uri."-"date("m-d-y"); How can i tell? I have done some research and lead me to believe i should be using INSERT...ON DUPLICATE KEY UPDATE?
Most probably this could be due to your uri being a primary key. For this, you should probably create a surrogate key and that would allow duplication. If that is indeed what you need.
Not sure if you are interested in Triggers but you can depend on BEFORE INSERT trigger. Trigger requires to check if new uri being inserted has a dup entry and if yes, append dateStringOfYourFormat and insert.
Example:
mysql> drop table mytable;
Query OK, 0 rows affected (0.03 sec)
mysql> create table mytable( uri varchar(128) );
Query OK, 0 rows affected (0.05 sec)
mysql> drop trigger uri_modifier;
ERROR 1360 (HY000): Trigger does not exist
mysql> delimiter //
mysql> create trigger uri_modifier before insert on mytable
-> for each row
-> begin
-> if ( select count(uri) from mytable where uri=NEW.uri ) > 0 then
-> set #modified_uri_string=concat(NEW.uri, '-', date_add(sysdate(), interval floor(rand()*1e6) microsecond));
-> set NEW.uri=#modified_uri_string;
-> end if;
-> end//
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> delimiter ;
mysql>
mysql> set #my_new_uri_string = 'my_uri_string_to_search';
Query OK, 0 rows affected (0.00 sec)
mysql> set #modified_uri_string = #my_new_uri_string;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from mytable;
Empty set (0.00 sec)
mysql> insert into mytable values(#my_new_uri_string);
Query OK, 1 row affected (0.03 sec)
mysql> select #my_new_uri_string, #modified_uri_string;
+-------------------------+-------------------------+
| #my_new_uri_string | #modified_uri_string |
+-------------------------+-------------------------+
| my_uri_string_to_search | my_uri_string_to_search |
+-------------------------+-------------------------+
1 row in set (0.00 sec)
mysql> select * from mytable;
+-------------------------+
| uri |
+-------------------------+
| my_uri_string_to_search |
+-------------------------+
1 row in set (0.00 sec)
mysql> insert into mytable values(#my_new_uri_string);
Query OK, 1 row affected (0.03 sec)
mysql> select #my_new_uri_string, #modified_uri_string;
+-------------------------+----------------------------------------------------+
| #my_new_uri_string | #modified_uri_string |
+-------------------------+----------------------------------------------------+
| my_uri_string_to_search | my_uri_string_to_search-2012-05-03 02:21:39.983405 |
+-------------------------+----------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from mytable;
+----------------------------------------------------+
| uri |
+----------------------------------------------------+
| my_uri_string_to_search |
| my_uri_string_to_search-2012-05-03 02:21:39.983405 |
+----------------------------------------------------+
2 rows in set (0.02 sec)
mysql> insert into mytable values(#my_new_uri_string);
Query OK, 1 row affected (0.01 sec)
mysql> select #my_new_uri_string, #modified_uri_string;
+-------------------------+----------------------------------------------------+
| #my_new_uri_string | #modified_uri_string |
+-------------------------+----------------------------------------------------+
| my_uri_string_to_search | my_uri_string_to_search-2012-05-03 02:21:39.412580 |
+-------------------------+----------------------------------------------------+
1 row in set (0.00 sec)
mysql> select * from mytable;
+----------------------------------------------------+
| uri |
+----------------------------------------------------+
| my_uri_string_to_search |
| my_uri_string_to_search-2012-05-03 02:21:39.983405 |
| my_uri_string_to_search-2012-05-03 02:21:39.412580 |
+----------------------------------------------------+
3 rows in set (0.00 sec)
mysql>
mysql>
Make sure that if uri inserted is different than what passed in, you have a handle to know what the modified value is.
UPDATE I have filed a bug in Doctrine about this http://www.doctrine-project.org/jira/browse/DC-400
I have the following Doctrine schema:
---
TestTable:
columns:
bitty: bit(1)
I have created the database and table for this. I then have the following PHP code:
$obj1 = new TestTable();
$obj1['bitty'] = b'0';
$obj1->save();
$obj2 = new TestTable();
$obj2['bitty'] = 0;
$obj2->save();
Clearly my attempt is to save the bit value 0 in the bitty column.
However after running this PHP code I get the following odd results:
mysql> select * from test_table;
+----+-------+
| id | bitty |
+----+-------+
| 1 | |
| 2 | |
+----+-------+
2 rows in set (0.00 sec)
mysql> select * from test_table where bitty = 1;
+----+-------+
| id | bitty |
+----+-------+
| 1 | |
| 2 | |
+---+-------+
2 rows in set (0.00 sec)
mysql> select * from test_table where bitty = 0;
Empty set (0.00 sec)
Those boxes are the 0x01 character, i.e. Doctrine has set the value to 1, not 0.
However I can insert 0's into that table direct from MySQL:
mysql> insert into test_table values (4, b'0');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test_table where bitty = 0;
+----+-------+
| id | bitty |
+----+-------+
| 4 | |
+----+-------+
1 row in set (0.00 sec)
What's going on? Is this a bug in Doctrine?
There is nothing in the doctrine documentation that says Bit is a legal type.
Doctrine does know the bit type - at least if you're using MySQL and generate Doctrine models from the existing tables.
I tried to read a few bit columns and dump the resulting objects. Basically the bit value returned is either \0 or \1, instead of 0 and 1 as I expected.