Automatically truncate data when inserting - php

My MySQL Server (running with PHP via PDO on Windows 2008 Server) returns error code 1406 (data too long for field) when inserting strings longer than allowed in a column. The thing is I read somewhere that what MySQL usually truncates the data when it is not in strict mode. I changed the sql_mode in my.ini so that even at startup it doesn't enter in strict mode (it is currently ""), but it is still giving me the error and rolls back, so the data is lost (truncating is the desired behaviour of the site).
I entered to the command line and made an insert with a long string in a shorter varchar field and it does truncate the data and save, but it is the site that doesn't. When I changed the mode back to strict, it didn't truncate in the command line (only the error).
Also, I made the site output the current sql mode, both global and session (##GLOBAL.sql_mode and ##SESSION.sql_mode) and they both output "" but just don't work as desired.
Does anyone know what is causing this and/or how to change it?
My suspicion is that it may have to do with PDO enabled with PDO::ATTR_ERRMODE = PDO::ERRMODE_EXCEPTION, but I have read and can't find anything helpful about that (I don't really think this is definitely the explanation, but I am just putting this out there so that you know as much as possible about the problem).
Thank you very much

You should not really do that - please don't let bad data into your database, and sanitize it in your scripts before you insert.
If you don't know actual width of your VARCHAR columns or don't want to hard-code it in your scripts, you can read it from database by querying INFORMATION_SCHEMA table COLUMNS using query like this:
SELECT
column_name,
data_type,
character_maximum_length,
ordinal_position
FROM information_schema.columns
WHERE table_name = 'mytable'
(you may want to limit this to only data_type = 'varchar').
Having this information and specifically character_maximum_length, you can use PHP substr to trim your input strings to desired length.
Advantage of this approach is that it does not alter any server configuration, and should work for any other databases, not only MySQL.
But if you insist on doing it unsafe way, you can try to temporarily disable strict mode by executing this:
SET sql_mode = '';
After that MySQL should silently trim strings. Read more here.

Probably the mysql server is in "not forgiving" mode, aka. traditional (most times). What you read is true, if mysql server operates in forgiving mode. If you are trying to insert too long string, it can be really important information, therefore mysql will issue a error. You have a few alternatives:
1: Use insert ignore (which will transform all errors into warnings and will proceed to truncating the data)
2: For the current session, set the sql_mode to ''
With either of these your problem should go away.
PS: I have read the error you are getting, but i still think the server is operating in traditional mode (so it's no mistake that i recommended sql_mode set to empty).
PS2: After changing the my.cnf, did you restart the mysql server?

Related

different result executing an sql query from phpmyadmin(good) and from PHP script(bad)

I have a really strange problem, executing a query on a MySQL DB:
from phpmyadmin: the query executes and return good results
from my PHP script: the query executes, no errors, good number of rows, but nearly 50% of the values shown in the table are wrong !
The SQL query used is exactly the same, rather long(250 lines), takes 26 seconds to execute in phpmyadmin, and works good.
On my PHP script the query iss executed with the mysqli_query() the typical way I would say:
if ($res=mysqli_query($mysqli,$q, MYSQLI_USE_RESULT)){
$data = array();
while ($row=mysqli_fetch_assoc($res)){
$data[] = $row;
}
mysqli_free_result($res);
var_dump($data);
}
On the query I replaced backtite: (`) to single quote: (').
Any idea why it's working with phpmyadmin, but not from PHP with mysqli_query() function? Btw phpmyadmin doesn't use the mysqli_query() function?
No errors is thrown, I'm really lost here, if someone has a hint, it would be much appreciated :)
Thx :)
The most likely answer is that something is different between the queries. As you cannot easily trace the difference in 250 lines. Use the MySQL query log to record both queries as MySQL sees them and then compare the differences:
To disable or enable the general query log or change the log file name at runtime, use the global general_log and general_log_file system variables. Set general_log to 0 (or OFF) to disable the log or to 1 (or ON) to enable it. Set general_log_file to specify the name of the log file. If a log file already is open, it is closed and the new file is opened.
Something along the lines of:
SET GLOBAL general_log = 'ON';
SET GLOBAL general_log_file= 'querylog.log';
.. run queries
SET GLOBAL general_log = 'OFF';
Note that this is a global setting, the server will log queries from all clients whilst the log is enabled. Your MySQL also needs the super privilege to change this setting. Alternatively you can change in the my.cnf config file and restart MySQL.
Once you have the two queries, a comparison should show you where the difference is and guide you to a fix.
YAY after several headaches I solved by chance the mystery, I don't really know why though, but now it's working good.
Here are the small changes I made to make it work:
change the PHP file encoding from UTF8 to ISO-Latin1
retype all non alphha characters to be sure they're ok
In my SQL query I had an accent on a string I checked in a where clause, so I tried this..
The thing is I have many PHP files on the same server, encoded in UTF8 and text with accents that work perfectly.
The only difference here is that the accent is in my SQL query, maybe the server hosting my websites doesn't handle UTF8 characters properly and the system encoding is not well configured ..
Just to be sure, I have a terminal access to server, how can I see the system encoding ?
But problem solved, all good!

Inserting text from text file into MySQL TEXT column

I am trying the following which is not working:
update table_name set text_column= load_file('C:\temp\texttoinset.txt') where primary_key=5;
Here text_column is of type TEXT.
This gives:
Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. Rows matched: 1 Changed: 0 Warnings: 1
What is the right way to insert a log file contents in my SQL from PHP?
This is a possible duplicate of this question: https://serverfault.com/questions/316691/mysql-binlog-format-dilemma
Anyway, the key is Statement is unsafe because it uses a system function that may return a different value on the slave.
When the MySQL database is setup to use replication, system functions like load_file can cause issues. The file C:\temp\texttoinset.txt is likely different between the master server and the slave server (or may not even exist on one of them).
When using replication, it is best to avoid system functions (like load_file and NOW()) because the values will be different when executed on different servers. If you want to load a file into a MySQL database that uses replication, consider using PHP's file_get_contents to read the file, and then use that to insert it into the database.
As a side note, I don't know why you're trying to insert a log file into MySQL, especially as a single TEXT column. There is probably a better way to do what you are wanting to do.

update query not working in joomla

I'm working on a joomla extension and I'm trying to update entries in my joomla extensions database table using the following code in my model:
$this->_db->setQuery(
$this->_db->getQuery(true)
->update('#__my_table')
->set('position=position+1')
);
$dbres = $this->_db->result();
However it doesn't do anything and outputs no error (Development on and error reporting maximum in global config)
I entered the query directly in PHPmyAdmin:
UPDATE cprn7_my_table SET position=position+1
and it works without any problems.
I read about quoting keys and values with $this->_db->quoteName() or so, but I can't find any examples for that with queries like SET position=position+1 but only SET position=$newval so I don't know exactly what to quote and how.
//EDIT: Found the error, it has to be $this->_db->query() and not $this->_db->result()
A few possibilities come to mind. The first is that the --safe-updates setting is enabled, preventing updates (and deletes) whose WHERE clause lacks a primary key column specification.
phpMyAdmin may turn this setting off, while your default MySQL client settings (in my.cnf, under [client]) may be enabling it. You can use the show variables statement to discover the setting's value. Also, see this doc for more info: http://dev.mysql.com/doc/refman/5.5/en/mysql-command-options.html#option_mysql_safe-updates
A second thought: You can quote the column name using backticks, for example:
SET `position`=`position` + 1
However, if this still seems to have no effect, and, if you have an admin-level MySQL account for your server, you can turn the general log on, then run your query, then turn it off again, then examine your results. See this doc for working with the --general-log and related settings: http://dev.mysql.com/doc/refman/5.5/en/query-log.html
BTW, if your MySQL client provider (or Joomla, or any other tier in the mix) is setting --safe-updates using a SET command (i.e., upon connecting), you will also see this as an executed statement in the general log.

Storing Special Characters in MySQL (Android, PHP involved too)

Ok, I am trying to store data in a MySQL database from an Android app. I use PHP as the go between.
What I submit to the database is this (for example):
Sakè
What is stored in MySQL is:
Sakè
When I print the line back out in Android it knows to convert back to:
Sakè
The problem is, when I do certain select statements, yeah it basically doesn't work out like it should. Is there any way I can keep this consistent?
Just a note in MySQL: I use utf8_general_ci
You need to enforce correct character for your database connection for your PHP scripts. Simplest approach would be to execute this query:
SET NAMES 'utf8';
just once, best after you connect(). If you use Zend Framework, just add this:
resources.db.params.charset = UTF8
to your application.ini. For mysqli see set_charset(). If you use anything else, check the docs for something similar. If there's nothing, the SET NAMES trick would always work.
One important note though - depending on how you put your data to the DB, your database content most likely require fixing as it is corrupted by broken charset during INSERTs. So if even you do SET NAMES now, you most likely still see old data shown wrong. But that is, ironically, OK - you are now showing all fine, but data itself is broken. You just now need to fix your data (just re-insert it).

Is there any difference between SQL running in code vs the MySQL command line?

I have a SQL update statement I am running from inside a PHP program. It is prepared and then executed. When I run it in PHP, it reports a constraint violation. When I run the exact same statement from the command line (which I am getting via dBug()), it works with no errors. This sounds impossible, so I keep looking for differences between the statements. The only thing I can see is that when I execute it with an array of arguments, they all appear to be chars, when some should be integers.
Any suggestions for where to look?
Here is the PHP version (I tweaked it a little to make it more legible):
$st =& $db->prepare("update tbl set uid=?, frequency=? other_id=? where id=$id");
$values = array($uid, $freq, $other_id);
$res =& $db->execute($st, $values);
new dBug ($res);
Probably the PHP client and MySQL client use different charsets.
The user-input data which does not have a counterpart in the client's character table may get converted into ????? which are likely to violate the constraint:
SELECT CAST('абвгд' AS CHAR CHARSET LATIN1)
---
?????
, 'абвгд' here being Cyrillic characters.
Could you please provide some sample of the data you are trying to insert along with the table defintion?
Sounds improbable - there may be some difference in the SQL that is being run after the variables have been bound. Enable the general query log and compare the executed versions of the statements in the 2 scenarios.
C.
Well, hate to say it, but the problem was with my copy and paste. I was using dBug to show the values and sleep to pause while I read them, but since I could not copy and paste I had to retype the query. And I typo'd one of the values. Thanks for your efforts, but as usual: operator error.

Categories