Problem with JSON_EXTRACT in two similar enviroments - mysql

I'm using mysql 5.7 in two enviroments (staging and prod)
both with this same version
but when I try this query:
SELECT * FROM `EVENT_ONDEMAND_MODULE_CONTENT`
WHERE JSON_EXTRACT(EXTRA_INFO, '$.UPLOAD_ID') = 'Jh24ACh59sJ6mSSpQKXORJVscmy2iD3Dy1B0115L01hbI';
In staging that works, but in production I got this error:
SQLSTATE[22032]: <>: 3141 Invalid JSON text in argument 1 to function json_extract: "Invalid escape character in string."
{"UPLOAD_ID":"Jh24ACh59sJ6mSSpQKXORJVscmy2iD3Dy1B0115L01hbI","POLICY":"signed","FILE_NAME":"VIDEO 10s.mp4","FILE_MIME_TYPE":"video\/mp4","READY":false}
I copy the json from prod to staging and the query worked too.
Anybody knows if have something I must do to this function Json_extract work in prod??
Thanks in advance!

Related

Converting raw laravel mysql json query into postgres syntax

I have the following query that works in MYSQL
$query->whereRaw('
ST_Distance_Sphere(
point(address->>"$.longitude", address->>"$.latitude"),
point(?, ?)
) * .000621371192 < ?
', [$longitude, $latitude, $distance]);
When i deployed to heroku im getting this error
SQLSTATE[42703]: Undefined column: 7 ERROR: column "$.longitude" does not exist
LINE 3: point(address->>"$.longitude", address->>"$.latitu...
Im using postgres on heroku and i know the issue is something to do with the json operator.
What is the $.<json key> syntax called? and how do i convert this raw sql query to postgres?
In the worse case i leaning on switching my database to mysql if i cant solve this by Wednesday as it wont be a big deal
Postgres uses double quotes as delimiter for columns, so you must use single quotes to indicate strings. Laravel will take care of it
st_distance_sphere(
st_point(address->>'$.longitude',address->>'$.latitude'),st_point(?, ?)
)

How to use REGEXP_SUBSTR or REGEXP_EXTRACT in MySQL Workbench with database hosted on Google Cloud SQL?

I am working on a MYSQL database which is hosted on Google Cloud SQL. I am working through MySQL Workbench 8.0 CE.
I want to get a substring of the element_name column in the table p0999_pakbon in the schema projects.
Element names are like "LVLS 45 Beam 1" and "SPANO 18 Stud 1". I want to get: "LVLS 45" and "SPANO 18"
In an old copy of the database which is hosted on my local machine, the following code works perfectly:
SELECT REGEXP_SUBSTR(pp.element_name, "[A-Z]+[:space:][0-9]+")
FROM projects.p0999_pakbon pp
This is because REGEXP_SUBSTR is the standard function to get a substring in MySQL.
However, this code does not work in my database hosted in Google Cloud SQL. On this page https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#regexp_extract I seem to read that Google Cloud SQL uses REGEXP__EXTRACT instead. But also when I try the following:
SELECT REGEXP_EXTRACT(pp.element_name, "[A-Z]+[:space:][0-9]+")
FROM projects.p0999_pakbon pp
It does not work. It also doesn't work when I change the regex to a very simple one like "A".
I am getting these errors:
FUNCTION projects.REGEXP_SUBSTR does not exist
FUNCTION projects.REGEXP_EXTRACT does not exist
When I type the arguments in the wrong format, I get this error message:
Incorrect parameters in the call to stored fucntion 'REGEXP_EXTRACT'
Does anybody know how to solve my problem? Or maybe there is a workaround?
Assuming you just want the first two words, you could use SUBSTRING_INDEX here, which should work on most versions of MySQL:
SELECT SUBSTRING_INDEX('LVLS 45 Beam 1', ' ', 2) AS item
FROM yourTable;
If you also need to assert that the first term contains capitals, with the second digits, you could use REGEXP:
SELECT
CASE WHEN 'LVLS 45 Beam 1' REGEXP '^[A-Z]+ [0-9]+'
THEN SUBSTRING_INDEX('LVLS 45 Beam 1', ' ', 2)
ELSE 'no match' END AS item
FROM yourTable;

Json_object in Oracle returns ORA-00907: missing right parenthesis

I am trying to convert Oracle table data into JSON files. I have three databases and the below code gives output as JSON file in one DB but the other two databases throw ORA-00907: missing right parenthesis error.
Syntactically it is correct, as it gave output in one DB. Don't understand what is going wrong.
This is in Oracle DB, How do I find out which version of Oracle is installed in those DB's and if they are 12.2 and above, Is there a way to fix this issue? All I want is to convert the output of a select statement to a json file. Thanks in advance
code:
SELECT JSON_OBJECT ( 'empid' value eid , 'name' value ename , 'add' value eaddr )
FROM abc.emp
JSON_Object is available from Oracle version 12.2 .
Run the query Select * from v$version to check your oracle version

Perl DBI (MySQL) puts single quote instead of actual parameter in prepared statement

I'm trying to do a simple query as prepared statement but have no success. Here is the code:
package sqltest;
use DBI;
DBI->trace(2);
my $dbh = DBI->connect('dbi:mysql:database=test;host=***;port=3306','the_username', '****');
my $prep = 'SELECT me.id, me.session_data, me.expires FROM sys_session me WHERE me.id = ?';
$dbh->{RaiseError} = 1;
my $sth = $dbh->prepare($prep);
$sth->bind_param(1, 'session:06b6d2138df949524092eefc066ee5ab3598bf96');
$sth->execute;
DBI::dump_results($sth);
The MySQL server responds with a syntax error near '''.
The output of the DBI-trace shows
-> bind_param for DBD::mysql::st (DBI::st=HASH(0x21e35cc)~0x21e34f4 1 'session:06b6d2138df949524092eefc066ee5ab3598bf96') thr#3ccdb4
Called: dbd_bind_ph
<- bind_param= ( 1 ) [1 items] at perl_test_dbi_params.pl line 10
[...]
>parse_params statement SELECT me.id, me.session_data, me.expires FROM sys_session me WHERE me.id = ?
Binding parameters: SELECT me.id, me.session_data, me.expires FROM sys_session me WHERE me.id = '
[...]
DBD::mysql::st execute failed: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1
So to me, it looks like the statement does not get prepared as it should.
When I send the query without the parameter it works as expected.
What do I miss here?
DBI version is DBI 1.637-ithread, MySQL version is 5.5.57-0+deb8u1
Tested with Windows perl 5, version 26, subversion 1 (v5.26.1) built for MSWin32-x86-multi-thread-64int
and Ubuntu perl 5, version 22, subversion 1 (v5.22.1) built for x86_64-linux-gnu-thread-multi
Edit1:
for context: I noticed the problem while using Catalyst with Catalyst::Plugin::Session::Store::DBIC. Here, the id-column is a Varchar(72) type, that holds a session-id.
Edit2:
DBD::mysql version is 4.043
Binding via $sth->execute('session:foo'); results in the same problem
Binding via $sth->bind_param('session:foo', SQL_VARCHAR); results in the same problem
Binding a numeric field does work, but only with explicit type definition $sth->bind_param(1, 1512407082, SQL_INTEGER);
Edit3:
I found the time to do some more testing, but not with no satisfying results:
I was able to test with an older server and it worked. The versions of DBI and DBD::mysql are the same, but I found the server using MySQL 5.5 client, reported in the DBI-trace as MYSQL_VERSION_ID 50557, whereas both my original test servers using MySQL 5.7 MYSQL_VERSION_ID 50720 and MYSQL_VERSION_ID 50716
with $dbh->{mysql_server_prepare} = 1;it works! Maybe this helps someone who finds this q., but I would rather now the real cause of the problem
From your trace log can be seen that question mark placeholder (?) was replaced by DBD::mysql by one apostrophe ('). So it is pure DBD::mysql bug. At the first glance it does not make sense at all... as placeholder is replaced by parameter which is put into two apostrophes.
Relevant code which is doing this placeholder replacement can be found there: https://metacpan.org/source/MICHIELB/DBD-mysql-4.043/dbdimp.c#L784-786
*ptr++ = '\'';
ptr += mysql_real_escape_string(sock, ptr, valbuf, vallen);
*ptr++ = '\'';
So question is, can above C code result in just one apostrophe in *ptr buffer? And answer is yes, when mysql_real_escape_string() returns integer of same value as pointer size minus one -- to simulate numeric operation of decrement by one, when both apostrophes are written to same position in *ptr buffer.
And can this happen? Yes, it can, because Oracle changed API of mysql_real_escape_string() C function in MySQL 5.7.6 client library:
https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-6.html#mysqld-5-7-6-feature
Incompatible Change: A new C API function, mysql_real_escape_string_quote(), has been implemented as a replacement for mysql_real_escape_string() because the latter function can fail to properly encode characters when the NO_BACKSLASH_ESCAPES SQL mode is enabled. In this case, mysql_real_escape_string() cannot escape quote characters except by doubling them, and to do this properly, it must know more information about the quoting context than is available. mysql_real_escape_string_quote() takes an extra argument for specifying the quoting context. For usage details, see mysql_real_escape_string_quote().
And documentation for mysql_real_escape_string() from MySQL 5.7.6 version says:
https://dev.mysql.com/doc/refman/5.7/en/mysql-real-escape-string.html
Return Values: The length of the encoded string that is placed into the to argument, not including the terminating null byte, or -1 if an error occurs.
Therefore if you enable NO_BACKSLASH_ESCAPES SQL mode on you MySQL server, then mysql_real_escape_string() from MySQL 5.7.6 client cannot work and return error, therefore -1 casted to unsigned long. unsigned long is on both 32bit and 64bit x86 platform of same size as pointer, therefore above C code from DBD::mysql drivers results in one apostrophe character.
Now I fixed this problem for DBD::MariaDB driver (fork of DBD::mysql) in following pull request: https://github.com/gooddata/DBD-MariaDB/pull/77
So DBD::MariaDB would be compatible also when compiled with MySQL 5.7 client library.
After some testing, I came to the conclusion that this seems to be a compatibility problem between DBD::mysql and MySQL client 5.7 (and/or MySQL server 5.5).
At least, I found a solution for Ubuntu 16 (xenial), so for others, that may run into the same issue:
downgrade to MySQL 5.6 like described here. For me, installing libmysqlclient-dev without the server/client was sufficient
reinstall DBD::MySQL sudo cpanm --reinstall DBD::mysql, so that it gets build with the now installed MySQL 5.6
I will file an issue at the DBD::mysql GitHub and will update this answer, if there are any news regarding this problem.
An alternative solution, that also worked for me:
let the server prepare your statement $dbh->{mysql_server_prepare} = 1;

MySQL: CONCAT_WS function is running on local but not on server

Some days ago I asked a question about my problem and I was advised to use CONCAT_WS function. I am using CONCAT_WS on my local mysql database and it is working perfectly. But it is not working on server(application hosted) and generate the following error.
FUNCTION test.CONCAT_WS does not exist
Here test in error string is my database name on server.
My query is like this:
SELECT * FROM patient WHERE CONCAT_WS (',', LastName,FirstName,BirthDate ) NOT IN ('Abdul,Quddus,2000-09-30','Wasim,Akram,1993-09-12');
Can someone tell me the problem or suggest me another solution asked in linked question above ?
Thanks
The easiest way to fix it is by removing the whitespace between the function name and the parenthesis, i.e. CONCAT_WS(...) instead of CONCAT_WS (...).
From the MySQL Manual:
By default, there must be no
whitespace between a function name and
the parenthesis following it. This
helps the MySQL parser distinguish
between function calls and references
to tables or columns that happen to
have the same name as a function.
...
You can tell the MySQL server to
accept spaces after function names by
starting it with the
--sql-mode=IGNORE_SPACE option.
Also, this behavior depends on the MySQL version, this is why it works on one server and doesn't work on another, quote from the "Function Name Parsing and Resolution" manual page:
The number of function names affected
by IGNORE_SPACE was reduced
significantly in MySQL 5.1.13, from
about 200 to about 30.