Case sensitive issues with Mysql queries - php

I'm using a legacy PHP framework which automatically assembles queries for me. By some reason, it is assembling a query like this:
SELECT s.status,c.client FROM client C LEFT JOIN status S ON C.id_status=S.id_status'
This isn't a problem on my MacOS X workstation. But when I test it on my production server mysql raises the following error:
#1054 - Unknown column 's.status' in 'field list'
It is definitively a case issue on s.status. If I manually runs the query changing s,c for S,C , it works perfectly.
A quick look on google didn't solved the issue. Any ideas?

Well, it's said in the documentation:
By default, table aliases are case sensitive on Unix, but not so on
Windows or Mac OS X. The following statement would not work on Unix,
because it refers to the alias both as a and as A:
mysql> SELECT col_name FROM tbl_name AS a
-> WHERE a.col_name = 1 OR A.col_name = 2;
There are also some solutions given in this section of the documentation as well. For example, you can set lower_case_table_names to 1 on all platforms to force names to be converted to lowercase - but you have to rename all your tables to lowercase as well in that case.

Tables in MySQL are stored as files. File names are case-insensitive in MacOS X and Windows, whereas they are case-sensitive in Linux. You can use table names without regarding case in MacOS X and Windows, but not in Linux. So you should choose a consistent casing for all your table names and use it throughout your code.
I'd suggest using all lowercase or uppercase names separated with underscore like tbl_etc, MY_TBL etc so that there'd be no confusion regarding case.

Related

German Umlaute not considered in JSON_CONTAINS() with MariaDB

first time posting here.
I am facing a problem with unpredicted behavior on my PROD server and my local environment.
Here is some background on the situation:
In my application (backend Laravel 7, frontend regular html/javascript) I need to search for entries in a particular table based on JSON data stored in one of the columns:
Table: flights
columns: id, date, passengers, ... pilot_id, second_pilot_id, flight_data, updated_at, created_at
There are flights, that are directly linked to either a pilot or a second pilot via pilot_id or second_pilot_id. That is fine so far, because I can easily query them. However there are also flight entries, where no registered user is doing the entry and they are only represented by a name that is entered. This works only if the name doesn't contain special characters, in particular the german Umlaute (ö, ä, ü), also doesn't work for other specials like â or ß or é, è etc. But ONLY ON PROD, on Local everything works even with special characters.
flight_data has the data type "JSON" in my migration files.
$table->json('flight_data') ...
Now the problem:
On my local environment I can run the following and will get results returned:
... ->where(function($q) use ($r) {
$q->whereRaw("IF(payee = 2, JSON_CONTAINS(flight_data, '{\"second_pilotname\":\"$r\"}'), JSON_CONTAINS(flight_data, '{\"pilotname\":\"$r\"}'))");
})->...
This will get me my example results without issues, as expected
($r is filled a particular name of a pilot, in my example he is called "Jöhn Düe")
If I run this on my PROD system I will get no retuns. I tracked it down to the JSON_CONTAINS() function, that prevents the results. I also tried playing around with "Joehn Duee", which would be found correctly, so it basically comes down to the german Umlaute (ö, ä, ü) not being handled correctly somehow.
I also tried some SQL statements in phpmyadmin and these are the results:
LOCAL
select id, flight_data, comments, updated_at from logbook where JSON_CONTAINS(flight_data, '{"pilotname": "Juehn Duee"}')
1 result found
select id, flight_data, comments, updated_at from logbook where JSON_CONTAINS(flight_data, '{"pilotname": "Jühn Düe"}')
1 result found
PROD
select id, flight_data, comments, updated_at from logbook where JSON_CONTAINS(flight_data, '{"pilotname": "Juehn Duee"}')
1 result found
select id, flight_data, comments, updated_at from logbook where JSON_CONTAINS(flight_data, '{"pilotname": "Jühn Düe"}')
0 result found
I also checked the raw data that is stored:
PROD:
column
data
flight_data
{"pilotname":"J\u00fchn D\u00fce"}
LOCAL:
column
data
flight_data
{"pilotname":"J\u00fchn D\u00fce"}
So logically the data is transformed. Which is ok, because the data is then shown according to UTF-8 and then correctly displayed ("Jühn Düe")
The problem is, that in the backend I need to compare this data.
The differences are that on my local environment I am using MYSQL 8.0 (it's a homestead server, so select ##version; => 8.0.23-0ubuntu0.20.04.1) and on PROD (the hosted server) I am seeing "10.3.28-MariaDB-log-cll-lve"
Therefore the difference is clear, MariaDB vs. MYSQL and the handling of german Umlaute.
I tried various things around changing the conversion / charset of the entries, of the database, that all didn't solve the problem. I searched for quite a while for various similar problems, but most of them resulted in having the data stored not in UTF-8 - which I checked and is the case for me here.
Even querying for the raw data doesn't work somehow:
The following doesn't work neither on PROD nor on LOCAL:
select id, flight_data, comments, updated_at from logbook where JSON_CONTAINS(flight_data, '{"pilotname": "J\u00fchn D\u00fce"}')
0 results found
Can you help me figuring out what I am missing here?
Obviously it has to do something with the database, what else can I check or do I need to change?
Thanks a lot everybody for your help!
You should use the same software in development that you use in production. The same brand and the same version. Otherwise you risk encountering these incompatible features.
MariaDB started as a fork of the MySQL project in 2010, and both have been diverging gradually since then. MySQL implements new features, and MariaDB may or may not implement similar features, either by cherry-picking code from the MySQL project or by implementing their own original code. So over time these two projects grow more and more incompatible. At this point, over 10 years after the initial fork, you should consider MariaDB to be a different software product. Don't count on any part of it remaining compatible with MySQL.
In particular, the implementation of JSON in MariaDB versus MySQL is not entirely compatible. MariaDB creating their own original code for the JSON data type as an alias for LONGTEXT. So the internal implementation is quite different.
You asked if there's something you need to change.
Since you use MariaDB in production, not MySQL, you should use MariaDB 10.3.28 in your development environment, to ensure compatibility with the database brand and version you use in production.
I think the problem is a collation issue. Some unicode collations implement character expansions, so ue = ü would be true in the German collation.
Here's a test using MySQL 5.7 which is what I have handy (I don't use MariaDB):
mysql> select 'Juehn Duee' collate utf8mb4_unicode_520_ci = 'Jühn Düe' as same;
+------+
| same |
+------+
| 0 |
+------+
mysql> select 'Juehn Duee' collate utf8mb4_german2_ci = 'Jühn Düe' as same;
+------+
| same |
+------+
| 1 |
+------+
As you can see, this has nothing to do with JSON, but it's just related to string comparisons and which collation is used.
See the explanation in https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-sets.html in the section "_general_ci Versus _unicode_ci Collations"
Thank you all for your inputs and response!
I figured out a different solution for the problem. Maybe it helps someone..
I went a step back and checked how I am storing the data. I was using json_encode() for that, which created the table contents as shown above. By just using a raw array to save it, it was working then
$insert->pilotname = ['pilotname' => $request->pilotname];
Somehow the storing of data before was already the issue.

Calling Count column php mysql

I have query that COUNT the data based from user search condition in search.
My question is just simple although I don't know what the solution here:
I want to call the COUNT column, which I know it was just temporary column
I have PHP code like this:
$count = mysql_query("SELECT *, COUNT(*) AS SAMPLECOUNT FROM `subscribers` WHERE `country` = 'USA' ");
$row=mysql_fetch_array($count);
so by this code I can echo the columns inside the subscribers by using this:
echo $row['country'];
*echo the count result here*
So maybe the output will be like this:
USA: (the count result)
As requested
Since you're using an alias COUNT(*) AS SAMPLECOUNT you pass it along in the $row's array as
echo $row['SAMPLECOUNT'];
in order to show the row count's number.
Here are a few references:
http://www.mysqltutorial.org/mysql-alias/
https://dev.mysql.com/doc/refman/5.6/en/select.html
Sidenote: Aliases are case-sensitive on *NIX, but not so on Windows or Mac OSX”.
So echo $row['samplecount']; could fail if on *NIX.
However and quoting this answer https://stackoverflow.com/a/2009011/ on Stack:
"On Unix, table names are case sensitive. On Windows, they are not. Fun, isn't it? Kinda like their respective file systems. Do you think it's a coincidence?
In other words, if you are planning on deploying on a Linux machine, better test your SQL against a Linux-based MySQL too, or be prepared for mysterious "table not found" errors at prod time. VMs are cheap these days.
Field names are case-insensitive regardless."

WHERE clause not working in SQL-query using mdbtools

I've been working on a project using the LAMP server that requires frequent read of the MS-ACCESS database, stored in *.mdb file. The database has one table and about 40.000 rows in it.
I've installed mdb-tools and configured unixODBC to use it. First impression was positive:
SELECT * FROM [Table]
Worked fine, however returned a huge structure, that overflew my buffer and the tail of data was truncated.
SELECT [col1], [col2], [col3] FROM [Table]
Worked fine as well, but the amount of data was still on the edge of usability (barely didn't exceed the buffer). So I've tried to limit result with the WHERE statement, but neither
SELECT * FROM [Table] WHERE [col1]=X
nor
SELECT * FROM [Table] WHERE [col2] LIKE 'xxx'
nor
SELECT [col1], [col2], [col3] FROM [Table] WHERE [col1]=X
nor
SELECT [col1], [col2], [col3] FROM [Table] WHERE [col2] LIKE 'xxx'
isn't working. They just return empty structure.
But if the condition is all-matching - it works:
SELECT * FROM [Table] WHERE [col2] LIKE '%'
returned that huge bulk of data
I know that mdb-tools is quite an ancient solution, that provides read-only access - but that's ok for me. I just want it to work.
I've tried both versions - from sourceforge and from github.
If col1 is a text column then use ... WHERE [col1] = 'some text' (note the use of quotes) for an exact match.
... WHERE [col1] LIKE 'xxx' is equivalent to ... WHERE [col1] = 'xxx'.
When using LIKE the wildcard character % matches zero or more characters, and _ matches one character, so
... WHERE [col1] LIKE 'To%'
should match "Toronto", "Tokyo", "Toledo", etc. ...
Edit
The man page for the mdb-sql command of MDB Tools does claim to support LIKE, so I put together a test .mdb file with a table named [Clients] that contained
ID LastName FirstName Email
-- ---------- -------------- ------------------
1 Thompson Gord gord#example.com
2 Loblaw Bob bob#example.com
3 Kingsley Hank hank#example.com
4 Thompson Hunter S. hunter#example.com
I did sudo apt-get install mdbtools on my test server (Ubuntu 12.04.02), uploaded the .mdb file and did the following
gord#pingu:~$ mdb-sql -p ~/ubuTest2003.mdb
1 => SELECT ID, LastName FROM Clients
2 => go
ID LastName
1 Thompson
2 Loblaw
3 Kingsley
4 Thompson
4 Rows retrieved
1 => SELECT ID, LastName FROM Clients WHERE LastName LIKE 'Thomp%'
2 => go
ID LastName
1 Thompson
4 Thompson
2 Rows retrieved
If you are having difficulty with WHERE clauses I would suggest running a similar test (with a small sample dataset) on your system using mdb-sql to see if WHERE clauses work in that context. If they don't work, then your MDB Tools is broken. If they do work, then we'll need to investigate further.
Edit
I spent some time trying to recreate this issue in PHP on my Ubuntu 12.04 test server. I was unable to do so, only because I was unable to get the odbc_ functions in PHP to work with mdbtools at all. I could establish a "valid" connection (no errors) and I could "execute" a query (again, no errors), but I could not get any query to actually return results, not even SELECT * FROM Clients.
In searching for assistance with my problem I happened upon the Stack Overflow article here, which further discouraged me from pursuing the matter further.
Instead, since this is apparently an active Access database hosted on a Windows machine, I personally would opt for using ODBTP. It is a free (GPL) TCP/IP protocol that allows you to pass queries to a Windows machine, which then submits the query via its ODBC driver and passes the results back to you.
It does require that a service be installed and run on the Windows machine, and the PHP client component must be compiled on Linux boxes, but if those requirements aren't too daunting then it is a pretty robust solution to this type of problem. (I have used it a few times in the past.)
And while it is true that ODBTP hasn't been updated for several years, it still works: I tested it just now with my LAMP server running the following PHP script to query an .mdb file residing on my older Vista notebook:
<?php
echo '<html><body><pre>';
echo "ODBTP test:\n";
$con = odbtp_connect('192.168.1.254',
'DRIVER={Microsoft Access Driver (*.mdb)};DBQ=c:\\__tmp\\ubuTest.mdb;UID=admin;PWD=;');
if (!$con) die('_connect error: ' . odbtp_get_error($con));
$rst = odbtp_query("SELECT * FROM Clients WHERE LastName LIKE 'Thomp%'");
if (!$rst) die('_query error: ' . odbtp_get_error($con));
while ($row = odbtp_fetch_assoc($rst)) {
echo $row['ID'] . ': ' . $row['LastName'] . "\n";
}
echo '</pre></body></html>';
The results as displayed in my browser window are
ODBTP test:
1: Thompson
4: Thompson
It's been a while...
mdb-tools is CRAP.
We have ended up by writing out own Windows service listening to SQL queries on a port given and proxing them to Access by an ADO connection.
So if only you have such opportunity, I recommend you not to use dead mdb-tools.
I have a sneaky suspicion that your WHERE col data contains some special characters like single quotes or double quotes OR there is some issues with PrimaryKey.
I'm using MDBTools and I successfully select cols from tables with wildcards, BUT when i try to select from a certain col that has some double quotes in the data, i get ZERO results. When I run php blah.php on that particular col, I get the error
CRITICAL: can't find column with internal id ### in index PrimaryKey
Found that in the code on line 309, but still not past it...
https://github.com/brianb/mdbtools/blob/master/src/libmdb/index.c

SQL Server returned column name truncated to 29 characters using PHP

I have a SQL Server query that I take the result from and insert into an array like
while($row = mssql_fetch_array($res,
MSSQL_ASSOC)) { ... }
Now, the problem is that looking at the $row I see that the column named customer_social_sequrity_number becomes the key customer_social_sequrity_numbe. All other keys seems to be trunkated to 29 characters to. Is this a limit? I can't find any information about such a limit.
This is a bit of a drag since I'm importing data from a 3rd party database and use the key of the array to mapp the data to an object.
Does not seem to be a limitation on the PHP side as stated. Is it possibly some limitation on the SQL Server part? Running the query using MS Query Analyzer it seems fine.
I found the answer to the question. It seems like in Windows, Microsoft's DBLIB is used and functions that return a column name are based on the dbcolname() function in DBLIB. DBLIB was apperently developed for SQL Server 6 where the max length of a columnname was 30. For this reason, the maximum column length is 30 characters.
Here you can get a version of FreeTDS for Windows that hopefully eliviates this problem: http://docs.moodle.org/en/Installing_MSSQL_for_PHP#Using_FreeTDS_on_Windows
Also on Linux this will not be a problem it only affects Windows
this: What is the max key size for an array in PHP? seems te imply that you're not having trouble with a PHP array-key limit
Make sure the column in your database is definetly called customer_social_sequrity_number and is not cut off
Check this is definetly the key and not the value of the array, if it's the value then it's data rather than column name

How to make MSSQL query in PHP case-sensitive?

In a script on our web server, we display users who are online in-game by looking at a MSSQL database for specific values then displaying the members based on such data.
Lets say user login 'blargh' has 3 characters: MasteR, MasTeR, and BlarGh
Lets also say that he has logged in as 'MasteR'
The below script will look for the value of '1' in 'connectstat' field then grab his username along with some other pertinent data, then display it.
The problem lies when someone has two similar in-game names on a single account.
With the above example, this script will show MasteR, and MasTeR are both online, even though only one is actually in-game. I believe this is a case sensitivity issue where when it identifies 'MasteR' as online, it's ignoring the case and believes 'MasTeR' is online as well.
Anyone have ideas on how to isolate this by making it case-sensitive?
$query = 'Select GameIDC, Resets, Class, MapNumber, MapPosX, MapPosY, ServerName, OnlineHours, clevel From MEMB_STAT, AccountCharacter, Character where MEMB_STAT.Connectstat=1 and AccountCharacter.Id=MEMB_STAT.memb___id AND AccountCharacter.GameIDC=Character.Name collate Chinese_PRC_CI_AS order by GameIDC, ServerName desc';
$result = mssql_query($query);
This is on a xampp-based web server on winxp x86 using php5 and MSSQL (ODBC)
case sensitivity comes from collation. so if the collation is set as cs (case sensitive) then your query condition will be CS as well.
however, why dont you try to use group by
ie.
select playername from gameDb where status=1 group by playername;

Categories