Two Percent Signs in EXEC Statement - sql

In SQL Server 2014, the master database contains a system stored procedure called sp_rename. I was interested to know how it works, so I've been taking a look at it.
On line 190, there is an EXEC statement that contains two percent signs:
EXEC %%ScalarType(MultiName = #SchemaAndTypeName).LockMatchID(ID =
#xusertype, Exclusive = 1)
What does the %% mean? I've searched around online, but haven't found anything that even remotely mentions it.

Based off of this answer, it's an undocumented component of SQL Server. Basically, these are system commands that a typical user is not supposed to reference. Since you're looking at the components of a stored procedure, you'll see scripts that are normally inaccessible to a normal user.
Since the %% is (intentionally) undocumented it's difficult to determine exactly how the system is using it, but one can reasonably assume it's an indicator of system-only commands.

Related

How to use this weird .sql file?

I have a very strange 'reload.sql' file that I need to use to build a database.
It references about 200 XXX.dat files with straight-up readable data (although useless without explanations regarding the meaning of the fields).
I have tried msssql server, mysql workbench (on a server local-hosted on wamp), and directly accessing it through DBeaver and IBConsole, but I cannot manage to execute/build it.
It uses a weird syntax. There are elements like
begin
...
end
go
that hinted me towards T-SQL, but using sqlcmd on it gave me thousands upon thousands of errors regarding keywords.
Specifically, the very first batch of executable lines says
SET OPTION date_order = 'YMD'
go
SET OPTION PUBLIC.preserve_source_format = 'OFF'
go
SET TEMPORARY OPTION tsql_outer_joins = 'ON'
go
SET TEMPORARY OPTION st_geometry_describe_type = 'binary'
go
SET TEMPORARY OPTION st_geometry_on_invalid = 'Ignore'
go
SET TEMPORARY OPTION non_keywords = 'attach,compressed,detach,kerberos,nchar,nvarchar,refresh,varbit'
go
which generates about 150 errors 'Incorrect syntax near OPTION keyword' on its own, and according to google is part of a 'rexx' procedure but 'date_order' should then be 'DATFMT', right?
Another track is that of SyBase, but I cannot for the life of me get it to work (through my trials I did manage to build a .db file, that, well, is useless to me since I can't build it either..).
I've tried accessing it through ODBC pilots as well but none worked (the paradox ODBC did not crash, but said there was an error with a FROM clause, which are generated automatically...).
I need to know a way to build a database from this file or directly access the data it references, which I can't really post since it contains private medical data.
Also what madman came up with this.
The very first google link (for me anyway) against 'st-geometry-describe-option' shows this is a SAP SQL Anywhere database i.e. http://dcx.sybase.com/1200/en/dbadmin/st-geometry-describe-option.html
So I would suggest starting from the SQL Anywhere documentation and you will need to install the database software beforehand.

Must force MS SQL Server (2012) to return to it's "virgin" state when re-running an edited T-SQL script

Very often extremely trival edits cause my T-SQL scripts to fail when rerun from within a MS SQL Server 2012 edit window (e.g. "SqlQuery1.txt"). Frustratingly, there's no pattern to what (edits) cause this problem. Coping with this has forced me to jump through some wierd hoops.
An example: I changed exactly 1 character in a working query (from "Set #THisColumn = 1" to "Set #ThisColumn = 1"; the "H" was changed to "h'" to match the variable declaration). When the script was rerun MS SQL Server 2012 gave me this error:
Msg 213, Level 16, State 1, Line 54
Column name or number of supplied values does not match table definition.
My research shows this message gets thrown when there is a problem with a TABLE which should be impossible in the above case. The error is unimportant, my problem is much more general - having to use the following unsatisfactory "workaround":*
Copy the (edited) script into a new edit pane ("SQLQuery2.txt"). It works - until the next time it's edited. Which then forces me to use another edit pane ("SQLQuery3.txt"). Repeat ad nausum.
Having to do this supports the theory that the problem is somehow related to how the edit pane works - NOT the script. (Hence the title of this question)
Using this "workaround" destroys my train of thought while the resulting large number of open "scratchpad" windows causes me to lose track of what I was doing ("... lets see now, is it version 13, 17, 26 or 28 that is the last "known good" version?...).
My suspicion is that SQL considers every subsequent rerun as being a part (a continuation) of the FIRST invocation of that script. So it tries to be "helpful" (not!) by "optimizing" the query.
In a development environment this "assistance" is very premature - and exactly what I do NOT want to have happen. (First make it work...then optimize it.) How do I supress this undesirable behavoir?
From my research I know that my scripts must have lines like this one before creating a temporary table:
IF OBJECT_ID( 'tempdb..#XYZ) IS NOT NULL DROP TABLE #XYZ
and for a temporary procedure:
IF OBJECT_ID( 'tempdb..#ABCD) IS NOT NULL DROP PROCEDURE #ABCD
GO -- Required before defining any procedure
CREATE PROCEDURE #ABCD
The need to do this implies that my supposition may be correct (why else would you need to do it?).
What else has to be done so that every time I press the "execute" button I get a "clean restart" of SQL?
Other factors to keep in mind:
The script, invoked from Python 3.x, is periodically (and
frequently) run as batch/cron job (i.e. an automatically scheduled
task). This means that any form of manual intervention (e.g. using
tools like MS 2012 Management Studio etc.) is not an option.
Stored procedures aren't allowed, instead the python application reads a file of SQL commands that get passed to SQL for execution
(in effect emulating a user who types in those commands at a SQL
console).
Finally the script must also work for users that have the minimum
possible (e.g "guest") privileges
.

How do I declare a variable for a hard coded database?

I have some hard coded database values in my SQL and I need to convert to variables , I have declared them in places but I need Production2 to be changed to #Source_Database_Name variable below but I dont know how to place it in with the Information Schema just after it without getting a syntax error
IF EXISTS(SELECT * FROM Production2.INFORMATION_SCHEMA.COLUMNS
I guess that the only way you can do this is dynamic sql generation (unfortunately). And there's actually quite a few reasons (from database engine's perspective) for not allowing a user to parametrise queries in a way you want. The one that sits on top of my head is that it will make impossible to validate syntax of your query (no way to know that you're referring to what actually exists).
In case you're talking about "being able to execute the same set of SQL against different database(s)" and you're actually executing this sql from code (.NET / anything), you can achieve the same result by specifying target database in connection string (i.e. by changing the level where you set database -- not in the [sql] script, but rather at some external point).

SQL Parameters - where does expansion happens

I'm getting a little confused about using parameters with SQL queries, and seeing some things that I can't immediately explain, so I'm just after some background info at this point.
First, is there a standard format for parameter names in queries, or is this database/middleware dependent ? I've seen both this:-
DELETE * FROM #tablename
and...
DELETE * FROM :tablename
Second - where (typically) does the parameter replacement happen? Are parameters replaced/expanded before the query is sent to the database, or does the database receive params and query separately, and perform the expansion itself?
Just as background, I'm using the DevArt UniDAC toolkit from a C++Builder app to connect via ODBC to an Excel spreadsheet. I know this is almost pessimal in a few ways... (I'm trying to understand why a particular command works only when it doesn't use parameters)
With such data access libraries, like UniDAC or FireDAC, you can use macros. They allow you to use special markers (called macro) in the places of a SQL command, where parameter are disallowed. I dont know UniDAC API, but will provide a sample for FireDAC:
ADQuery1.SQL.Text := 'DELETE * FROM &tablename';
ADQuery1.MacroByName('tablename').AsRaw := 'MyTab';
ADQuery1.ExecSQL;
Second - where (typically) does the parameter replacement happen?
It doesn't. That's the whole point. Data elements in your query stay data items. Code elements stay code elements. The two never intersect, and thus there is never an opportunity for malicious data to be treated as code.
connect via ODBC to an Excel spreadsheet... I'm trying to understand why a particular command works only when it doesn't use parameters
Excel isn't really a database engine, but if it were, you still can't use a parameter for the name a table.
SQL parameters are sent to the database. The database performs the expansion itself. That allows the database to set up a query plan that will work for different values of the parameters.
Microsoft always uses #parname for parameters. Oracle uses :parname. Other databases are different.
No database I know of allows you to specify the table name as a parameter. You have to expand that client side, like:
command.CommandText = string.Format("DELETE FROM {0}", tableName);
P.S. A * is not allowed after a DELETE. After all, you can only delete whole rows, not a set of columns.

Dynamic SQL Within A Stored Procedure Security

I've got the SQL stored procedure from hell that I've created and all input parameters are parameterised for security but it's not running as quick as I'd like so I wanted to make it dynamic and so a bit more efficient.
I know I can keep my input parameters to my stored procedure, then within it create a dynamic SQL statement into which I can then pass the input parameters of the stored procedure, but are there any security implications I need to be aware of when doing this? I'm guessing not as it just another set of parameters and they should be treated the same as the parameters passed to the current stored procedure.
Obviously, producing code like this "WHERE OrderNo = ' + #orderno is asking for trouble - I will be doing 'WHERE OrderNo = #orderno' in the dynamic SQL, but is there anything else I need to be aware of?
Thx MH
PS - before anyone suggests it, I can't create the SQL dynamically at the client side using LINQ or similar - it all (for various reasons) has to be contained and controlled at the database level
There is a form of SQL injection that many people don't think about when doing dynamic SQL in stored procedures: SQL Truncation attacks.
With a SQL truncation attack, the attacker injects a long peace of text making the used text variable overflow and lose part of the query.
This article gives more information about this.
Where your parameters are always Data Items, both when being passed to the StoredProc and when used in yor DynamicSQL, everything will stay safe.
Should any of your StoredProc's parameters end up being table or field names, and so forming part of the structure of the DynamicSQL itself, you introduce a new risk : That the parameter can be used to inject rogue SQL Code.
To prevent against such an injection attack you should always validate any such parameters.
One example of how to do this would be to use the input parameter as a token, rather than substitute it directly into the DynamicSQL...
SET #SQL = #SLQ + CASE targetTable WHEN '1' THEN 'table1'
WHEN 'tx' THEN 'tableX'
END
Some people suggest you only need to validate on the client application. But that means that if someone becomes able to execute you SP's directly, the SP has become a point of attack. I always prefer to validate both on the client AND in the server.
EDIT Performance
Note that using DynamicSQL isn't always a guarnatee of performance increases. If you use parameterised queries, the execution plans can indeed be stored. But if the queries do vary greatly, you may still find a significant overhead in compiling the SQL.
There is also the fact that dependancy tracking is lost. It's not possible to see what tables the SP is dependant on, because the code is hidden away as strings.
I have very rarely found that DynamicSQL is needed. Often a complex query can be reformed as several optimised queries. Or the data can be re-structured to meet the new demands. Or even a rethink of both the data and the algorithm using the data. One might even be able to suggest that a dependancy on DynamicSQL is an indicator of another underlying problem.
Perhaps it's not in the scope of your question, but it would be interesting to see the actual puzzle you're facing; to see if anyone has any alternative approaches for you.