MYSQL incorrect DATETIME format - php

I have an app with Doctrine 1 and I generate update_datetime fields for objects via new Zend_Date->getIso(). It worked just fine for years, but now I got a new notebook and Doctrine tries to insert a DATETIME fields as a string "2013-07-12T03:00:00+07:00" instead of normal MySQL datetime format "2013-07-12 00:00:00" which is totally weird.
The very same code runs just fine on another computer. Everything is nearly identical – MySQL 5.6.12, PHP 5.3.15 on both. Any idea where should I look?
Fatal error: Uncaught exception 'Doctrine_Connection_Mysql_Exception' with message 'SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: '2013-07-12T03:00:00+07:00' for column 'nextrun' at row 1' in library/Doctrine/Connection.php:1083
UPDATE
Ok with the help from StackOverflow community I finally solved it. The problem was with STRICT_TRANS_TABLES in sql_mode variable. But changing it in /etc/my.cnf seemed not enough, so I had to run mysql -uroot and type the following:
set sql_mode=NO_ENGINE_SUBSTITUTION; set global sql_mode=NO_ENGINE_SUBSTITUTION;
Thus removing STRICT_TRANS_TABLES
UPDATE2
How to get rid of STRICT forever? How to get rid of STRICT SQL mode in MySQL

If it exists, you can try removing STRICT_TRANS_TABLES from sql-mode in your my.ini.
This can cause this error with a datetime string value containing the format you have not being converted to mysql datetime. This my.ini change was reported as a fix in:
PING causes 500 Internal Server Error - Incorrect datetime value
(AuthPuppy Bug #907203)

Date constants in zend are determined from sniffing out locale in this order (form zend_locale comments)
1. Given Locale
2. HTTP Client
3. Server Environment
4. Framework Standard
I'm thinking the difference between the two systems is going to be reflected in the Server Environment.
To correct and avoid this problem in the future you can specify the locale options within your application.ini using these configuration directive.
resources.locale.default = <DEFAULT_LOCALE>
resources.locale.force = false
resources.locale.registry_key = "Zend_Locale"
The locale should be set to a string like en_US
Zend_Locale specificly sniffs the locale from the environment from a call to setlocale and parsing the results.

This is caused by Zend not setting your timestamp format to one that matches what MySQL is expecting. You could disable STRICT mode in MySQL, but this is a hack and not a solution (MySQL will attempt to guess what the date you're entering is).
In Zend you can set the datetime format to what MySQL is expecting to solve this:
$log = new Zend_Log ();
$log->setTimestampFormat("Y-m-d H:i:s");

Ok with the help from StackOverflow community I finally solved it. The problem was with STRICT_TRANS_TABLES in sql_mode variable. But changing it in /etc/my.cnf seemed not enough, so I had to run mysql -uroot and type the following:
set sql_mode=NO_ENGINE_SUBSTITUTION; set global sql_mode=NO_ENGINE_SUBSTITUTION;
Thus removing STRICT_TRANS_TABLES
------this answer works

Related

xmldb_field Moodle change column type

I'm trying to change the column type from a character varying (10) to that of a date.
I can run it individually like so:
ALTER TABLE "tbl_name" ALTER "col_name" TYPE timestamp USING (col_name ::timestamp);
But after throwing this into the upgrade.php script, it barfs on me and requires the USING clause which I can't seem to get to work. Or if there even is a way...
Here's my upgrade.php script:
$table = new xmldb_table('tbl_name');
$field = new xmldb_field('col_name', XMLDB_TYPE_DATETIME);
if ($dbman->field_exists($table, $field)) {
$dbman->change_field_notnull($table, $field);
}
When logging into the Moodle admin and running the update, I get the following error:
ERROR: column "col_name" cannot be cast automatically to type timestamp without time zone HINT: You might need to specify "USING col_name::timestamp without time zone".
Any ideas?
Thanks!
As noted in the Moodle docs (https://docs.moodle.org/dev/XMLDB_column_types) you should avoid using datetime fields - all timestamps in Moodle are declared as integer(10).
If you're using the XMLDB Editor built into Moodle to generate your database table definitions (and you really should do that), then it does not give the option of using the datetime field type.

PostgreSQL: getting error messages from `pg_convert()`

I'm trying to diagnose a problem only found on a production system and I'm trying to improve the error reporting for errors thrown by pg_convert(), but not sure where to go. I tried changing the code in the dev environment to:
$converted_values = pg_convert($cnx, $table, $values);
if ($converted_values === FALSE)
throw new Exception("Failed to insert record: '".pg_last_error($cnx)."' using values: ".var_export($values, true));
But pg_last_error() returned nothing.
Note: I tested the above by trying to insert a null value into a NOT NULL column. In addition to getting no joy from pg_last_error() the log had some "PHP Notice"s in it. The production log didn't have any such notices. Just the empty return value from pg_convert() :(
I'm running PostgreSQL 9.4.6 on Debian 8.3 and PHP 5.6.22.
From what I can tell, trying to get anything done w/pg_convert() is a bust. It's not very reliable in dealing w/different data, and it's inconsistent about putting double quotes around column names. If you're using pg_convert() you'll likely want to convert to prepared statements. What they do is very different, so you might have to make fundamental changes to your code base, but we made the change and it seems to be working for us.
Edit: and one such problem that pg_convert()/pg_query() seemed to be able to roll w/that pg_execute() doesn't, is empty strings assigned to integer columns where NOT NULL isn't set. To fix this (at least for now) I had to:
loop through the array passed to pg_execute()
call pg_meta_data() when I found one w/an empty string
determine if the destination column is an integer (be careful: there are probably a lot of ways in which the type for an integer column can be expressed) then if nulls are allowed at all
overwrite the empty string w/null.
Inserting a NULL into a NOT NULL column will not trigger an error in pg_convert. Errors will result from connection problems, a missing table, or a missing column, or data that cannot be converted from the PHP structure to the type in the database (e.g. a word to a number).

Getting oci_execute(): ORA-01843: not a valid month invalid in php while inserting record?

I am getting oci_execute(): ORA-01843: not a valid month invalid. Why it is giving it?
INSERT INTO DETAIL (PPD_ID, PPD_ID,PPD_ENTRY_DATE, PPD_IGM_ID, PPD_DFM_ID, PPD_DRM_ID, PPD_HEIGHT, PPD_UOM_ID, PPD_FTM_ID, PPD_FRQ_ID, PPD_START_DATE_TIME, PPD_END_DATE_TIME, PPD_STATUS, PPD_STM_ID)
VALUES ('WS00318229',2440900,'29-12-2015',350,1,1,50,46,1,1,'29-12-2015','29-12-2015','PRESCRIBED',6)
When i am using the above query from php to insert record in to oracle database it is giving following error.
oci_execute(): ORA-01843: not a valid month invalid
But when i use the following query it is not giving any error and it is inserting record.How to solve this? This error was already is there but i am not clear about the answers.Any ideas why it is like this.
INSERT INTO DETAIL (PPD_ID, PPD_ID,PPD_ENTRY_DATE, PPD_IGM_ID, PPD_DFM_ID, PPD_DRM_ID, PPD_HEIGHT, PPD_UOM_ID, PPD_FTM_ID, PPD_FRQ_ID, PPD_START_DATE_TIME, PPD_END_DATE_TIME, PPD_STATUS, PPD_STM_ID)
VALUES ('WS00318229',2440900,'29-DEC-2015',350,1,1,50,46,1,1,'29-DEC-2015','29-DEC-2015','PRESCRIBED',6)
You are inserting strings into DATE columns. When you do that, oracle performs implicit conversion based on your NLS settings, specifically, nls_date_format. Evidently when you connect from php script and from some client you use (SQL*Plus, SQL Developer, what have you), your NLS settings differ.
You can check session parameters using following query.
SELECT * FROM nls_session_parameters;
For date presented in format '29-DEC-2015' nls_date_format should be 'DD-MON-YYYY'. If it has some other value, you can change it using following query.
alter session set nls_date_format='DD-MON-YYYY'
Or you can explicitly convert string to date using TO_DATE function and passing format as second parameter, but this will require your application code to be consistent in using only specified date format.
TO_DATE('29-DEC-2015', 'DD-MON-YYYY')

PHP ODBC not accepting alias on column name with space

Basically, I need to get some data out of a SQL Server 2005, using PHP.
Previously we used the mssql_* functions, however due to various server issues we are only now able to use odbc_* functions.
The table has various columns whose names have spaces in them, and before it is suggested.... no I cannot change them as this is a totally separate piece of software in another language and it would break it, I am just getting stats out of it.
Anywho, I had previously been accessing these columns by putting their names in square brackets, e.g. [column name] and it worked fine under the mssql_* functions, however when I do this:
$sql = "select top 1 [assessment name] as AssessmentName from bksb_Assessments";
$result = odbc_exec($db, $sql);
while($row = odbc_fetch_array($result))
{
var_dump($row);
}
It prints the results out as:
'assessment name' => string 'Mathematics E3 Diagnostic' (length=25)
So as you can see it is totally ignoring the alias I've given it and still calling it [assessment name].
But if I run the exact same thing in SQL Server Management Studio Express, it works fine and uses the alias.
I've tried various different combinations, such as quoting the alias, quoting the column, different brackets, etc... but no luck so far.
This isn't a huge issue, as I can change what my script uses to look for "assessment name" in the result array instead of the alias, but it's just a bit annoying that I couldn't work out why this was happening...
Cheers! :)
EDIT:
Actually i don't think the square brackets make a difference, just trying to alias any column isn't working with through php odbc, however I can still do something like CAST(whatever) AS 'alias' and that works fine... just not selecting a column as an alias...? :/
This is by no means a perfect solution, and I would love to learn the proper way to deal with this issue, but in the mean time, add +'' to each column, after the underlying column name, but before the AS alias and you should be able to circumvent this issue.
While attempting to troubleshoot this issue and determine why some of my team's stored procedures exhibited this behavior, I finally discovered why. What's strange is that we were only experiencing this issue with a few stored procedures, while most returned the the aliases as expected.
It appears that declaring at least one variable, whether or not it is being used, will prevent this particular bug from occurring. The variable can be of any type.
If you're just executing a SELECT query without using a stored procedure, use a DECLARE statement to define a variable before or after the statement:
// This works...
DECLARE #ignore TINYINT; SELECT EmployeeID AS employee_id FROM Employee;
// So does this...
SELECT EmployeeID AS employee_id FROM Employee; DECLARE #ignore TINYINT;
Now if you're running into this issue with your stored procedures, you can take the same approach above by defining a variable anywhere in the body.
One other thing I noticed is that if the stored procedure is defined with parameters, if your the parameter gets set or evaluated in something like an if statement, this bug will also not occur. For example,
// This works...
CREATE PROC get_employee(
#employee_id VARCHAR(16) = NULL
)
AS
IF (#employee_id IS NOT NULL)
BEGIN
SELECT FirstName AS first_name FROM Employee WHERE EmployeeID = #employee_id;
END
GO
Using SET:
// So does this...
CREATE PROC get_employee(
#employee_id VARCHAR(16) = NULL,
#ignore TINYINT
)
AS
SET #ignore = NULL;
SELECT FirstName AS first_name FROM Employee WHERE EmployeeID = #employee_id;
GO
I still don't quite understand the cause or nature of the bug; but these workarounds, similar to the type-casting hack above, appear to get around this annoying bug.
It's probably also worth mentioning that we didn't encounter this issue in Ubuntu 14.04 and PHP 5.4. As soon as we upgraded to Ubuntu 18.04 and PHP 7.2, that was when we began experiencing this issue. In both instances, we do have FreeTDS configured to use version 7.1, which is why we're baffled by this particular bug.
#dearsina's approach in fact seems to be one of the few ways to handle this bug.
However, this solution is not applicable to all datatypes. So for me, the only way to cover all needed columns was to CAST() the relevant column (where initially c.State would be of datatype bit):
SELECT
CAST(c.State AS nvarchar) AS 'customer_state'
FROM
customers AS c;
as else you might get an error message similar to
The data types bit and varchar are incompatible in the add operator.
Reference on CASTing large data sets: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/643b6eda-fa03-4ad3-85a1-051f02097c7f/how-much-do-cast-statements-affect-performance?forum=transactsql
Some further finding on this topic is a recently (November 2017) raised bug report at bugs.php.net claiming that the problem is related to FreeTDS: https://bugs.php.net/bug.php?id=75534.
This bug report contains an inofficial (and at least from my end untested) patch:
diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h
index 93e2c96..8451bcd 100644
--- a/ext/odbc/php_odbc_includes.h
+++ b/ext/odbc/php_odbc_includes.h
## -292,18 +292,16 ## void odbc_sql_error(ODBC_SQL_ERROR_PARAMS);
#define PHP_ODBC_SQLCOLATTRIBUTE SQLColAttribute
#define PHP_ODBC_SQLALLOCSTMT(hdbc, phstmt) SQLAllocHandle(SQL_HANDLE_STMT, hdbc, phstmt)
-
-#define PHP_ODBC_SQL_DESC_NAME SQL_DESC_NAME
#else
#define IS_SQL_LONG(x) (x == SQL_LONGVARBINARY || x == SQL_LONGVARCHAR)
#define PHP_ODBC_SQLCOLATTRIBUTE SQLColAttributes
#define PHP_ODBC_SQLALLOCSTMT SQLAllocStmt
-
-#define PHP_ODBC_SQL_DESC_NAME SQL_COLUMN_NAME
#endif
#define IS_SQL_BINARY(x) (x == SQL_BINARY || x == SQL_VARBINARY || x == SQL_LONGVARBINARY)
+#define PHP_ODBC_SQL_DESC_NAME SQL_DESC_LABEL
+
PHP_ODBC_API ZEND_EXTERN_MODULE_GLOBALS(odbc)
#define ODBCG(v) ZEND_MODULE_GLOBALS_ACCESSOR(odbc, v)
Faced similar problem. The 4th parameter of odbc_connect did the trick in my case choosing cursor type SQL_CUR_USE_ODBC.

Why TEXT column returns only 4096 bytes?

I'm storing a long text with mssql_query();
And Using the field with datatype called 'text'.
I tried with different long strings by using str_repeat(), the page takes long time, but in the end submits the result.
When I retrieve the result however, I get only 4096 bytes nomatterwhat.
I tried to retrieve the value with management studio too, and it gets the same outcome.
It looks to me like a storing problem to me. Please advice something... I'm confused.
EDIT for these who asked, this is what I'm using:
function sql_escape($sql) {
/* De MagicQuotes */
$fix_str = stripslashes($sql);
$fix_str = str_replace("'","''",$sql);
$fix_str = str_replace("\0","[NULL]",$fix_str);
return "'".$fix_str."'";
}
$query=mssql_query('update prod_cat set htmlbottom='.sql_escape(str_repeat('\'choose_cat ', 122000)).
' where ID=1' );
$query=mssql_query('select htmlbottom from prod_cat where ID=1');
$a=mssql_fetch_assoc($query);
echo strlen($a['htmlbottom']);
Microsoft's PHP driver (for reference): http://www.microsoft.com/en-us/download/details.aspx?id=20098
But if you don't want to (or can't) change drivers, from this site:
You need to increase the maximum size of a text column to be returned from
SQL Server by PHP. You can do this with a simple SQL query:
SET TEXTSIZE 2147483647
Which you can run with the following PHP (best run just after you make a
connection).
mssql_query("SET TEXTSIZE 2147483647");
A better way to work around the issue is to change the "textlimit" and
"textsize" settings within php.ini, like so:
mssql.textlimit = 2147483647
mssql.textsize = 2147483647
Your MSSQL driver is truncating the text. If you can't change datatypes, drivers, etc., this should fix the issue for you.

Categories