Sybase dblib stored procedure - sybase

I am using Sybase DB and using dblib interface( C++ Interface) to connect and pass commands to Sybase DB.
I have one stored procedure added to Sybase DB. Below is the signature of stored procedure:
create procedure process_write #id varchar(35), #pTime datetime,#status tinyint
and I am calling this stored procedure with below :
process_write '000000100', '22/9/2022 10:18:37', 1
Now when I run my code I do not see error on console and the stored procedure executes successfully, But when I run this in isql command prompt, I get below error:
Msg 247, Level 16, State 1:
Server 'ABCXYZ', Procedure 'process_write':
Arithmetic overflow during implicit conversion of VARCHAR value '22/9/2022 10:18:37' to a DATETIME field .
(return status = -6)
I am not able to figure out how this is working in code but failing in isql console?

tl;dr
ASE defaults to processing strings of the format X/Y/Z as M/D/Y and this likely explains why your isql session is generating an error (ie, your isql session is running with mdy as its default dateformat). My guess is that somewhere in your dblib/C++ code you've either modified the dateformat or the language used by the dblib/C++ session which in turn insures your proc call works (ie, no conversion errors are generated).
I don't work with dblib/C++ so I don't know if you need to modify a db connection attribute or if you just issue a T-SQL command upon successful connection, eg:
set dateformat 'dmy'
In Sybase ASE when processing strings as dates it's necessary to tell ASE the ordering of the date components in strings like X/Y/Z.
From a strictly T-SQL point of view there are two set options that can tell ASE how to interpret X/Y/Z as a date:
set dateformat <format> - where <format> is one of 'mdy', 'myd', 'ymd', 'ydm', 'dmy' and 'dym'; default is 'mdy'
set languange <language> - where <language> is going to be based on what languages you've loaded into ASE; default is 'us_english' which causes the dateformat to default to 'mdy' [I don't have details on if/how individual languages may modify the dateformat so you would need to run some tests in your environment]
NOTES:
see T-SQL Users Guide: Date Formats and Reference Manual: Commands: set for more details.
to see the current dateformat in use for your session: select get_appcontext('SYS_SESSION','dateformat')
Demonstrating the use of set dateformat with a stored proc:
create proc testp
#pTime datetime
as
select #pTime
go
-------------
select get_appcontext('SYS_SESSION','dateformat')
go
---
mdy <<<--- ASE default
exec testp '22/9/2022 10:18:37'
go
Msg 247, Level 16, State 1:
Server 'ASE400', Procedure 'testp':
Arithmetic overflow during implicit conversion of VARCHAR value '22/9/2022 10:18:37' to a DATETIME field .
----------------
set dateformat 'dmy'
go
select get_appcontext('SYS_SESSION','dateformat')
go
---
dmy
exec testp '22/9/2022 10:18:37'
go
-------------------
Sep 22 2022 10:18AM

Related

Passing datetime as parameter in sybase stored procedure

i'd like to pass a datetime as parameter for a sybase stored procedure and use it for a query, but i always get the error
SQL Error: Syntax error during explicit conversion of VARCHAR value '2021-06-16 13:28:48.390' to a DATETIME field
My stored procedure is like:
create proc mystoredprocedure
#mydate varchar(50)
select * from mytable where date =CONVERT(DATETIME, #mydate, 121)
Call:
exec mystoredprocedure '2021-06-16 13:28:48.390'
Sybase docu for CONVERT code 121:
yyyy-mm-dd hh:nn:ss.sss (24 hour clock, ODBC canonical with milliseconds, 4-digit year)
Does anybody know why i get this error?
Thank you very much!
Andi
Assuming this is Sybase ASE ...
I'm unable to reproduce the issue in my ASE 15.7 instance (ie, your code works for me).
Can you try explicitly telling ASE how to parse the string by using the set dateformat command?
From the manauls re: the set command:
set dateformat format – sets the order of the date
parts (month/day/year) for entering datetime, smalldatetime, date
or time data. Valid arguments are 'mdy', 'dmy', 'ymd', 'ydm', 'myd',
and 'dym'. The us_english language default is 'mdy'.
In this case you'll want to try set dateformat 'ymd'.

SQL Server Collation problem (Msg 468, Level 16, State 9) in IF statement

My problem is occurring with a "simple-as-it-gets" IF statement, making the suggested fixes to many similar questions (e.g. Cannot resolve the collation conflict in my query) seemingly useless.
The error message is :
Msg 468, Level 16, State 9, Procedure #XYZ, Line 11
Cannot resolve the collation conflict between "Latin1_General_CI_AS" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.
It's known that the server collation is set to SQL_Latin1_General_CP1_CI_AS.
This query demonstrates the problem :
-- this procedure (which gets put into tempdb) is called WITHOUT specifying #Choice
CREATE PROCEDURE #XYZ
(
-- all other parameters removed (none of them have default values)
#Choice AS NVARCHAR(1) = 'Y'
)
AS
BEGIN
IF (#choice = 'Y') -- error raised here
BEGIN
DECLARE #NULL_STATEMENT AS int -- only here because there's no "do nothing" statement
END
RETURN
END
How can I fix this, given that altering the default collation of the server (and/or all of the tables) is NOT going to happen AND it is impractical to insert "COLLATE DATABASE_DEFAULT" in all queries, tables, etc. (for this solution see https://www.mssqltips.com/sqlservertip/4395/understanding-the-collate-databasedefault-clause-in-sql-server/ and Cannot resolve the collation conflict between temp table and sys.objects).
Closely related links:
Documentation of the COLLATE clause: https://learn.microsoft.com/en-us/sql/t-sql/statements/collations?view=sql-server-2017
A solution that I probably cannot use: https://www.mssqltips.com/sqlservertip/2901/how-to-change-server-level-collation-for-a-sql-server-instance/
(From the currently accepted answer):
The fix was to change the default parameter from ASCII (varchar) to nvarchar (UTF-8) form
No, that did not fix it. That particular change had no effect since the value was converted to NVARCHAR when the T-SQL was parsed (due to the parameter/variable being NVARCHAR) and this error happens at compile time.
This issue has absolutely nothing to do with NVARCHAR, UTF-8, or even parameter default values.
UTF-8 is not being used here. SQL Server is only seeing UTF-16 as that is what Unicode strings are transferred in by the driver (i.e. the TDS / tabular data stream). And even when using a UTF-8 collation (new in SQL Server 2019), that encoding is only used with VARCHAR types as NVARCHAR is only ever UTF-16 (Little Endian).
The issue you ran into is one of several "odd" behaviors found in temporary stored procedures (both local and global). For temporary stored procs, parameters and variables will always have a collation matching the tempdb collation, while string literals will use the collation of the database where the CREATE PROCEDURE statement was executed. These two collations do not change (for the main T-SQL context of the module) even if you use another database that has a different default collation other than [tempdb] and the database where the temporary proc was created (though dynamic SQL executed in a temporary stored procedure will use the current DB's collation! Fun, eh?).
Thus, as Martin Smith said in a comment on the question, you must have changed the "current" / "active" database when executing the CREATE PROCEDURE statement after prefixing the parameter value with N.
The following example is a simplified version of the code shown in the question, but clearly shows that prefixing the string literals with N does not prevent the error.
Execute the following T-SQL in a database that has a different collation than [tempdb]:
-- The two returned collations need to be different, else no error with CREATE PROC:
SELECT DATABASEPROPERTYEX(N'tempdb', 'collation') AS [tempdb collation],
DATABASEPROPERTYEX(DB_NAME(), 'collation') AS [current DB collation];
SET NOEXEC ON;
GO
CREATE PROCEDURE #XYZ
(
#Choice NVARCHAR(5) = N'Y'
)
AS
BEGIN
IF (#Choice = N'Y') PRINT 'yup';
END;
GO
SET NOEXEC OFF;
/*
Msg 468, Level 16, State 9, Procedure #XYZ, Line XXXXX [Batch Start Line YYYYY]
Cannot resolve the collation conflict between "{current_DB_collation}" and
"{tempdb_collation}" in the equal to operation.
*/
(From the currently accepted answer):
The weird thing is that after running that version I was able to remove the leading N and the query worked without problems.
Correct. That's due to the N prefix not actually having anything to do with the error or fixing it. You were simply in a DB that had a collation of SQL_Latin1_General_CP1_CI_AS which matched the [tempdb] collation.
I'm working on a blog post detailing several odd behaviors with temporary stored procedures, including this collation stuff. If / when I ever finish it, I will try to remember to update this answer with a link to it.
I've summarized the answer provided by #Sean Lange (a variation of #Lamak's comment) as it was was deleted before I could accept it.
The problem (for details see comments on original question) was that I hit a gotcha! while moving the working code to a new server. The fix was to change the default parameter from ASCII (varchar) to nvarchar (UTF-8) form :
CREATE PROCEDURE #XYZ
(
-- all other parameters removed (none of them have default values)
#Choice AS NVARCHAR(1) = N'Y' -- Note the leading N
)
AS
....
The wierd thing is that after running that version I was able to remove the leading N and the query worked without problems.

ORA-1861: literal does not match format string

I've encountered a quite strange behavior of a procedure called from various environments. The procedure is implemented in Oracle environment.
function licence_update(p_licence ax_import_licence_vw%rowtype) return number;
When I run the statement from Oracle everything is allright:
declare l_res number := null; begin l_res := licence_update(p_licence); end;
But when the same procedure is called from MS SQL using OPENROWSET I get an error
ORA-1861: literal does not match format string.
EXECUTE ('BEGIN licence_update(p_licence); END;') AT LinkedServer;
There is a date attribute in the view ax_import_licence_vw, that certainly cause the error. If I take out this attribute the procedure always finished successfully.
So, I guess it happens because of NLS_DATE_FORMAT that is set up differently when the procedure is called. I took a look at the log table and found out the following information about nls_date_formats:
from Oralce: DD.MM.RR
from MS SQL: YYYY-MM-DD HH24:MI:SS
What kind of converting operation should be done to that date attribute to get rid of this error?

Query in SQL Server Management Studio fails to pass date to linked InterSystems server

I have a SQL Server and Cache server and need to combine some data. Most all functions are working, except when I attempt to pass a date with a variable or a parameter.
Below is a test I ran (one of many).
declare #myDate datetime
set #myDate = convert(datetime,'2012-02-01',120)
select * from ccms..dbo.dcdnstat where timestamp > '2012-02-01' -- WORKS
exec( 'select * from dbo.dcdnstat where cdn = ?', 21004) at ccms -- WORKS
exec( 'select * from dbo.dcdnstat where timestamp > ?',#myDate) at ccms -- ERROR 7213
select * from ccms..dbo.dcdnstat where timestamp > #myDate -- ERROR 7322
Msg 7213, Level 16, State 1, Line 9 The attempt by the provider to
pass remote stored procedure parameters to remote server 'ccms'
failed. Verify that the number of parameters, the order, and the
values passed are correct. Msg 7322, Level 16, State 2, Line 11 A
failure occurred while giving parameter information to OLE DB provider
"MSDASQL" for linked server "ccms".
I have tried different date formats, and as shown above I can query on other fields with variables and I can query on date if I use a specific value.
Instead of a "DATETIME" type for your stored procedure parameter, just use "DATE"
(as long as you don't need the time requirements)
I had a problem similar to this today. It had to do with the fact that the calling server and the linked server were not the same version. One was SQL Server 2005 and the other was SQL Server 2008. The problem was due to the fact that the column being queried against at the remote end (2008) was a datetime2 and the calling server (2005) does not support datetime2.
I know this is a little late but I stumbled upon it looking for something similar with the Cache system. Looks like we are working on the same backend system. Mine is the Avaya CCMS system. Here is what I do to pass dates as variables:
DECLARE #myDate DATETIME
SET #myDate = CAST('2012-07-01' AS DATETIME)
SELECT SUM(CallsOffered), SUM(CallsAnswered), SUM(SkillsetAbandonedAftThreshold)
FROM AvayaCCMS..dbo.mSkillsetStat
WHERE Timestamp = #myDate
I was doing something very similar using a Sybase database as the linked server. Just as MobileMon said, I was able to change the datetime to date and it works fine now.
declare #myDate date
set #myDate = convert(datetime,'2012-02-01',120)

Change default date time format on a single database in SQL Server

I need to change the date format from US (mm/dd/YYYY) to UK (dd/mm/YYYY) on a single database on a SQL server machine.
How can this be done?
I've seen statements that do this for the whole system, and ones that do it for the session, but I can't change the code now as it will have to go through QA again, so I need a quick fix to change the date time format.
Update
I realize that the date time has nothing to do with how SQL Server stores the data, but it does have a lot to do with how it parses queries.
I'm chucking raw data from an XML file into a database. The dates in the XML file are in UK date format.
You could use SET DATEFORMAT, like in this example
declare #dates table (orig varchar(50) ,parsed datetime)
SET DATEFORMAT ydm;
insert into #dates
select '2008-09-01','2008-09-01'
SET DATEFORMAT ymd;
insert into #dates
select '2008-09-01','2008-09-01'
select * from #dates
You would need to specify the dateformat in the code when you parse your XML data
In order to avoid dealing with these very boring issues, I advise you to always parse your data with the standard and unique SQL/ISO date format which is YYYY-MM-DD. Your queries will then work internationally, no matter what the date parameters are on your main server or on the querying clients (where local date settings might be different than main server settings)!
You can only change the language on the whole server, not individual databases. However if you need to support the UK you can run the following command before all inputs and outputs:
set language 'british english'
Or if you are having issues entering datatimes from your application you might want to consider a universal input type such as
1-Dec-2008
Although you can not set the default date format for a single database, you can change the default language for a login which is used to access this database:
ALTER LOGIN your_login WITH DEFAULT_LANGUAGE=British
In some cases it helps.
If this really is a QA issue and you can't change the code. Setup a new server instance on the machine and setup the language as "British English"
Use:
select * from mytest
EXEC sp_rename 'mytest.eid', 'id', 'COLUMN'
alter table mytest add id int not null identity(1,1)
update mytset set eid=id
ALTER TABLE mytest DROP COLUMN eid
ALTER TABLE [dbo].[yourtablename] ADD DEFAULT (getdate()) FOR [yourfieldname]
It's working 100%.
You do realize that format has nothing to do with how SQL Server stores datetime, right?
You can use set dateformat for each session. There is no setting for database only.
If you use parameters for data insert or update or where filtering you won't have any problems with that.
For SQL Server 2008 run:
EXEC sp_defaultlanguage 'username', 'british'

Resources