Read binary data in TSQL through HTTP GET - sql-server

I need to export some images into my SQL Server through HTTP URL.
I've found article about exporting of XML data:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
Declare #Object as Int;
Declare #ResponseText as Varchar(8000);
Declare #Url as Varchar(MAX);
select #Url = 'http://somexml.com/xmlfile.xml'
Exec sp_OACreate 'MSXML2.XMLHTTP', #Object OUT;
Exec sp_OAMethod #Object, 'open', NULL, 'get', #Url, 'false'
Exec sp_OAMethod #Object, 'send'
Exec sp_OAMethod #Object, 'responseText', #ResponseText OUTPUT
Exec sp_OADestroy #Object
--load into Xml
Declare #XmlResponse as xml;
select #ResponseText
Also during research I've found that I should use ADODB.Stream for binary data. But I can't figure out how to read this object using approach described above.
Is there a way for reading binary data in pure TSQL or I should use CLR for this?
Thanks a lot for helping.

I had the same question as you, and found how to do it!
Here is my sql to do it (it supports retrieval of text and binary data):
EXEC sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
EXEC sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
declare #xmlObject as int
declare #responseText as varchar(max)
declare #responseBody as varbinary(max)
declare #status as int
declare #url as varchar(2048)
select #url = 'http://someurl.com/someimage.jpg'
exec sp_OACreate 'MSXML2.XMLHTTP', #xmlObject OUT;
exec sp_OAMethod #xmlObject, 'open', NULL, 'get', #url, 'false'
exec sp_OAMethod #xmlObject, 'send'
exec sp_OAMethod #xmlObject, 'status', #status OUTPUT
exec sp_OAMethod #xmlObject, 'responsetext', #responseText OUTPUT
declare #responseTable as table ( body varbinary(max) )
INSERT INTO #responseTable exec sp_OAMethod #xmlObject, 'responsebody'
exec sp_OADestroy #xmlObject
select #status
select #responseText
select #responseBody=body from #responseTable
select #responseBody
Hope this helps somone out there :)

Related

SQL Server Woocommerce API connection gives NULL when getting products, works fine with orders

I am trying to set up a connection between a external SQL Server Database and the Woocommerce API.
The goal is to communicate between 2 websites, where they exchange data, the external website will send a POST request to Woocommerce to create a product, then GET the list of products to select the latest added one and then uses that product ID to create a add to cart link which will put the product into the Cart.
Now here is my code :
DECLARE #contentType NVARCHAR(64);
DECLARE #ret INT;
DECLARE #responseText NVARCHAR(4000);
DECLARE #status NVARCHAR(32);
DECLARE #statusText NVARCHAR(32);
DECLARE #token INT;
DECLARE #url NVARCHAR(256);
SET #contentType = 'application/json';
set #url = 'https://mywebsite.com/wp-json/wc/v3/products/?consumer_key=mykey&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1458225139&oauth_nonce=nVq4rX&consumer_secret=mysecret&oauth_signature=kzoVx%20VYSWlLbRpi3f8222222%3D'
EXEC #ret = sp_OACreate 'WinHttp.WinHttpRequest.5.1', #token OUT;
EXEC #ret = sp_OAMethod #token, 'open', NULL, 'GET', #url, 'false';
EXEC #ret = sp_OAMethod #token, 'setRequestHeader', NULL, 'Content-type', #contentType;
EXEC #ret = sp_OAMethod #token, 'send', NULL;
EXEC #ret = sp_OAGetProperty #token, 'status', #status OUT;
EXEC #ret = sp_OAGetProperty #token, 'statusText', #statusText OUT;
EXEC #ret = sp_OAGetProperty #token, 'responseText', #responseText OUT;
EXEC #ret = sp_OADestroy #token;
RETURN #responseText;
When i return the status i get 200, which to my knowledge is the desirable status.
But when i return responseText i get null.
The infuriating part is when i replace products with orders i get a result as expected, but when getting the products it keeps saying NULL.
Please help, because i am losing the last few hairs on my head.
Also my boss insists on doing it by SQL Server..

SQL Server - sp_OAGetProperty returns nothing

I have the below code that calls a link and it return some information in a json structure:
DECLARE
#Object INT,
#vResponseText varchar(8000),
#CountryInfo varchar(8000),
#GetCountryRequest AS varchar(8000)=
'{
"userName":"200900119",
"password":"8481774916"
}'
EXEC sp_OACreate 'MSXML2.ServerXMLHTTP', #Object OUTPUT
EXEC sp_OAMethod #Object, 'Open', NULL, 'POST', 'https://api.dpd.ro/v1/location/country/642', 'false'
EXEC sp_OAMethod #Object, 'SETRequestHeader', null, 'Content-Type', 'application/json'
EXEC sp_OAMethod #Object, 'Send', NULL, #GetCountryRequest
EXEC sp_OAMethod #Object, 'responseText', #vResponseText OUTPUT
EXEC sp_OADestroy #Object
PRINT #vResponseText
So far so good! If I would like to insert the response into a table and then use JSON_QUERY to manipulate the data, I need to insert it into a table (a global temporal table in my case), using GetProperty method, which is not working.
IF OBJECT_ID('tempdb.dbo.##CountryTable', 'U') IS NOT NULL
BEGIN
DROP TABLE ##CountryTable
END
CREATE TABLE ##CountryTable(
CountryInfo varchar(8000)
)
INSERT ##CountryTable (CountryInfo)
EXEC sp_OAGetProperty #Object, 'responseText'
EXEC sp_OADestroy #Object
What am I missing? Thanks
Take a look here: http://www.sqlservercentral.com/articles/JSON/141175/. It might help you getting to the result you are looking for.

Consuming webservice by SQL Server procedure

I am using sql server 2016 to consume webservice through store procedure. I have a webservice in JSON returning the following:
["Name":"Rebecca","email":"rebecca#hotmail.com","ra":"12345"},
{"name":"Caroline","email":"caroline#hotmail.com","ra":"23456"},
{"name":"Vanessa","email":"vanessa#yahoo.com.br","ra":"99999"}]
I can consume it by passing a variable. If I leave my webservice to receive a parameter and pass it I can return the name and email of the student. But if I leave my webservice without the need to receive parameter and remove the procedure parameter pass and execute, my procedure returns null. What do I need to change in my code to be able to return the complete list of students my webservice exposes?
Here's my code:
create PROCEDURE webservice_parametros (#RA as varchar (5))
AS
BEGIN
DECLARE #OBJ INT;
DECLARE #URL VARCHAR(200);
DECLARE #RESPONSE VARCHAR(8000);
SET #URL = 'http://dominio:8080/v1/alunos/' + #RA
EXEC SP_OACREATE 'MSXML2.ServerXMLHttp', #OBJ out
EXEC SP_OAMETHOD #OBJ, 'OPEN', NULL, 'GET', #URL, FALSE
EXEC SP_OAMETHOD #OBJ, 'SEND'
exec SP_OAGETPROPERTY #OBJ, 'responseText', #RESPONSE out
EXEC SP_OADESTROY #OBJ
SELECT JSON_VALUE(#RESPONSE, '$.nome') as nome,
JSON_VALUE(#RESPONSE, '$.email') as email
END
execute webservice_parametros '12345'
My code that returns NULL
create PROCEDURE webservice
AS
BEGIN
DECLARE #OBJ INT;
DECLARE #URL VARCHAR(200);
DECLARE #RESPONSE VARCHAR(8000);
SET #URL = 'http://dominio:8080/v1/alunos/'
EXEC SP_OACREATE 'MSXML2.ServerXMLHttp', #OBJ out
EXEC SP_OAMETHOD #OBJ, 'OPEN', NULL, 'GET', #URL, FALSE
EXEC SP_OAMETHOD #OBJ, 'SEND'
exec SP_OAGETPROPERTY #OBJ, 'responseText', #RESPONSE out
EXEC SP_OADESTROY #OBJ
SELECT JSON_VALUE(#RESPONSE, '$.nome') as nome,
JSON_VALUE(#RESPONSE, '$.email') as email
END
execute webservice

How to avoid sp_OACreate limits?

Declare #Object as Int;
Declare #ResponseText as Varchar(8000);
Declare #Url as Varchar(MAX);
set #Url = 'http://mysite.ru/cgi-bin/my_xml.cgi'
Exec sp_OACreate 'MSXML2.XMLHTTP', #Object OUT;
Exec sp_OAMethod #Object, 'open', NULL, 'get', #Url, 'false'
Exec sp_OAMethod #Object, 'send'
Exec sp_OAMethod #Object, 'responseText', #ResponseText OUTPUT
Exec sp_OADestroy #Object
SELECT #ResponseText
XML length in url is 4210 and #ResponseText return NULL , when I change length to 3970 #ResponseText return me data. Does sp_OACreate have limit 400 ? If yes if it possible to avoid ?
despite the subject of your post i think that the issue is likely with sp_OAMethod and not sp_OACreate itself.
also IMHO accessing the web from sql code should be avoided at all costs but this is just my opinion because i don't like the idea having a RDBMS 'surfing the web'. ^^
to circumvent the limitation of sp_OAMethod you can try to elaborate an answer present on msdn.
your code should become something like this:
Declare #Object as Int;
Declare #ResponseText as Varchar(8000);
Declare #Url as Varchar(MAX);
set #Url = 'http://mysite.ru/cgi-bin/my_xml.cgi'
Exec sp_OACreate 'MSXML2.XMLHTTP', #Object OUT;
Exec sp_OAMethod #Object, 'open', NULL, 'get', #Url, 'false'
Exec sp_OAMethod #Object, 'send'
--Exec sp_OAMethod #Object, 'responseText', #ResponseText OUTPUT
INSERT #temptable ( appropriatefield )
EXEC #Result = sp_OAGetProperty #Obj, 'YourPropertyName'
Exec sp_OADestroy #Object
the solution requires a temp table with appropriate structure and datatype to store the value produced by the remote page and this should allow you to get more than 4k of data.
According to this thread on sqlservercentral.com, sp_OACreate is limited to 4000 characters.
A workaround is to split up the read into smaller "chunks" that are then concated together in SQL. Here is a code snippet from the above link, that might help you although it reads XML from file instead of through HTTP:
EXECUTE #hResult = sp_OACreate ''Scripting.FileSystemObject'' , #objFileSystem OUT
IF #hResult <> 0
BEGIN
EXEC sp_OAGetErrorInfo #objFileSystem, #ErrorSource OUT, #ErrorDesc OUT
SET #ErrorFailPoint = ''Creating FSO''
GOTO DestroyFSO
RETURN
END
SET #FileNameAndPath = #Path + ''\'' + #FileName
-- Read file
EXECUTE #hResult = sp_OAMethod #objFileSystem, ''OpenTextFile'', #objTextStream OUT, #FileNameAndPath, 1, false, 0--for reading, FormatASCII
IF #hResult <> 0
BEGIN
EXEC sp_OAGetErrorInfo #objFileSystem, #ErrorSource OUT, #ErrorDesc OUT
SET #ErrorFailPoint = ''Opening Reponse File''
GOTO Destroy
RETURN
END
SET #ResponseText = ''''
WHILE #hResult = 0
BEGIN
EXECUTE #hResult = sp_OAGetProperty #objTextStream, ''AtEndOfStream'', #YesOrNo OUTPUT
IF #hResult <> 0
BEGIN
EXEC sp_OAGetErrorInfo #objTextStream, #ErrorSource OUT, #ErrorDesc OUT
SET #ErrorFailPoint = ''Checking AtEndOfStream''
GOTO Destroy
RETURN
END
IF #YesOrNo <> 0
BREAK
EXECUTE #hResult = sp_OAMethod #objTextStream, ''Read'', #Chunk OUTPUT, 4000
IF #hResult <> 0
BEGIN
EXEC sp_OAGetErrorInfo #objTextStream, #ErrorSource OUT, #ErrorDesc OUT
SET #ErrorFailPoint = ''Reading Chunk''
GOTO Destroy
RETURN
END
SET #ResponseText = #ResponseText + ISNULL(#Chunk, '''')
END
EXECUTE #hResult = sp_OAMethod #objTextStream, ''Close''
IF #hResult <> 0
BEGIN
EXEC sp_OAGetErrorInfo #objTextStream, #ErrorSource OUT, #ErrorDesc OUT
SET #ErrorFailPoint = ''Closing Response File''
GOTO Destroy
RETURN
END
-- Record response info
SET #ResponseXml = CAST(#ResponseText AS XML)
Destroy:
EXEC sp_OADestroy #objTextStream
DestroyFSO:
EXEC sp_OADestroy #objFileSystem
This is what I use to overcome the limitation. I use it for a RESTful api communication. I can receive varchar(max) but am still limited on the amount of data I can send. This might get you where you need to be. The top 5 variables are the arguments I use for the sproc.
Declare #url as varchar(1024)
Declare #connection_type as varchar(6)='GET' --POST, PUT, GET DELETE
Declare #post_string as varchar(max)=null
Declare #response_text as Varchar(max)
Declare #content_type varchar(254)='application/json'
Declare #oa_object as Int;
Declare #err_code as Int
Declare #result_table Table (xml_result varchar(max))
Select #post_string=dbo.fn_regex_replace('([ ]{2,10})|\r|\n', #post_string,'') --remove carriage returns and multiple spaces
Exec #err_code=sp_OACreate 'MSXML2.ServerXMLHTTP.3.0', #oa_object OUT;
If #err_code<>0
Set #response_text=dbo.fn_oa_error_message(#oa_object)
Else
Begin
Exec #err_code=sp_OAMethod #oa_object, 'open', NULL, #connection_type, #url,'false','d0b1a0aaed2a529356471de4fe99cae2','8e7aa1a91fa68d06cd027914d3aa1140'
If #err_code<>0
Set #response_text='Open '+dbo.fn_oa_error_message(#oa_object)
Else
Begin
Exec #err_code=sp_OAMethod #oa_object, 'setRequestHeader', NULL, 'User-Agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)'
If #err_code<>0
Set #response_text='setRequestHeader:User-Agent '+dbo.fn_oa_error_message(#oa_object)
Else
Begin
Exec #err_code=sp_OAMethod #oa_object, 'setRequestHeader', NULL, 'Content-Type', #content_type
If #err_code<>0
Set #response_text='setRequestHeader:Content-Type '+dbo.fn_oa_error_message(#oa_object)
Else
Begin
Exec #err_code=sp_OAMethod #oa_object, 'send', Null, #post_string
If #err_code<>0
Set #response_text='Send '+dbo.fn_oa_error_message(#oa_object)
Else
Begin
Set #response_text=null--make sure we don't return garbage
INSERT #result_table (xml_result)
Exec #err_code = sp_OAGetProperty #oa_object, 'responseText'
If #err_code<>0
Set #response_text='responseText '+dbo.fn_oa_error_message(#oa_object)
Else
SELECT #response_text=xml_result FROM #result_table
End
End
End
End
End
Exec sp_OADestroy #oa_object
Although you don't need it, the error handler is below. It helps with troubleshooting.
CREATE FUNCTION
dbo.n_oa_error_message(#oa_object int)
RETURNS varchar(max)
AS
BEGIN
Declare #source varchar(255)
Declare #description varchar(255)
exec sp_OAGetErrorInfo #oa_object, #source OUT, #description OUT
return 'Error: '+IsNull(#description,'no description')
END
I used the following query to solve this issue. The problem is probably not sp_OACreate or sp_OAMethod, but the way to return the #ResponseText. Inserting the data into a table variable instead of using "#ResponseText OUTPUT" is the key. Note that I changed the #Response to VARCHAR(MAX).
DECLARE #TABLEVAR TABLE (responseXml VARCHAR(MAX))
DECLARE #URL VARCHAR(200)
SELECT #URL = 'http://mysite/php-start/callxml.php'
DECLARE #Response NVARCHAR(MAX)
DECLARE #Xml XML
DECLARE #Obj INT
DECLARE #Result INT
EXEC #Result = sp_OACreate 'MSXML2.XMLHttp', #Obj OUT
EXEC #Result = sp_OAMethod #Obj, 'open', NULL, 'GET', #URL, false
EXEC #Result = sp_OAMethod #Obj, 'setRequestHeader', NULL, 'Content-Type', 'application/x-www-form-urlencoded'
EXEC #Result = sp_OAMethod #Obj, SEND, NULL, ''
INSERT INTO #TABLEVAR
EXEC #Result = sp_OAGetProperty #Obj, 'responseXML.xml'--, #Response OUT
EXEC sp_OADestroy #Obj
SELECT #Response = responseXml FROM #TABLEVAR
SELECT #Xml = CONVERT(XML, #Response, 2)
DECLARE #handle INT
EXEC sp_xml_preparedocument #handle OUTPUT, #Xml
SELECT *
FROM OPENXML(#handle, '/data/record', 2)
WITH [dbo].[tblDialogTechTemp]
EXEC sp_xml_removedocument #handle
My query suddenly returned null without changing anything. After changing 'MSXML2.XMLHttp' to 'MSXML2.ServerXMLHTTP', it started to work again. To know more about the difference between these two, see this article and Microsoft documentation.

Can't use sp_configure in remote Sql server

I used sq_configure to use OLE automation process to send http request from SQL server like
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO
and then I built one stored procedure called HTTP_Request as shown below
CREATE procedure HTTP_Request( #sUrl varchar(200))
As
Declare
#obj int
,#hr int
,#msg varchar(255)
exec #hr = sp_OACreate 'MSXML2.ServerXMLHttp', #obj OUT
if #hr <> 0 begin Raiserror('sp_OACreate MSXML2.ServerXMLHttp.3.0
failed', 16,1) return end
exec #hr = sp_OAMethod #obj, 'open', NULL, 'POST', #sUrl, false
if #hr <>0 begin set #msg = 'sp_OAMethod Open failed' goto eh end
exec #hr = sp_OAMethod #obj, 'setRequestHeader', NULL, 'Content-Type',
'application/x-www-form-urlencoded'
if #hr <>0 begin set #msg = 'sp_OAMethod setRequestHeader failed' goto
eh end
exec #hr = sp_OAMethod #obj, send, NULL, ''
if #hr <>0 begin set #msg = 'sp_OAMethod Send failed' goto eh end
exec #hr = sp_OADestroy #obj
return
eh:
exec #hr = sp_OADestroy #obj
Raiserror(#msg, 16, 1)
return
GO
and I called the stored procedure as
USE [master]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[HTTP_Request]
#sUrl = N'url'
SELECT 'Return Value' = #return_value
GO
It was working fine in my local sql server, I can able to send the http request from database.
Now My problem is I got access to remote sql server where I suppose to use the same thing as I did in my local system, but when I try to execute sp_configure I can't. I got error as
could not find stored procedure 'sp_configure'
any idea?
Is this problem with access restriction?
You can't run sp_configure on WASD, sorry. And even if you could, you would not be able to invoke OA methods. You will need to find another way to hit your web page (e.g. hit it from your application instead of from a stored procedure - arguably where it should happen anyway).

Resources