PRINT statement in T-SQL - sql-server

Why does the PRINT statement in T-SQL seem to only sometimes work? What are the constraints on using it? It seems sometimes if a result set is generated, it becomes a null function, I assumed to prevent corrupting the resultset, but could it's output not go out in another result set, such as the row count?

So, if you have a statement something like the following, you're saying that you get no 'print' result?
select * from sysobjects
PRINT 'Just selected * from sysobjects'
If you're using SQL Query Analyzer, you'll see that there are two tabs down at the bottom, one of which is "Messages" and that's where the 'print' statements will show up.
If you're concerned about the timing of seeing the print statements, you may want to try using something like
raiserror ('My Print Statement', 10,1) with nowait
This will give you the message immediately as the statement is reached, rather than buffering the output, as the Query Analyzer will do under most conditions.

The Print statement in TSQL is a misunderstood creature, probably because of its name. It actually sends a message to the error/message-handling mechanism that then transfers it to the calling application. PRINT is pretty dumb. You can only send 8000 characters (4000 unicode chars). You can send a literal string, a string variable (varchar or char) or a string expression. If you use RAISERROR, then you are limited to a string of just 2,044 characters. However, it is much easier to use it to send information to the calling application since it calls a formatting function similar to the old printf in the standard C library. RAISERROR can also specify an error number, a severity, and a state code in addition to the text message, and it can also be used to return user-defined messages created using the sp_addmessage system stored procedure. You can also force the messages to be logged.
Your error-handling routines won’t be any good for receiving messages, despite messages and errors being so similar. The technique varies, of course, according to the actual way you connect to the database (OLBC, OLEDB etc). In order to receive and deal with messages from the SQL Server Database Engine, when you’re using System.Data.SQLClient, you’ll need to create a SqlInfoMessageEventHandler delegate, identifying the method that handles the event, to listen for the InfoMessage event on the SqlConnection class. You’ll find that message-context information such as severity and state are passed as arguments to the callback, because from the system perspective, these messages are just like errors.
It is always a good idea to have a way of getting these messages in your application, even if you are just spooling to a file, because there is always going to be a use for them when you are trying to chase a really obscure problem. However, I can’t think I’d want the end users to ever see them unless you can reserve an informational level that displays stuff in the application.

Query Analyzer buffers messages. The PRINT and RAISERROR statements both use this buffer, but the RAISERROR statement has a WITH NOWAIT option. To print a message immediately use the following:
RAISERROR ('Your message', 0, 1) WITH NOWAIT
RAISERROR will only display 400 characters of your message and uses a syntax similar to the C printf function for formatting text.
Please note that the use of RAISERROR with the WITH NOWAIT option will flush the message buffer, so all previously buffered information will be output also.

I recently ran into this, and it ended up being because I had a convert statement on a null variable. Since that was causing errors, the entire print statement was rendering as null, and not printing at all.
Example - This will fail:
declare #myID int=null
print 'First Statement: ' + convert(varchar(4), #myID)
Example - This will print:
declare #myID int=null
print 'Second Statement: ' + coalesce(Convert(varchar(4), #myID),'#myID is null')

For the benefit of anyone else reading this question that really is missing print statements from their output, there actually are cases where the print executes but is not returned to the client. I can't tell you specifically what they are. I can tell you that if you put a go statement immediately before and after any print statement, you will see if it is executed.

Do you have variables that are associated with these print statements been output? if so, I have found that if the variable has no value then the print statement will not be ouput.

Related

Avoid newline when using raiserror

Suppose I debug using raiserror, like so:
raiserror('Trying to do something...',0,0) with nowait
(queries that do something)
raiserror('Done.',0,0) with nowait
It would be handy to have this output in the "Messages" of SSMS in a single line:
Trying to do something...Done.
Is there a way? I haven't found anything around
No, either you wait until both actions are complete and print a single line with one call, or you have the output on two lines. SSMS (and ADS) just aren’t equipped to do what you want to do.

Prevent scripts generating errors in blocks that aren't executed?

if 1=0
begin
print 'This should not run'
select NonexistentField from MyTable
end
else
print 'This should run'
Inside that code I reference a field that depending on the scenario, may or may not exist. The script is meant to be deployed in varied scenarios, and this line is supposed to be avoided by conditional branching in the cases where it's not applicable. This is meant to be simulated by the 1=0 condition meaning the field is absent in this test, so the code using it is not to be executed.
The thing is, even if the select line doesn't execute, provided MyTable exists, the script throws an
invalid column name
error even before running, and the "This should run" message is never shown.
If, on the other hand, MyTable doesn't exist, the code runs fine and the expected "This should run" is shown.
What sense is there to be made from this?
Is there any way to avoid parts of the script that aren't meant to run generating these errors?
As it is, I find myself unable to have a condition indicate whether a field in a table exists, because the code will fail anyway.
Is there any way to avoid parts of the script that aren't meant to run generating these errors?
You need to keep the invalid code from being compiled. So use dynamic SQL.
if 1=0
begin
print 'This should not run'
exec ('select NonexistentField from MyTable')
end
else
print 'This should run'

SQL Injection, ignore first select command

I am trying to build a scenario that would allow me to expose additional data from a server (for case-demo purposes). The server calls a vulnerable SQL code:
EXEC my_storeProc '12345'
where "12345" (not the single quotes) is the parameter. This performs a SELECT statement. I would like to eliminate this execution and instead call my own select statement, however the server side code will only accept the first select statement called, contained within the aforementioned EXEC call. Calling the second statement is easy:
EXEC my_storeProc '12345 ' select * from MySecondTable--
(the -- at the end will block the closing single quote added by the server to prevent errors). My problem is that although there are 2 select statements, the server will only parse the first one. Is there a way to cancel the first EXEC call without throwing an error so that the second one would be taken instead? Perhaps even a UNION but there isn't much I can do with only one variable open to exploit (variable being 12345 in this case).
You have to think of how it will be executed, specifically you want it called so it doesn't raise an exception and put the kabosh on the whole statement. You can't set the result to always true with a proc call, so there is no real way escape the proc. Instead, you'll want to slip a second command in, Your desired code looks like;
exec my_Storeproc '1234'; select * from mysecondtable
So we need to close the quotes, and make a new statement. That would mean the string with the insert needs to be;
1234'; select * from mysecondtable where 1 = '1
There is a flaw in this, whatever command you are executing is not being returned to the UI. To get the data you'll have to add a server connection to the second command.
To make the second command unnecessary you would have to inject code into the proc, which is a non starter since the proc is already complied and sql injection relies on confusing the compiler as to what is data and what is commands. For a more verbose explanation of that check out this answer:
https://security.stackexchange.com/a/25710

Trying to escape a sp_executesql variable

I've run in to a problem with a software I'm configuring. I do not have access to the source code, only the config.
The issue is as follows, in the configuration the software expects me to enter a string, but I would like the string to jump out of the compare and instead execute a funtion.
Using sql profiler I get something like this:
exec sp_executesql N'SELECT * FROM dummyTable WHERE (Name LIKE #Pattern)',N'
This does not work in my setup, because pattern is not clearly defind in advanced. I need to take the
variable passed as pattern and run it trough a sql function but I can't figure out how. Typically Pattern contains a single char, in my example "1". I've tried altering the Pattern to use an escape char and run my function on it, but I think I'm missing someting (If this is at all possible).
The variable I've send from config is as follows:
{0}' or Name like dbo.RunCalulation({0})
Giving me the following:
'…#Pattern nvarchar(43)',#Pattern=N'1'' or Name like dbo.RunCalulation(1) '
This executes, but does not give any response, so I think the esacpe char does not work, and it compares the whole string to Name.
I'm real stuck at this, hope someone has a good idea what to do (I know that not having the source code is a real problem here.
One of the huge advantages of query parameters (such as #Pattern) is that they help protect against SQL injection (which is what you are trying to do).
So the answer is that you cannot do what you want. There's no way to escape the #Pattern parameter and add some of your own SQL to that query, because everything you pass as #Pattern will be interpreted as data, and never as SQL command text (which is the reason why your SQL text ends up inside the single quotes, and why your quote is automatically escaped to ''.).

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