How to get around UDF restriction on side-effecting operators? - sql-server

Microsoft Books Online (BOL) on Using Change Data explains a misleading error messages for cdc.fn_cdc_get_all_changes_* & cdc.fn_cdc_get_net_changes_* when an invalid, out-of-range LSN (Log Sequence Number) has been passed to them.
Msg 313, Level 16, State 3, Line 1
An insufficient number of arguments were supplied for the procedure or function `cdc.fn_cdc_get_all_changes_` ...
Msg 313, Level 16, State 3, Line 1
An insufficient number of arguments were supplied for the procedure or function `cdc.fn_cdc_get_net_changes_` ...
Their explanation on this misleading error message is as following
Note:
It is recognized that the
message for Msg 313 is misleading and
does not convey the actual cause of
the failure. This awkward usage stems
from the inability to raise an
explicit error from within a TVF.
Nevertheless, the value of returning a
recognizable, if inaccurate, error was
deemed preferable to simply returning
an empty result. An empty result set
would not be distinguishable from a
valid query returning no changes.
Here is a demonstration of what the note meant RAISERROR
There are times when I'd like to throw an error and you cannot use TRY..CATCH within UDF since it also has a side-effect like RAISERROR.
Now the question is, how do you get around this problem?
I am sure that you have faced with this restriction before.
What alternative would you suggest?
[UPDATE] Let's suppose that you are forced to use UDF.

In the case of your function which returns BIT, I'll return NULL back to the calling code, and at some point after using the function check for NULL, and throw an error then.

Related

How to interpret SQL Server errors?

Whenever I make a syntax error in a SQL Server query, I get an error message which I find pretty hard to interpret. For example the error that I have right now is
Msg 102, Level 15, State 1, Procedure myQuery, Line 3 [Batch Start Line 57]
Incorrect syntax near '!'.
I used table!column instead of table.column. I fixed my problem because I understood this bit:
Incorrect syntax near '!'
However, I do not understand how to interpret this message
Msg 102, Level 15, State 1, Procedure myQuery, Line 3 [Batch Start Line 57]
Do people usually just ignore that part? I have been getting along just fine without paying much attention to it. But being able to understand the error message might help be locate exactly where the error is.
Edit:
I don't understand what Msg, Level, State, Batch and Start Line means
Edit2:
Besides the accepted answer this link also helped me clear up my misunderstanding of what line number means. I always thought that line number meant the line in the SQL query where the error is which confused me. Turns out the line number is the line in the query window. To enable line number in query editor window go to :
Tools > Options > Text Editor > Transact-SQL > General >Line Numbers
Press OK
From Understanding Database Engine Errors:
Errors raised by the Microsoft SQL Server Database Engine have the (following) attributes:
Error number
Each error message has a unique error number.
Error message string
The error message contains diagnostic information about the cause of the error. Many
error messages have substitution variables in which information, such as the name of
the object generating the error, is inserted.
Severity
The severity indicates how serious the error is. Errors that have a low severity, such
as 1 or 2, are information messages or low-level warnings. Errors that have a high
severity indicate problems that should be addressed as soon as possible.
State
Some error messages can be raised at multiple points in the code for the Database
Engine. For example, an 1105 error can be raised for several different conditions.
Each specific condition that raises an error assigns a unique state code.
When you are viewing databases that contain information about known issues, such as
the Microsoft Knowledge Base, you can use the state number to determine whether the
recorded issue is the same as the error you have encountered. [...]
Procedure name
Is the name of the stored procedure or trigger in which the error has occurred.
Line number
Indicates which statement in a batch, stored procedure, trigger, or function generated
the error.
Specifically, [Batch Start Line 57] means that you are running a script with multiple batches - (if it's in SSMS the batches are separated by the GO keyword) - so the error is in the 3rd line of the batch that starts in line 57 of the script.
Here's a break down of the error message you've posted to it's parts:
ErrorNumber
Msg 102,
Severity
Level 15,
State
State 1,
Procedure
Procedure myQuery,
Line number
Line 3 [Batch Start Line 57]
Error message string
Incorrect syntax near '!'.
Unfortunately, this did not work for me. I use the latest version of SSMS or sql server management studio. I have a SQL script (in query editor) which has about 100 lines of code. This is error I got in the query:
Msg 245, Level 16, State 1, Line 2
Conversion failed when converting the nvarchar value 'abcd' to data type int.
The error message is either incorrect or simply misleading. The actual error on line number 70 in the query editor ! When, I click on the error message, it takes me to line 2 which is just a simple select top 1. Google searches revealed that the error had something to do with String concatenation, but there was no concatenation in my sql code.
Luckily, I remembered that I had seen this kind of error before when I forgot to enclose a number (in varchar column) in single quotes. So, it looks like SSMS is useless when it comes to debugging errors.

Error in Ingeres E_SC0520_SCS_BAD_DBV SCS_INPUT invalid DBV detected:

Please need help! Issuing this problem for couple days cannot understand and find any useful information on how to resolve it
I am getting this error when I am trying to run procedure with call from php
E_AD2005_BAD_DTLEN ADF routine found DB_DATA_VALUE with an invalid length.
E_SC0520_SCS_BAD_DBV SCS_INPUT invalid DBV detected: db_datatype = -20, db_length = 1, db_prec = 0.
E_SC021C_SCS_INPUT_ERROR SCS_INPUT internal error.
any idea how to resolve it and what does it mean ?
also, strange thing i am getting this error only if I do call from php , if I am calling this procedure from Visual DBA its running perfectly with no errors.
The value of one of your parameters is inconsistent with the declaration in the procedure..
Remember php by default does not define its variables until you put something in it so if you are dealing with a string and it has numeric values php will see that as a numeric variable ..
If in doubt cast your variables (string) $variable_name.

SQLCLR Aggregate: no message about NULL values being eliminated

when I do
SELECT SUM(some_field) FROM some_table
the result is a single record/field with a number in it. Additionally, there will be a message send to the client along the lines of Warning: Null value is eliminated by an aggregate or other SET operation. in case some_field has a NULL value in the table somewhere. Only when they all are NULL (or the table is empty) it will return NULL.
I'm currently in the process of writing my own SqlUserDefinedAggregate and although things work as expected, it does NOT show me this message when one of the values passed turns out to be NULL. The outcome of the function is still correct, but there is no warning. First I assumed I might have to pipe this manually in the Terminate() method, but alas, SQLCLR then throws me an InvalidOperationException saying Data acces is not allowed in this context.
Any hints?
If your aggregate is discarding NULLs then the IsInvariantToNulls property should definitely be set to true else you might get unexpected results sometimes, as stated on the MSDN page for SqlUserDefinedAggregateAttribute.IsInvariantToNulls:
Used by the query processor, this property is true if the aggregate is invariant to nulls. That is, the aggregate of S, {NULL} is the same as aggregate of S. For example, aggregate functions such as MIN and MAX satisfy this property, while COUNT(*) does not.
Incorrectly setting this property can result in incorrect query results. This property is not an optimizer hint; it affects the plan selected and the results returned by the query.
And a UDA is a function so there is no SqlContext.Pipe to use. And even if there was, the Terminate method isn't an appropriate place to handle this since it executes for every group. The warning you are seeing when using SUM, however, is an ANSI warning and is displayed once for the query, not per group.
So, if SQL Server isn't displaying the warning then there likely isn't anything you can do about it. I assume that SQL Server isn't using the IsInvariantToNulls property as a means of knowing if it should display the message or not because it is not guaranteed to be accurately set.
And personally, I find this to be a benefit since, in my opinion, the "Null value is eliminated by an aggregate" warning is entirely not helpful, yet if you want to get rid of it you need to use ISNULL() to inject a value that won't influence the result (e.g. 0 in the case of SUM), or turn off ALL ANSI warnings, in which case you disable some warnings that are sometimes helpful.

How do SQL Server table-valued functions report errors?

When I query a SQL Server 2008 system dynamic management view which is implemented as a table-valued function and it returns an empty result set, how can I tell that the reason for the empty result set is that an error occurs in the function, and then, what that error is?
There is a much more useful way to force an error inside a function in TSQL than performing a division by zero. What we do at our company is to cast a string (describing the very problem) and convert it to a string.
if #PersonID is null
insert into #Result values(#Right, cast('FT_AclGetAccess must never be called with #PersonID null' as int))
This will result in an error on the application server looking like this:
Conversion failed when converting the varchar value 'FT_AclGetAccess
must never be called with #PersonID null' to data type int.
A little string manipulation on the application server and you get a pretty sane error message for the log file! ;-)
They don't. You cannot use THROW nor RAISERROR inside T-SQL functions. Some devs force a divide by 0 to trigger an error inside UDFs. This works fine, but sometimes confuses the poor soul that has to investigate a divide by 0 error that comes from apparently nowhere.

Error Handling in User Defined Functions

I want to write a non-CLR user-defined function in SQL Server 2005. This function takes an input string and returns an output string. If the input string is invalid, then I want to indicate an error to the caller.
My first thought was to use RAISERROR to raise an exception. However, SQL Server does not allow this inside a UDF (though you can raise exceptions in CLR-based UDFs, go figure).
My last resort would be to return a NULL (or some other error-indicator value) from the function if the input value is in error. However, I don't like this option, as it:
Doesn't provide any useful information to the caller
Doesn't allow me to return a NULL in response to valid input (since it's used as an error code).
Is there any caller-friendly way to halt a function on an error in SQL Server?
It seems that SQL Server UDF's are a bit limited in this (and many other) way.
You really can't do a whole lot about it - that's (for now) just the way it is. Either you can define your UDF so that you can signal back an error condition by means of its return value (e.g. returning NULL in case of an error), or then you would almost have to resort to writing a stored procedure instead, which can have a lot more error handling and allows RAISERROR and so forth.
So either design your UDF to not require specific signaling of error conditions, or then you have to re-architect your approach to use stored procedures (which can have multiple OUTPUT parameters and thus can also return error code along with your data payload, if you need that), or managed CLR code for your UDF's.
Sorry I don't have a better idea - for now, I'm afraid, those are your options - take your pick.
Marc
There's a possible solution given in an answer to a duplicate question here, based on this idea:
return cast('Error message here.' as int);
Which throws something like this:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value 'Error message here.' to data type int.
It works OK for scalar-valued UDFs, but not for table-valued ones.

Resources