How to get JSON response from a teiid REST service - teiid

I am issuing a SQL SELECT query against a MySQL data source from teiid and trying to get the SQL response in the JSON format. I was able to get the response in the XML format but having trouble when I'am trying to get the response in JSON format. it seems that there are not equivalent JSON functions to XMLELEMENT, XMLAGG, XMLFOREST XML functions. I have posted the XML version of my query bellow. What are the equivalent JSON version of this query.
CREATE VIRTUAL PROCEDURE GetFlightRecordsByAirDelay1(IN p1 integer, IN
p2 integer) RETURNS (xml_out xml) OPTIONS (UPDATECOUNT 0,
"REST:METHOD" 'GET', "REST:URI" 'GetFlightRecordsByAirDelay1')
AS
/*+ cache(pref_mem ttl:14400000) */
BEGIN
SELECT XMLELEMENT("FlightDelayRecords",
XMLAGG(XMLELEMENT("FlightDelayRecord",
XMLFOREST(UniqueCarrier,FlightNum, CRSDepTime, DepTime,
CRSArrTime, ArrDelay) )) ) as xml_out FROM (SELECT UniqueCarrier,FlightNum, CRSDepTime, DepTime, CRSArrTime,
ArrDelay FROM flight_records_mod1 WHERE flight_records_mod1.ArrDelay <
p1 AND flight_records_mod1.YEAR = p2 LIMIT 10) A;
END

It can be simpler to return json. To produce a result like:
{"FlightDelayRecords":[{"UniqueCarrier":...},...]}
Use
CREATE VIRTUAL PROCEDURE GetFlightRecordsByAirDelay1(IN p1 integer, IN p2 integer)
RETURNS (clob json) OPTIONS (UPDATECOUNT 0, "REST:METHOD" 'GET', "REST:URI" 'GetFlightRecordsByAirDelay1') AS /*+ cache(pref_mem ttl:14400000) */
BEGIN
SELECT JSONOBJECT(JSONARRAY_AGG(JSONOBJECT(UniqueCarrier,FlightNum, CRSDepTime, DepTime, CRSArrTime, ArrDelay)) as "FlightDelayRecords") as json FROM (SELECT UniqueCarrier,FlightNum, CRSDepTime, DepTime, CRSArrTime,
ArrDelay FROM flight_records_mod1 WHERE flight_records_mod1.ArrDelay < p1 AND flight_records_mod1.YEAR = p2 LIMIT 10) A;
END

Related

How to convert string format of time type field in DolphinDB c ++ API

Suppose I have the following table,
t=table(1..3 as id,(now() - 2)..now() as ts)
share(t, `sharedT);
I query the value of the ts column in the API, the code is as follows,
DBConnection conn;
TableSP table = conn.run("select * from sharedT");
ConstantSP col1=table->getcolumn(1);
cout<<col1->getString(0)<<endl;
The displayed result is like 2020.02.20T01:44:58, but the format I want to get is 02/20/2020T01:44:58.
How to convert this is more convenient?
It is better off to format the datetime column on the server end.
DBConnection conn;
TableSP table = conn.run("select id,format(ts,'MM/dd/yyyyTHH:mm:ss') as ts from sharedT");
ConstantSP col1=table->getcolumn(1);
cout<<col1->getString(0)<<endl;

getting result metadata from coldfusion newQuery() in cfscript

Documentation on CFscript is a bit sparse in the docs, and searching for a cfscript specific answer gets lost in CF tag answers. So here's my question:
How do I get the result metadata from a query that was performed using script? Using tags I can add result="myNamedResultVar" to my cfquery. I can then refer to the query name for data, or myNamedResultVar for some metadata. However, now I'm trying to write everything in script, so my component is script based, top-to-bottom. What I'm ultimately after is the last inserted Id from a MySQL insert. That ID exists in the result metadata.
myNamedResultVar.getPrefix().generatedkey
Here's my query code:
public any function insertUser( required string name, required string email, required string pass ) {
// insert user
var sql = '';
var tmp = '';
var q = new query();
q.setDatasource( application.dsn );
q.addParam(
name='name'
,value='#trim( arguments.name )#'
,cfsqltype='CF_SQL_VARCHAR'
);
q.addParam(
name='email'
,value='#trim( arguments.email )#'
,cfsqltype='CF_SQL_VARCHAR'
);
q.addParam(
name='pass'
,value='#hashMyString( arguments.pass )#'
,cfsqltype='CF_SQL_VARCHAR'
);
sql = 'INSERT INTO
users
(
name
,email
,pass
,joined
,lastaccess
)
VALUES
(
:name
,:email
,:pass
,CURRENT_TIMESTAMP
,CURRENT_TIMESTAMP
);
';
tmp = q.execute( sql=sql );
q.clearParams();
}
How do I specify the result data? I've tried something like this:
...
tmp = q.execute( sql=sql );
var r = tmp.getResult();
r = r.getPrefix().generatedkey;
q.clearParams();
return r;
However, on an insert the getResult() returns a NULL as best I can tell. So the r.getPrefix().generatedkey does NOT work after an insert. I get r is undefined
You are getting the result property of the query first and then from that you are trying to get the prefix property in result. But this is not the case. You can directly get the prefix property and then the generated key like this:
tmp.getPrefix().generatedkey;
For reference you can check this blog entry: Getting the Generated Key From A Query in ColdFusion (Including Script Based Queries)
after some futzing... THIS seems to work
... tmp = q.execute( sql=sql );
var r = tmp.getPrefix( q ).generatedkey;
q.clearParams();
return r;

inserting to database using ado command

I am trying to insert records into a table using adodb using c++.
Stored Proc:
CREATE PROCEDURE [dbo].[dbo.insert_command]
#Id INT OUTPUT,
#Name varchar(25),
#Age int = NULL
-- WITH ENCRYPTION
AS
...
Declaring the commands:
TESTHR(m_pInsertCommand.CreateInstance(__uuidof(Command)));
m_pInsertCommand>ActiveConnection = m_pConnection;
m_pInsertCommand>CommandText = L"dbo.insert_command";
m_pInsertCommand>Parameters->Append(m_pInsertCommand->CreateParameter(L"Id", adInteger, adParamOutput, 4, vtNull));
m_pInsertCommand>Parameters->Append(m_pInsertCommand->CreateParameter(L"Name", adVarChar, adParamInput, m_lLabelLength));
m_pInsertCommand>Parameters->Append(m_pInsertCommand->CreateParameter(L"Age", adInteger, adParamInput, sizeof(long), vtNull));
Setting the parameters:
dbConnection.m_pInsertCommand->Parameters->Item[L"Id"]->Value = vtNull;
dbConnection.m_pInsertCommand->Parameters->Item[L"Name"]->Value = (BSTR) m_Name;
dbConnection.ExecuteCommand(dbConnection.m_pInsertCommand, adCmdStoredProc | adExecuteNoRecords);
Id = (long) dbConnection.m_pInsertDefectCommand->Parameters->Item[L"Id"]->Value;
Trace through SQL Profiler:
declare #p1 int
set #p1=16
exec dbo.insert_Command #p1 output,'Name',NULL
select #p1
My question is why is the command generating the parameter #p1 in the sql statement. this is causing the logic to change as I am trying to insert a record if the parameter id is null.
Any suggestions for why this is happening?
Thanks in advance

T4 Templates : Reading resulting columns of a stored procedure table

I am learning T4 templates right now, and all examples I got on internet is about using the tables for code generation. I want to use stored procedure result columns to generate automated UI, is it possible? OR I have to create view for same query? in that case, how to read from view?
Thanks in advance.
I got the solution and here is how you can generate a rad grid directly from the sp name
<#
'requires: <## assembly name="System.Data" #>
dim Server as new Server(".\sqlexpress")
dim database as new Database(server, "xxxx")
dim strSpName as String= "sp_xxxx"
Dim dt as System.Data.DataTable= database.ExecuteWithResults("exec sp_GetEquipment").Tables(0)
dim ctlName as String = "grdEqp"
#>
<telerik:RadGrid ID="grd" runat="server" Skin="Web20" AutoGenerateColumns="false">
<MasterTableView>
<Columns>
<#
For Each column As System.Data.DataColumn In dt.Columns
#><telerik:GridBoundColumn DataField="<#=column.ColumnName #>" HeaderText="<#=column.ColumnName #>"/>
<#Next#>
</Columns>
</MasterTableView>
</telerik:RadGrid>
If you don't actually want to execute the stored procedure as various stored procedures have a number of different parameters passed then you could use the sp_describe_first_result_set system stored procedure to return the columns of the result set assuming there is just one.
/// <summary>
/// Returns table for which stored procedures need to be generated.
/// </summary>
string TableName = "usp_getNominalCode";
string SchemaName = "Financial";
DataTable DataTable
{
get
{
if (_table == null)
{
Server server = new Server(new ServerConnection(new SqlConnection(this.ConnectionString)));
SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder(this.ConnectionString);
Database database = new Database(server, connectionStringBuilder.InitialCatalog);
DataSet storedProcedureColumns = database.ExecuteWithResults("sp_describe_first_result_set #tsql= " + "'[" + SchemaName + "]" + ".[" + TableName + "]'");
_table = storedProcedureColumns.Tables[0];
}
return _table;
}
}
DataTable _table;
You can then query this table for it's structure like the other answer but it'll be a little more generic

Changing SQL Provider from SQLOLEDB.1 to SQLNCLI.1 causes app to fail when accessing data via stored procedure

I'm supporting a legacy app written in MFC/C++. The database for the app is in SQL Server 2000. We bolted on some new functionality recently and found that when we change the SQL Provider from SQLOLEDB.1 to SQLNCLI.1 some code that is trying to retrieve data from a table via a stored procedure fails.
The table in question is pretty straightforward and was created via the following script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UAllergenText](
[TableKey] [int] IDENTITY(1,1) NOT NULL,
[GroupKey] [int] NOT NULL,
[Description] [nvarchar](150) NOT NULL,
[LanguageEnum] [int] NOT NULL,
CONSTRAINT [PK_UAllergenText] PRIMARY KEY CLUSTERED
(
[TableKey] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[UAllergenText] WITH CHECK ADD CONSTRAINT
FK_UAllergenText_UBaseFoodGroupInfo] FOREIGN KEY([GroupKey])
REFERENCES [dbo].[UBaseFoodGroupInfo] ([GroupKey])
GO
ALTER TABLE [dbo].[UAllergenText] CHECK CONSTRAINT
FK_UAllergenText_UBaseFoodGroupInfo]
Bascially four columns, with TableKey being an identity column and everything else is populated via the following script:
INSERT INTO UAllergenText (GroupKey, Description, LanguageEnum)
VALUES (401, 'Egg', 1)
with a long list of other INSERT INTO's that follow the one above. Some of the rows inserted have special characters (like accent marks above letters) in their descriptions. I had originally thought that the inclusion of the special characters was part of the problem but if I completely clear out the table and then repopulate it with just the single INSERT INTO from above that has no special characters, it still fails.
So I moved on...
The data in this table is then accessed via the following code:
std::wstring wSPName = SP_GET_ALLERGEN_DESC;
_variant_t vtEmpty1 (DISP_E_PARAMNOTFOUND, VT_ERROR);
_variant_t vtEmpty2(DISP_E_PARAMNOTFOUND, VT_ERROR);
_CommandPtr pCmd = daxLayer::CDataAccess::GetSPCommand(pConn, wSPName);
pCmd->Parameters->Append(pCmd->CreateParameter("#intGroupKey", adInteger, adParamInput, 0, _variant_t((long)nGroupKey)));
pCmd->Parameters->Append(pCmd->CreateParameter("#intLangaugeEnum", adInteger, adParamInput, 0, _variant_t((int)language)));
_RecordsetPtr pRS = pCmd->Execute(&vtEmpty1, &vtEmpty2, adCmdStoredProc);
//std::wstring wSQL = L"select Description from UAllergenText WHERE GroupKey = 401 AND LanguageEnum = 1";
//_RecordsetPtr pRS = daxLayer::CRecordsetAccess::GetRecordsetPtr(pConn,wSQL);
if (pRS->GetRecordCount() > 0)
{
std::wstring wDescField = L"Description";
daxLayer::CRecordsetAccess::GetField(pRS, wDescField, nameString);
}
else
{
nameString = "";
}
The daxLayer is a third party data access library the application is using, though we have the source to it (some of which will be seen below.) SP__GET_ALLERGEN_DESC is the stored proc used to get the data out of the table and it was created via this script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spRET_AllergenDescription]
-- Add the parameters for the stored procedure here
#intGroupKey int,
#intLanguageEnum int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT Description FROM UAllergenText WHERE GroupKey = #intGroupKey AND LanguageEnum = #intLanguageEnum
END
When the SQL Provider is set to SQLNCLI.1, the app blows up at:
daxLayer::CRecordsetAccess::GetField(pRS, wDescField, nameString);
from the above code snippet. So I stepped into GetField, which looks like the following:
void daxLayer::CRecordsetAccess::GetField(_RecordsetPtr pRS,
const std::wstring wstrFieldName, std::string& sValue, std::string sNullValue)
{
if (pRS == NULL)
{
assert(false);
THROW_API_EXCEPTION(GetExceptionMessageFieldAccess(L"GetField",
wstrFieldName, L"std::string", L"Missing recordset pointer."))
}
else
{
try
{
tagVARIANT tv = pRS->Fields->GetItem(_variant_t(wstrFieldName.c_str()))->Value;
if ((tv.vt == VT_EMPTY) || (tv.vt == VT_NULL))
{
sValue = sNullValue;
}
else if (tv.vt != VT_BSTR)
{
// The type in the database is wrong.
assert(false);
THROW_API_EXCEPTION(GetExceptionMessageFieldAccess(L"GetField",
wstrFieldName, L"std::string", L"Field type is not string"))
}
else
{
_bstr_t bStr = tv ;//static_cast<_bstr_t>(pRS->Fields->GetItem(_variant_t(wstrFieldName.c_str()))->Value);
sValue = bStr;
}
}
catch( _com_error &e )
{
RETHROW_API_EXCEPTION(GetExceptionMessageFieldAccess(L"GetField",
wstrFieldName, L"std::string"), e.Description())
}
catch(...)
{
THROW_API_EXCEPTION(GetExceptionMessageFieldAccess(L"GetField",
wstrFieldName, L"std::string", L"Unknown error"))
}
}
}
The culprit here is:
tagVARIANT tv = pRS->Fields->GetItem(_variant_t(wstrFieldName.c_str()))->Value;
Stepping into Fields->GetItem brings us to:
GetItem
inline FieldPtr Fields15::GetItem ( const _variant_t & Index ) {
struct Field * _result = 0;
HRESULT _hr = get_Item(Index, &_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return FieldPtr(_result, false);
}
Which then takes us to:
GetValue
inline _variant_t Field20::GetValue ( ) {
VARIANT _result;
VariantInit(&_result);
HRESULT _hr = get_Value(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _variant_t(_result, false);
}
If you look at _result while stepping through this at runtime, _result's BSTR value is correct, its value is "Egg" from the "Description" field of the table. Continuing to step through traces back through all the COM release calls, etc. When I finally get back to:
tagVARIANT tv = pRS->Fields->GetItem(_variant_t(wstrFieldName.c_str()))->Value;
And step past it to the next line, the contents of tv, which should be BSTR="Egg" are now:
tv BSTR = 0x077b0e1c "ᎀݸﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮ㨼㺛帛᠄"
When the GetField function tries to set its return value to the value in tv.BSTR
_bstr_t bStr = tv;
sValue = bStr;
it unsurprisingly chokes and dies.
So what happened to the value of BSTR and why does it only happen when the provider is set to SQLNCLI.1?
For the heck of it, I commented out using the stored procedure in the topmost code and just hard coded the same SQL SELECT statement that the stored procedure uses and found that it works just fine and the value returned is correct.
Also, it's possible for users to add rows to the table through the application. If the application creates a new row in that table and retrieves that row via stored procedure, it also works correctly unless you include a special character in the description in which case it correctly saves the row but blows up again in the exact same way as above upon retrieval of that row.
So to summarize, if I can, rows put into the table via the INSERT script ALWAYS blow up the app when they are accessed by stored procedure (regardless of whether they contain any special characters). Rows put into the table from within the application by the user at runtime are retrieved correctly via stored procedure UNLESS they contain a special character in the Description, at which point they blow up the app. If you access any of the rows in the table by using SQL from the code at runtime instead of the stored procedure it works whether there is a special character in the Description or not.
Any light that can be shed on this will be greatly appreciated, and I thank you in advance.
This line might be problematic:
tagVARIANT tv = pRS->Fields->GetItem(_variant_t(wstrFieldName.c_str()))->Value;
If I read it right, ->Value returns a _variant_t, which is a smart pointer. The smart pointer will release its variant when it goes out of scope, right after this line. However, tagVARIANT is not a smart pointer, so it won't increase the reference count when it is assigned to. So after this line, tv might point to a variant which has effectively been released.
What happens if you write the code like this?
_variant_t tv = pRS->Fields->GetItem(_variant_t(wstrFieldName.c_str()))->Value;
Or alternatively, tell the smart pointer not to release its payload:
_tagVARIANT tv = pRS->Fields->GetItem(
_variant_t(wstrFieldName.c_str()))->Value.Detach();
It's been a long time since I coded in C++, and reading this post, I don't regret moving away!