There are dangers to using the xp_sprintf system call in SQL Server 2000.
- Firstly, it has a 256 character limit, and
- secondly, it suffers from a buffer overflow bug in some versions which can cause all sorts of unpredicatable damage.
- it also provides a vulnerability in that an attacker can inject code which could gain access to your data.
In short, it wasn’t one of Microsoft’s best moments.
There are a few occasions where something like the xp_sprintf is very handy. I find that, when writing a multi-lingual application where the user can set the language used at any point in time, it is very handy to have any text read from a table with placeholders for the actual data.
The english version of the string might be ‘You have %s%s%s left in your account’, with the first parameter being the prefix currency symbol (e.g. ‘£’) or blank if it is postfix, the second being the value, and the third being any postfix currency symbol.
I discovered the 256 -character limit of xp_sprintf by accident, late at night trying to meet a deadline whilst trying to work out why strings were getting truncated.
Here is a version, as a user function, returning a varchar(8000), that has a more reasonable 8000 character limit. Whilst I was about it, I made the delimiter for the insertion list configurable, and the placeholder (traditionally ‘%s’) configurable too
Having done it, I wondered whether this sort of routine could be developed to extend its usefulness. Could it be rewritten for TEXT variables, for example? could it be altered to add resultsets in the same way as sp_MakeWebTask, or to do more complex HTML presentation jobs?
I’d be interested to hear from anyone who has done so.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
CREATE FUNCTION dbo.ufsSPrintf ( @FormatString VARCHAR(8000), @Args VARCHAR(8000), -- delimited list @Delimiter VARCHAR(80) = ',', @PlaceHolder VARCHAR(80) = '%s' ) RETURNS VARCHAR(8000) AS BEGIN DECLARE @Start INT; DECLARE @End INT; DECLARE @Where INT; DECLARE @LenDelimiter INT; DECLARE @LenPlaceholder INT; DECLARE @ii INT; SELECT @Start = 1, @LenDelimiter = Len(@Delimiter), @LenPlaceholder = Len(@PlaceHolder), @ii = 1; IF(@FormatString + @Args + @Delimiter + @PlaceHolder IS NOT NULL) WHILE(1 = 1) BEGIN SELECT @End = CharIndex(@Delimiter, Coalesce(@Args, '') + @Delimiter, @Start ), @Where = CharIndex(@PlaceHolder, @FormatString); IF @End < @Start + 1 OR @Where = 0 BREAK; --if no more variables or placeholders SELECT @FormatString = Stuff(@FormatString, @Where, @LenPlaceholder, Substring(@Args, @Start, @End - @Start) ); SELECT @Start = @End + @LenDelimiter, @ii = @ii + 1; END; RETURN Replace(@FormatString, @PlaceHolder, ''); END; /* Usage: select dbo.ufsSprintF ('Dear %s, your account is now overdrawn to the value of £%s beyond your credit limit of £%s and in consequence we must ask for an immediate payment of £%s. Assuring you of our continued service Signed %s, manager','Miss Cannon|25|100|125|Phil Factor','|','%s') select dbo.ufsSprintF ('to %s, or not to %s. That is the question' ,'be|be' ,'|' ,'%s') */ |
1 |
Load comments