Output Parameter of Stored Procedure is not getting set - sql-server

So I have the following stored procedure:
CREATE PROCEDURE dbo.uspUpdateOrInsertDataObjectValue
#ParentDataObjectId INT,
#DataObjectName NVARCHAR(256),
#DataObjectValue NVARCHAR(256),
#ForceInsert BIT,
#ReturnDataObjectId INT OUT
WITH RECOMPILE
AS
BEGIN
if #ForceInsert = 0
BEGIN
UPDATE DataObjects SET Value=#DataObjectValue WHERE Name=#DataObjectName AND ParentDataObjectId=#ParentDataObjectId
END
if ( #ForceInsert = 1 ) OR ( ##ROWCOUNT = 0 )
BEGIN
--Spend time on the hierarchy id stuff only if we have to insert
DECLARE #ParentTreeId HierarchyId
DECLARE #LastChildTreeId HierarchyId
SELECT #ParentTreeId = TreeId FROM DataObjects WHERE DataObjectId=#ParentDataObjectId
SELECT #LastChildTreeId = MAX(TreeId) FROM DataObjects WHERE TreeId.GetAncestor(1)=#ParentTreeId
INSERT INTO DataObjects ( Name, Value, ParentDataObjectId, TreeId ) VALUES ( #DataObjectName, #DataObjectValue, #ParentDataObjectId, #ParentTreeId.GetDescendant( #LastChildTreeId, NULL ) )
END
SELECT #ReturnDataObjectId = (SELECT TOP 1 DataObjectId FROM DataObjects WHERE Name=#DataObjectName AND ParentDataObjectId=#ParentDataObjectId ORDER BY DataObjectId DESC)
RETURN 0
END
GO
`
And I'm executing it like this:
int iParentDataObjectId = 1;
int iDataObjectId = 0;
SQLWCHAR name[256];
SQLWCHAR value[256];
_sntprintf_s( (wchar_t*)name, 256, _TRUNCATE, _T("%s"), pCDBDataObject->GetName() );
_sntprintf_s( (wchar_t*)value, 256, _TRUNCATE, _T("%s"), pCDBDataObject->GetString() );
result = SQLBindParameter( sqlStatementHandle, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &iParentDataObjectId, 0, NULL );
result = SQLBindParameter( sqlStatementHandle, 2, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WVARCHAR, 256, 0, name, 256, NULL );
result = SQLBindParameter( sqlStatementHandle, 3, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WVARCHAR, 256, 0, value, 256, NULL );
result = SQLBindParameter( sqlStatementHandle, 4, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, 1, 0, &forceInsert, 0, NULL );
result = SQLBindParameter( sqlStatementHandle, 5, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &iDataObjectId, 0, NULL );
result = SQLExecDirect( sqlStatementHandle, (SQLWCHAR*)_T("{CALL uspUpdateOrInsertDataObjectValue (?,?,?,?,?)}"), SQL_NTS );
'
The stored procedure executes properly and inserts or updates the database but iDataObjectId never changes.
However when I execute it like this in a script in Sql Server Management Studio:
DECLARE #testval int
EXECUTE uspUpdateOrInsertDataObjectValue 1, 'Config', 'testasdfasdfasdfas', 1, #testval OUT
SELECT * from DataObjects where DataObjectId=#testval
the output value is assigned to #testval and the subsequent select statement works just fine.
What am I missing?

I found the answer after a more careful examination of this example: http://technet.microsoft.com/en-us/library/ms403283.aspx
You need to clean out the result sets of the query(call) with SqlMoreResults before the output variables get set. Not the behavior I would have expected but it was right there in the documentation.

Related

Always Encrypted - Parameters

Have set up Always Encrypted for my table columns at server side.
From a C++ client, I use the below connection string to connect to the database:
CString connString = L"Driver={ODBC Driver 17 for SQL Server};Server=192.122.200.200,1433;Encrypt=no;Trusted_Connection=no;ColumnEncryption=Enabled;DATABASE=AlwaysEncrypted;UID=sa;PWD=;";
From the same client I invoke below command to insert data:
CString csQStrInsert = L"declare #val1 int = 3; declare #val2 int = 3; insert into [dbo].[Table_AlwaysEncrypted] ([col1], [col2]) values (#val1, #val2);";
pDatabase->ExecuteSQL(csQStrInsert);
Unfortunately the query fails with below error:
pEX->m_strError = L"Encryption scheme mismatch for columns/variables '#val1'. The encryption scheme for the columns/variables is (encryption_type = 'PLAINTEXT') and the expression near line '1' expects it to be DETERMINISTIC, or PLAIN TEXT.
What am I doing wrong?
You cannot use local variables for Always Encrypted columns, they must come from client-side parameters. In SSMS it works because SSMS parses your script and pulls out the variables into parameters, but in C++ or other clients you must parameterize it yourself.
For example, the below code is used as an example on Microsoft's website, see there for more info on how to use Always Encrypted:
SQL_DATE_STRUCT date;
SQLLEN cbdate; // size of date structure
SQLCHAR SSN[12];
strcpy_s((char*)SSN, _countof(SSN), "795-73-9838");
SQLWCHAR* firstName = L"Catherine";
SQLWCHAR* lastName = L"Abel";
SQLINTEGER cbSSN = SQL_NTS, cbFirstName = SQL_NTS, cbLastName = SQL_NTS;
// Initialize the date structure
date.day = 10;
date.month = 9;
date.year = 1996;
// Size of structures
cbdate = sizeof(SQL_DATE_STRUCT);
SQLRETURN rc = 0;
string queryText = "INSERT INTO [dbo].[Patients] ([SSN], [FirstName], [LastName], [BirthDate]) VALUES (?, ?, ?, ?) ";
rc = SQLPrepare(hstmt, (SQLCHAR *)queryText.c_str(), SQL_NTS);
//SSN
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 11, 0, (SQLPOINTER)SSN, 0, &cbSSN);
//FirstName
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)firstName, 0, &cbFirstName);
//LastName
rc = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WCHAR, 50, 0, (SQLPOINTER)lastName, 0, &cbLastName);
//BirthDate
rc = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 10, 0, (SQLPOINTER)&date, 0, &cbdate);
rc = SQLExecute(hstmt);
As you can see, SQLBindParameter is used to add parameters to the query. You cannot use either literals or SQL local variables to insert or compare with encrypted columns, as the server has no access to the decrypted data.
The client driver needs to have access to the relevant certificate.

Invalid length parameter passed to the LEFT or SUBSTING function

Declare #FileNumber int
Set #FileNumber = cast (SubString(#fileName, CharIndex('Stats', #fileName) + 6, charindex('.',#fileName) - (CharIndex('Stats', #fileName) + 6)) as int)
I'm passing in '' for the #fileName and getting this error. This is in SQL Server 2016
Because ...
select SubString('', 6 , - 6)
Returnes ...
Msg 536, Level 16, State 1, Line 7
Invalid length parameter passed to the substring function.
https://learn.microsoft.com/en-us/sql/t-sql/functions/substring-transact-sql

how to handle Zero divided by zero in sqlserver

how we can handle 0/0 in SQL Server? I used select nullif(0)/nullif(0) but ..
Msg 8134, Level 16, State 1, Line 1 Divide by zero error encountered.
Use NULLIF like this something like this
SELECT 0/NULLIF(0,0)
If you want the result as 0 when you encounter NULL, then use ISNULL/COALESCE
SELECT COALESCE(0/NULLIF(0,0),0)
In your query, you only need to move the ISNULL to check like this isnull(([Total Collection]) / nullif([Billed Amount], 0), 0)
update generalRegionWise set [Collection %] =
convert(VARCHAR,convert(MONEY,100.0 * isnull(([Total Collection]) / nullif([Billed Amount], 0), 0)),1) + '%'
It is recommended to specify the length when converting to VARCHAR like this convert(VARCHAR(50),... In your case it will take the default length of 30.
here are a few more examples.
DECLARE #numerator Int = 0
DECLARE #denominator Int = 0
SELECT ISNULL(NULLIF(#numerator, #denominator),0) AS Result;
SELECT CASE WHEN #denominator = 0
THEN 0
ELSE #numerator / #denominator
END AS Results
Hope this helps.

EXEC %%System().FireTrigger

I was just wondering what is this?
EXEC %%System().FireTrigger(ID = 225, ID = 102, ID = 0, ID = 0, Value = #server,
ID = -1, ID = 0, ID = 0, Value = NULL,
ID = 7, Value = #server, Value = #srvproduct2, Value = #provider, Value = #datasrc, Value = #location, Value = NULL, Value = #catalog)
I have been trying to look for it in mssql but I cant find it, what does it mean? I know EXEC is used to execute stored procedure, but what is %%System()?
and what is FireTrigger? is it an embedded command in the system? external dll? been trying to Google it but it seems to be vague at the moment.
This is an internal mechanism that is sometimes exposed but you can't call it yourself and it is undocumented.

Simple Math Stored Procedure Returning NULL?

I would appreciate if someone could let me know why this stored procedure returns NULL (I am using SQL Server 2005)? Thanks for the help.
CREATE PROCEDURE calc_runningtotal_averageprice_realisedpl
#filled_size REAL,
#reported_execution REAL,
#old_running_total REAL,
#old_average_price REAL,
#new_running_total REAL OUTPUT,
#new_average_price REAL OUTPUT,
#realised_pl REAL OUTPUT
AS
BEGIN
SET #new_running_total = #old_running_total + #filled_size
SET #realised_pl = 0
IF SIGN(#filled_size) = SIGN(#old_running_total)
BEGIN
SET #new_average_price = (#filled_size * #reported_execution + #old_running_total * #old_average_price) / (#new_running_total)
END
ELSE
BEGIN
DECLARE #quantity REAL
IF ABS(#reported_execution) < ABS(#old_running_total)
SET #quantity = ABS(#reported_execution)
ELSE
SET #quantity = ABS(#old_running_total);
SET #realised_pl = (#reported_execution - #old_average_price) * #quantity * SIGN(#filled_size) * -1;
SET #new_average_price =
CASE
WHEN ABS(#filled_size) < ABS(#old_running_total) THEN #old_average_price
WHEN ABS(#filled_size) = ABS(#old_running_total) THEN 0
WHEN ABS(#filled_size) > ABS(#old_running_total) THEN #reported_execution
END
END
END
IF I run the following, I get 3 NULLS
DECLARE #new_running_total REAL
DECLARE #new_average_price REAL
DECLARE #realised_pl REAL
EXEC calc_runningtotal_averageprice_realisedpl 1, 1, 2, 2, #new_running_total, #new_average_price, #realised_pl
SELECT #new_running_total, #new_average_price, #realised_pl
I am expecting something like 3, 1.66666, 0
You are simply not decorating the output parameters in the call with OUTPUT:
EXEC calc_runningtotal_averageprice_realisedpl 1, 1, 2, 2,
#new_running_total OUTPUT,
#new_average_price OUTPUT,
#realised_pl OUTPUT

Resources