I am writing a procedure take the data from the web service. The web services gives the data in an XML string. However, It is truncating the data being pulled from the website. It runs perfectly when executed in SSMS. It truncated the data to 2048 characters when run through a batch file and truncated the data to 512 characters when run using a SS Job.
These values can not be random. There must be a setting somewhere but I can't find it. Any ideas?
Here's the code:
DECLARE
#url nvarchar(max),
#win integer,
#hr integer ,
#Date date,
#SearchDate nvarchar(50)
Set #Date = GETDATE()
set #SearchDate = CAST(#Date as nvarchar(50))
set #SearchDate = REPLACE(#SearchDate,'-','')
CREATE TABLE TextData([SEMO_Data] [nvarchar](max) NULL)
Select #url = 'http://semorep.sem-o.com/DataCollection/DataSets.asmx/queryDatasetXML?DatasetName=SET_CAL&User=primplims#gmail.com&Password=testsemo&FromDate=20130103&ToDate=20130111&P1=Energy&P2=Statements&P3=Initial&P4=&P5='
EXEC #hr=sp_OACreate 'WinHttp.WinHttpRequest.5.1',#win OUT
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
EXEC #hr=sp_OAMethod #win, 'Open',NULL,'GET',#url,'false'
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
EXEC #hr=sp_OAMethod #win,'Send'
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
INSERT XMLParsing.dbo.TextData(SEMO_Data)
EXEC #hr=sp_OAGetProperty #win,'ResponseText'
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
EXEC #hr=sp_OADestroy #win
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
This is a follow on from my last question. Am hoping that it will be seen easier if I post a new question.
I know it's too late, 2022, but i had the same problem today, this solved for me:
https://stackoverflow.com/a/38918970/1750527
Spoiler: queries run outside SSMS has a default text size of 2048. I needed to add a
SET TEXTSIZE 2147483647;
before my script so it run properly.
Related
I am trying 30 days free trial of Chilkat and I am not getting any results in SQL, nor error information (unless it is a string text value, hardcoded). I have installed the module on the server and it confirms correctly
For example this piece of code with obviously incorrect address just runs through without any feedback (the code is from their tutorial - apart from the address - so should be technically correct)
DECLARE #hr int
DECLARE #iTmp0 int
DECLARE #sTmp0 nvarchar(max)
DECLARE #rest int
EXEC #hr = sp_OACreate 'Chilkat_9_5_0.Rest', #rest OUT
IF #hr <> 0
BEGIN
PRINT 'Failed to create ActiveX component'
RETURN
END
-- Connect to the REST server.
DECLARE #bTls int
SELECT #bTls = 1
DECLARE #port int
SELECT #port = 443
DECLARE #bAutoReconnect int
SELECT #bAutoReconnect = 1
DECLARE #success int
EXEC sp_OAMethod #rest, 'Connect', #success OUT, 'www.incorrect_address.co', #port, #bTls, #bAutoReconnect
IF #success <> 1
BEGIN
EXEC sp_OAGetProperty #rest, 'LastErrorText', #sTmp0 OUT
PRINT #sTmp0
EXEC #hr = sp_OADestroy #rest
RETURN
END
the Global Unlock method returns message that it is working
'Unlocked in trial mode.'
do you have any idea why it does not work? Any messages hardcoded (like 'unlocked in trial mode') are working but anything that should return values of objects - does not. I have of course enabled Configuration option 'Ole Automation Procedures' in SQL
Slav
The contents of the LastErrorText property is likely too large for limits imposed by sp_OAGetProperty. Try using a temp table like this:
DECLARE #tmp1 TABLE (lastErrText ntext)
INSERT INTO #tmp1 EXEC sp_OAGetProperty #rest, 'LastErrorText'
SELECT * from #tmp1
I am trying to extract a blob file from SQL Server. I was able to get it to execute successfully but when I look in my Desktop\consol\output directory, the file isn't there (refreshed, still nothing). Here is the code:
SELECT * FROM FileWarehouse
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
DECLARE #SQLIMG VARCHAR(MAX),
#File VARBINARY(MAX),
#OpPath VARCHAR(MAX),
#ObjectToken INT
SELECT #File = StoredFile FROM [dbo].[FileWarehouse] WHERE Id= 157994
SET #OpPath = 'C:\Users\Nick\Desktop\consol\output\marksheet.doc'
EXEC sp_OACreate 'ADODB.Stream', #ObjectToken OUTPUT
EXEC sp_OASetProperty #ObjectToken, 'Type', 1
EXEC sp_OAMethod #ObjectToken, 'Open'
EXEC sp_OAMethod #ObjectToken, 'Write', NULL, #File
EXEC sp_OAMethod #ObjectToken, 'SaveToFile', NULL, #OpPath, 2
EXEC sp_OAMethod #ObjectToken, 'Close'
EXEC sp_OADestroy #ObjectToken
GO
In the SELECT statement, dbo.[FileWarehouse] and StoredFile are both underlined, saying 'Invalid Object Name' and 'Invalid Column Name', respectively. They are definitely valid, so I'm not sure it's saying that. Here is the tutorial I was following https://www.youtube.com/watch?v=8g7_F3Ice6E .
Any help would be greatly appreciated. Thank You.
While Dan's answer is correct (use Powershell or SQL CLR instead), the reason your COM automation isn't working, is that you've failed to capture and inspect the return codes from the extended stored procedures.
Here's an example:
--exec sp_configure 'Show Advanced Options', 1
--reconfigure
--exec sp_configure 'Ole Automation Procedures', 1
--reconfigure
declare #url varchar(2000) = 'http://www.bing.com'
declare #hr int;
declare #win int;
begin try
EXEC #hr=sp_OACreate 'WinHttp.WinHttpRequest.5.1',#win OUT
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
EXEC #hr=sp_OAMethod #win, 'Open',NULL,'GET',#url,'false'
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
EXEC #hr=sp_OAMethod #win,'Send'
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
declare #status int
EXEC #hr=sp_OAGetProperty #win,'Status', #status out
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win
if #status <> 200
begin;
declare #msg varchar(2000) = concat('web request failed ', #status);
throw 60000, #msg, 1;
end;
declare #response table(text nvarchar(max));
insert into #response(text)
EXEC #hr=sp_OAGetProperty #win,'ResponseText';
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win;
select * from #response;
EXEC #hr=sp_OADestroy #win
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win;
end try
begin catch
EXEC #hr=sp_OADestroy #win
IF #hr <> 0 EXEC sp_OAGetErrorInfo #win;
throw;
end catch
The IntelliSense error is erroneous if the script runs.
I suggest you generally avoid the ole automation procs for new development. If you don't really need to use T-SQL to create the file, consider a simple PowerShell script. This is more robust and flexible for ad-hoc needs. Below is an example that uses the standard ADO.NET objects.
$connection = New-Object System.Data.SqlClient.SQLConnection("Data Source=YourServer;Initial Catalog=YourDatabase;Integrated Security=SSPI")
$command = New-Object System.Data.SqlClient.SqlCommand("SELECT StoredFile FROM [dbo].[FileWarehouse] WHERE Id= 157994;", $connection)
$connection.Open()
$blob = $connection.ExecuteScalar()
$connection.Close()
[System.IO.File]::WriteAllBytes("C:\Users\Nick\Desktop\consol\output\marksheet.doc", $blob)
This is part of my procedure to return #v_buffer variable.
Problem is that, the size of file i want to upload is greater than 8000 bytes. That's why i need to use varbinary(max) type.
But sp_oamethod read returns me an error.
Is someone know hot to use sp_oamethod to solve my problem?
declare #returnCode int
declare #v_file int
declare #v_buffer varbinary(max)
declare #v_fullpath nvarchar(400) --pdf file phusical location
exec #returncode = sp_oacreate 'adodb.stream', #v_file out
exec #returncode = sp_oamethod #v_file, 'open'
exec #returncode = sp_oasetproperty #v_file, 'type', 1
exec #returncode = sp_oasetproperty #v_file, 'loadfromfile', #v_fullpath
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out, -1
if #returncode <> 0
begin
exec sp_oageterrorinfo #v_file
end
exec #returnCode = sp_OAMethod #v_file, 'Close'
exec #returnCode = sp_OADestroy #v_file
Error message returned by sp_oageterrorinfo:
0x8004271A, ODSOLE Extended Procedure, Error in srv_convert.
Please do not use the OLE Automation stored procedures (i.e. sp_OA* ) as they have been deprecated since SQL Server 2005 was released. What you are trying to do is rather simple with SQLCLR (i.e. .NET-based objects that exist within SQL Server). You can create a scalar function to accept a filepath and return its bytes using the File.ReadAllBytes method. Return that byte[] via the SqlBytes type.
You will need to set your Assembly to PERMISSION_SET = EXTERNAL_ACCESS. In order to accomplish that, please do not set the database to TRUSTWORTHY ON as that is an unnecessary security risk. Instead, sign the Assembly (using a password), then create an Asymmetric Key in the master Database from the DLL, then create a Login from that Key, and finally grant the Login the EXTERNAL ACCESS ASSEMBLY permission.
For a lot more information on working with SQLCLR, including many examples, please see the series of articles I am writing on this topic on SQL Server Central: Stairway to SQLCLR (that site does require free registration in order to read their content).
Or, if you don't want to deal with any coding, I created a library of over 270 functions and stored procedures called SQL#. There are several file system related functions, though none of them are available in the Free version. Still, the one that would help here is called: File_GetFileBinary.
If you try to pass a string that is greater than 4000 characters but less than or equal to 8000 characters in length to the sp_OASetProperty or to the sp_OAMethod OLE Automation extended stored procedure, the input string is silently truncated to 4000 characters before it is passed to the object and no error is returned.
If you try to set a property to a string that is greater than 8000 characters through the sp_OASetProperty OLE Automation extended stored procedure, or if you try to pass an input parameter to the sp_OAMethod OLE Automation extended stored procedure that is longer than 8000 characters, you receive the following error message:
hr Source Description
---------- ---------------------------- --------------------------
0x8004271A ODSOLE Extended Procedure Error in srv_convert.
https://support.microsoft.com/en-us/kb/325492
If someone had same problem, i have done it like this:
In my procedure i create temp #IMG table:
create table #IMG (FileID2 nvarchar(50), img image)
If the file size is greater than 8k, i split it to parts in size 8000 and update #IMG:
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out, 8000
update #IMG set img = #v_buffer
SELECT #ptrval = TEXTPTR(Img) FROM #IMG WHERE FileID2 = #v_FileID2
--file split section
select #v_Blocks = #v_FileSize/8000+1
if #v_Blocks = 1
begin
WRITETEXT #IMG.Img #ptrval #v_buffer
end
else
begin
WRITETEXT #IMG.Img #ptrval #v_buffer
set #j=#v_blocks-1
while #j>0
begin
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out , 8000
set #i=(select DATALENGTH(Img) from #IMG WHERE FileID2= #v_FileID2)
UPDATETEXT #IMG.Img #ptrval #i 0 #v_buffer
set #j=#j-1
end
end
You could use the same workaround as described at 0x8004271A ODSOLE Extended Procedure Error in srv_convert.
In your case, the line
exec #returnCode = sp_oamethod #v_file, 'read', #v_buffer out, -1
should be replaced by
Create table #tmp(dt varbinary(max))
insert into #tmp
exec #hr = sp_oamethod #v_file, 'read', #mode = -1
Select dt from #tmp -- single column/single row.
Drop Table #tmp -- clean up
Caution: this code wasn't tested. However the following code works fine for 32KB xml output:
Create table #tmp(dt xml)
insert into #tmp
exec #hr = sp_OAGetProperty #obj, 'responseXML.XML'
/*
Here is the trick: inserting from the returned result set, i.e.
`insert into <table>(<columns>) select <columns>`
*/
Select dt from #tmp -- single column/single row.
Drop Table #tmp -- clean up
responseXML.XML returns the whole xml document after calling MSXML2.ServerXMLHttp.send. The trick works according to section Result Sets of sp_OAMethod.
When the table variable type is available, the code can be even shorter:
DECLARE #xml(val xml);
insert into #xml
exec #hr = sp_OAGetProperty #obj, 'responseXML.XML'
Select * from #xml; -- just to see the output
I.e. there is no need to clean up.
I received the same issue. Apparently, you cannot use sp_OAMethod with a VARBINARY(MAX) variable.
Try changing: declare #v_buffer varbinary(max)
to declare #v_buffer varbinary(8000).
Good luck!
I have a basic query, and i'd like to email the results. How can I do this at the query level? So if my query is:
SELECT
Store_Id, Paid_Out_Amount, Paid_Out_Comment,
Paid_Out_Datetime, Update_UserName
FROM Paid_Out_Tb
WHERE (Store_Id = 1929) OR
(Paid_Out_Amount > 50) AND
(Paid_Out_Datetime BETWEEN
CONVERT(DATETIME, '2012-06-01 00:00:00', 102) AND
CONVERT(DATETIME, '2012-06-30 00:00:00', 102))
How would I email the output? I have a procedure to send email via SMTP and the parameters are #From, #To, #Subject and #body... which works.. How would I make the body the outcome of the query?
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
CREATE PROCEDURE [dbo].[sp_SQLNotify]
#From varchar(100) ,
#To varchar(100) ,
#Subject varchar(100)=" ",
#Body varchar(4000) = "Test"
/*********************************************************************
This stored procedure takes the above parameters and sends an e-mail.
All of the mail configurations are hard-coded in the stored procedure.
Comments are added to the stored procedure where necessary.
Reference to the CDOSYS objects are at the following MSDN Web site:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_messaging.asp
***********************************************************************/
AS
Declare #iMsg int
Declare #hr int
Declare #source varchar(255)
Declare #description varchar(500)
Declare #output varchar(1000)
--************* Create the CDO.Message Object ************************
EXEC #hr = sp_OACreate 'CDO.Message', #iMsg OUT
--***************Configuring the Message Object ******************
-- This is to configure a remote SMTP server.
-- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_schema_configuration_sendusing.asp
EXEC #hr = sp_OASetProperty #iMsg, 'Configuration.fields("http://schemas.microsoft.com/cdo/configuration/sendusing").Value','2'
-- This is to configure the Server Name or IP address.
-- Replace MailServerName by the name or IP of your SMTP Server.
EXEC #hr = sp_OASetProperty #iMsg, 'Configuration.fields("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value', '10.1.1.10'
-- Save the configurations to the message object.
EXEC #hr = sp_OAMethod #iMsg, 'Configuration.Fields.Update', null
-- Set the e-mail parameters.
EXEC #hr = sp_OASetProperty #iMsg, 'To', #To
EXEC #hr = sp_OASetProperty #iMsg, 'From', #From
EXEC #hr = sp_OASetProperty #iMsg, 'Subject', #Subject
-- If you are using HTML e-mail, use 'HTMLBody' instead of 'TextBody'.
EXEC #hr = sp_OASetProperty #iMsg, 'TextBody', #Body
EXEC #hr = sp_OAMethod #iMsg, 'Send', NULL
-- Sample error handling.
IF #hr <>0
select #hr
BEGIN
EXEC #hr = sp_OAGetErrorInfo NULL, #source OUT, #description OUT
IF #hr = 0
BEGIN
SELECT #output = ' Source: ' + #source
PRINT #output
SELECT #output = ' Description: ' + #description
PRINT #output
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
RETURN
END
END
-- Clean up the objects created.
EXEC #hr = sp_OADestroy #iMsg
PRINT 'Mail Sent!'
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
This is the procedure i'm using to send the mail... which works... I just want to add a spot in it to send the results of the query above it... Can this be done easily within in the procedure?
Use the SQL Server Powershell pack. An example (with detailed explanation) of using it to obtain output is here.
(The above is taken from this SO answer, but to clarify something s/he says: SQL Server 2008 client components is required (Express should be fine), but it can work with SQL Server 2000 databases (source).)
You can also use a variable for a direct loop concatenation. See https://stackoverflow.com/a/4447564/1180926 (although you would use tab and newline delimiters instead of HTML code).
You would then just change your query accordingly, store it in #Body, and you're done!
Can I call a remote webservice from a Stored Procedure and use the values that areretuned?
If you're using SQL 2005/2008, you could do this from a CLR stored procedure if you have the ability to install and run these. For more info:
http://msdn.microsoft.com/en-us/library/ms190790.aspx
Service Broker might provide the sort of functionality you're looking for here.
As The AntiSanta says, using a CLR stored procedure this is possible. The real question is whether you can avoid it altogether. It feels upside-down to call a web service from a stored procedure. Ideally you'd have some other service/app/layer that calls both the stored procedure and a web service. Possibly the stored proc returns parameter values for the web service, and you commit your local transaction after the WS call is complete.
This would make both debugging, deployment and support much more simple in the long run, and decouples the direct reference between the stored proc and the web service.
On SQL Server 2000 and up (if CLR is not enabled), you can use COM through stored procedures (sp_OACreate, sp_OAMethod, etc) if you have an existing COM wrapper for your web service.
Here is my code that works.
exec #hr = sp_OACreate 'MSXML2.ServerXMLHttp', #obj OUT
if #hr < 0 begin Raiserror('sp_OACreate MSXML2.ServerXMLHttp failed',16,1)
return end
exec #hr = sp_OAMethod #obj, 'Open', NULL, 'GET', #UrlString, false
if #hr <0 begin set #msg = 'sp_OAMethod Open failed' goto eh end
exec #hr = sp_OAMethod #obj, 'send'
if #hr <0 begin set #msg = 'sp_OAMethod Send failed' goto eh end
exec #hr = sp_OAGetProperty #obj, 'status', #status OUT
if #hr <0 begin set #msg = 'sp_OAMethod read status failed' goto eh end
if #status <> 200 begin set #msg = 'sp_OAMethod http status ' +str(#status) goto eh end
exec #hr = sp_OAGetProperty #obj, 'responseText', #response OUT
if #hr <0 begin set #msg = 'sp_OAMethod read response failed' goto eh end
exec #hr = sp_OADestroy #obj
select #response
......
eh:
exec #hr = sp_OADestroy #obj
Raiserror(#msg, 16, 1)
Return