FireDAC Query dropping special characters in SQL statement to SQL Server - sql-server

I have hit this issue off and on in Delphi 10.3 using FireDAC and the EMS Rad Server. I have not experienced it in Delphi 10.2 or below, but I am not using FireDAC anywhere but in Delphi 10.3.
The issue I am experiencing is some special characters seem to be getting stripped out of the SQL statements before they reach the Database.
For example, if I run:
update messageread set
MessageDeliveredDateTime = '8/11/2020 6:33:45 PM'
where messageread.dts in ('5/7/2020 12:48:20 PM-!+[[786', '5/7/2020 12:47:06 PM-!#[[782', '5/7/2020 12:43:35 PM-&K[[775', '5/7/2020 12:41:01 PM-&K[[773')
what gets executed on the SQL server is:
update messageread set MessageDeliveredDateTime = '8/11/2020 6:33:45 PM' where messageread.dts in ('5/7/2020 12:48:20 PM-+[[786', '5/7/2020 12:47:06 PM-[[782', '5/7/2020 12:43:35 PM-[[775', '5/7/2020 12:41:01 PM-[[773')
It appears to be dropping 2 characters after the "-". Because it is 2 characters, it makes me thing its some Unicode thing.
In the past, I have worked around this by using parameterized queries, but in this case, it still isn't helping. The Delphi code that I am currently running is:
fdTemp.SQL.Text := 'update messageread set MessageDeliveredDateTime = ' + QuotedStr(DateTimeToStr(now)) + ' where messageread.dts in (' + sUpdateDTS + ')';
fdTemp.ExecSQL;
sUpdateDTS = '5/7/2020 12:48:20 PM-!+[[786', '5/7/2020 12:47:06 PM-!#[[782', '5/7/2020 12:43:35 PM-&K[[775', '5/7/2020 12:41:01 PM-&K[[773'
Where fdTemp is TFDQuery and DTS is the primary key of the table.
If I take the SQL statement and run it in Mgt Studio, it works just fine. However when run from Delphi, 0 rows are affected because nothing matches the where clause.
Does anyone have any idea?

Some characters in SQL commands have special meaning in FireDAC and thus have to be entered in a special way. In your case an identifier starting with & is treated as a macro.
You can suppress that by setting ResourceOptions.MacroCreate to false.
More info on special character handling in FireDAC can be found in the documentation:
Special Character Processing

Related

Why does SQL Server Management Studio get these syntax errors from copied code

So while testing some code, I discovered odd behavior with code I had pasted in a query window. Below is a simplified example of where I got the code from:
declare #a nvarchar(max) = '';
select #a = 'select ' + cast(n as char(1)) + ';' + char(13) + 'GO' + char(13) from nums where n = 1;
print #a
exec sp_executesql #a
This was executed in a query window in SSMS. It errors, of course, because of that GO delimiter that won't work in dynamic SQL.
However, just so I could confirm the code itself was OK, I copied it into a new query window. To continue the example:
select 1;
GO
select 1
GO
The first statement gives a syntax error, and the second treats the GO as a column alias. Interestingly, this continued to be true if I just typed code directly into that query window. It didn't affect other windows or new ones, just the one I had pasted the PRINT results into.
The last interesting fact about this is that if I compared doing a LEN() on the above example in the "bad" query window versus one that works as expected, the "bad" query is 26 characters long, but the normal one is 31.
I found that backspacing all the characters didn't seem to help, but that if I did a Select All and did a delete that this seemed to fix it. I assume this means it's getting a non-printable character, but if I do a Select All and copy into Notepad++ with a Show All Symbols option, I don't see anything of note.
Does anyone know why SSMS is behaving this way? I'm using version 17.9 (and running against a SQL Server 2014 instance if that matters).
char(13) is Carriage Return (CR).
char(10) is Linefeed (LF).
Windows uses CRLF as a line terminator.
Linux uses LF as a line terminator.
No modern environment uses just CR as a line terminator as your script does. SSMS happens to render CR by inserting vertical space, and this behavior probably is inherited from the underlying Visual Studio codebase.
SSMS's TSQL batch parser, however, doesn't recognize CR as a line terminator, so it doesn't look for the GO symbol following CR. It works with LF or CRLF.

why 12c with extended varchar2 limit still converting sql server varchar(max) to long

Oracle version 12.1.0.2
max_string_size=extended
I am using sql server ODBC to connect to sql server database via Oracle gateway to sql server, the connection is working fine and i am able to access sql server tables.
However, as per Oracle documentation starting 12c and with extended limit on varchar2 data type the conversion of sqlserver varchar(max) to oracle Long will only happen if the length of sql server data is more than 32k.
My sql server table has few columns defined as varchar(max) in and all of those i see getting converted to LONG when i try to describe the table over dblink.
I need to load the data from sql server to oracle and the above problem is making it very difficult as more than one long columns can not be copied over dblink.
Any help will be deeply appreciated.
I created a view on the SQL server side that uses substr(column,1,4000) to fit within the old Oracle max 4000 character length. This worked quite well with Oracle 11.
I am in the process of migrating to a new Oracle 18 instance that uses character set AL32UTF8 instead of WE8MSWIN1252. The exact same SQL is now getting:
ORA-28500: connection from ORACLE to a non-Oracle system returned this message:
[Microsoft][ODBC Driver Manager] Program type out of range {HY003}
ORA-02063: preceding 2 lines from CEAV195
Fortunately I don't have a tight deadline for working this out.
Comment: I am now getting
[Error] Execution (8: 17): ORA-00997: illegal use of LONG datatype
despite using the following in the view on the SQL Server side:
cast(substring(cr.response,1,2000) as varchar(2000)) response
As I said earlier, this worked perfectly fine with Oracle 11 and the WE8MSWIN1252 character set.
I hit the same issue and found this solution elsewhere
set serverout on
DECLARE
l_cursor BINARY_INTEGER;
l_id VARCHAR2(60);
l_temp VARCHAR2(250);
l_notes VARCHAR2(32767);
BEGIN
l_cursor := DBMS_HS_PASSTHROUGH.open_cursor#remotedb;
DBMS_HS_PASSTHROUGH.parse#remotedb(
l_cursor,
'select "RecId","Notes" from "MySqlServerTable"'
);
LOOP
DBMS_HS_PASSTHROUGH.get_value#remotedb(l_cursor, 1, l_id);
DBMS_HS_PASSTHROUGH.get_value#remotedb(l_cursor, 2, l_notes);
DBMS_OUTPUT.put_line(l_id || ' ' || l_notes);
END LOOP;
exception
when others then
DBMS_HS_PASSTHROUGH.close_cursor#remotedb(l_cursor);
raise;
END;
/

Incorrect syntax in SQL Server 2008R2 script containing 0x0A character

I am running a select statement which contains the following CASE clause:
SELECT
(CASE MyTable.IsBook WHEN 1 THEN  'B' ELSE  'M' END) AS IsBookOrManuscript
FROM MyTable;
I have the same exact database(schema and data) restored in two different physical servers running SQL Server 2008 R2 with build version 10.50.4276.0 and SQL Server 2014 respectively.
When run in SQL Server 2014 the query returns as expected. When run in SQL Server 2008R2 the error message Incorrect syntax near ' '. occurs.
Searching the script file for non-ascii characters I found that indeed, three occurrences of 0x0A character appear in the CASE line and removing it solves the problem in SQL Server 2008R2.
Does anyone know why that happens? Is it an intended behavior? As far as I can see there are 2 CUs released since my last update BUT they do not seem to fix or recognize the problem. Any thoughts?
Check the Setting of
QUOTED_IDENTIFIER
on each server.
as MSDN says:
Causes SQL Server to follow the ISO rules regarding quotation mark delimiting identifiers and literal strings. Identifiers delimited by double quotation marks can be either Transact-SQL reserved keywords or can contain characters not generally allowed by the Transact-SQL syntax rules for identifiers.
so try the next code:
SET QUOTED_IDENTIFIER off
-- Type your code here
SET QUOTED_IDENTIFIER On

Determine ODBC database driver from TADOConnection object?

Using Delphi 7 with ADO objects, is it possible to determine the ODBC database driver from the TADOConnection object? So detect whether it is MS-Access or SQL Server or Oracle etc.
The program connects to a database by just using the name of an ODBC data source, and I want to determine whether that database is an MS-Access database or SQL Server. I want to do this because MS-Access and SQL Server use different SQL function names to cast an integer to a string.
The application builds an SQL string which retrieves the VERSION of some configuration objects. It works for SQL server using cast(), but I also want to support MS-Access which uses CStr():
SELECT NAME + '_' + CAST(VERSION as varchar) as OBJECT_NAME FROM ANALYSIS // SQL Server
SELECT NAME + '_' + CStr(VERSION) as OBJECT_NAME FROM ANALYSIS // MS-Access
I've tried looking at the TADOConnection.Provider but that is MSDASQL.1 in both cases.
if (myqry.Connection.Provider = 'MSDASQL.1') then
strSQL := strSQL + 'cast(' + myfieldname + ' as varchar)' // always goes here..
else
strSQL := strSQL + 'CStr(' + myfieldname + ')'; // ..never to here
I've looked at all the TADOConnection properties, but I'm starting to suspect it's not possible. Any ideas how to solve this?
ODBC is designed to abstract away the implementation details of the server. You can use ODBC specific syntax that will be translated to a statement of the appropriate SQL flavour for the server. Here you can substitute :
... { fn CONVERT( VERSION, SQL_VARCHAR ) } AS OBJECT_NAME FROM ANALYSIS
These substitutions are known as ODBC Escape Sequences and can be substituted in queries where there are vendor-specific syntax differences.

sp_generate_inserts for SQL Server 2008

I've been using Narayana Vyas Kondreddi's excellent stored procedure sp_generate_inserts http://vyaskn.tripod.com/code/generate_inserts.txt in a SQL Server 2005 database.
But after moving to SQL Server 2008 I get weird results where a long whitespace is inserted after UNIQUEIDENTIFIER values:
INSERT INTO [BannerGroups]([Id], [DescriptionText], [Width], [Height])
VALUES('BFCD0173-9432-47D1-84DF-8AB3FB40BF76 ', 'Example', 145, NULL)
Anyone know how to fix this?
Appears to be this section, just over half way down:
WHEN #Data_Type IN ('uniqueidentifier')
THEN
'COALESCE('''''''' + REPLACE(CONVERT(char(255),RTRIM(' + #Column_Name + ')),'''''''','''''''''''')+'''''''',''NULL'')'
See it's converting to a CHAR(255) which means the value is being padded out to 255 characters. Change that to VARCHAR instead and it should be fine as that will not pad the values out with spaces.
Since SQL Server 2008 we can generate the INSERT scripts via Generate Script utility itself.
For more detailed answer check out - What is the best way to auto-generate INSERT statements for a SQL Server table?

Resources