VB.net parameterized query uses sp_executesql but loses UTF8 characters - sql-server

I have an odd scenario that I'm looking for some clarification on.
I currently have an VB.net application that is sending the parameterized query below to an SQL Server 2019 database using ADO.net. To make the database support UTF8, we are using one of the new _UTF8 collations. For this test, we are using a database configured to use Latin1_General_100_CI_AI_SC_UTF8.
Query:
exec sp_executesql
N'UPDATE Roles SET Name = #pName WHERE Role_ID = 6',
N'#pName varchar(1000)',
#pName='æææDeveloper'
Now, I know that when I run the query above in MSSQL Management Studio, I don't lose my 'æ' characters but if I run this through code, my characters are replaced by '?'. My question is why would I lose them through code via ADO.net and not through MSSQL Management Studio.
I also know that sp_executesql does not support varchar as parameters which was the main problem and we were able to solve but again. Why would it work in MSSQL but not in ADO.net?

Related

Write a script to run on different SQL engines

I'm writing a SQL script that needs to be able to run on multiple SQL engines, namely SQL Server and Azure SQL. An IF statement checks the database version to execute the correct code. But the code won't compile if used on the wrong engine.
This works fine in Azure SQL, but SQL Server rejects it.
IF (##VERSION LIKE 'Microsoft SQL Azure %')
BEGIN
ADD SENSITIVITY CLASSIFICATION TO [dbo].[User].[UserName] WITH (LABEL = 'Confidential', INFORMATION_TYPE = 'Credentials')
...
END
GO
What are my options for ensuring this is accepted by both engines?
Dynamic SQL could be used to circumvent syntax check:
IF (##VERSION LIKE 'Microsoft SQL Azure %')
BEGIN
EXEC('ADD SENSITIVITY CLASSIFICATION TO [dbo].[User].[UserName] WITH (LABEL = ''Confidential'', INFORMATION_TYPE = ''Credentials'')');
...
END
GO
Please note that all ' have to be quoted i.e.''. Add support for here-strings i T-SQL
ADD SENSITIVITY CLASSIFICATION will be supported starting from SQL Server 2019.

SQL Server Profiler does not show data in SQL statement

I am using the SQL Server Profiler to trace the SQL generated from nHibernate in a Windows SmartClient appplication.
The trace of the SQL statement does not show actual data, but rather, looks like this:
exec sp_executesql N'SELECT attachment0_.RecordKey as RecordKey1_, attachment0_.Id as Id1_, attachment0_.Id as Id87_0_, attachment0_.RecordType as RecordType87_0_, attachment0_.RecordKey as RecordKey87_0_, attachment0_.FileName as FileName87_0_, attachment0_.OriginalFileName as Original6_87_0_, attachment0_.DateTimeAttached as DateTime7_87_0_ FROM MyDatabase.dbo.tblAttachment attachment0_ WHERE attachment0_.RecordKey=#p0',N'#p0 int',#p0=262
Is there a way to see the the actual data in the SQL command?
It's just showing the parameterized sql. If you want to log or to show non-parameterized sql I came up with a solution to this here:
Execute NHibernate-generated prepared statements in SQL Server Management Studio
The item of note is the log4net appender that basically translates this in the accepted answer.

How do you call a SQL Server Stored Procedure in BI Publisher 11g?

I am trying to call a Microsoft SQL Server Stored Procedure that delivers data in table like format (rows / columns) in Oracle BI Publisher 11g (11.1.1.7).
Selecting procedure call as a data source for the data model does not work because BIP expects it to behave like a PL/SQL call to an Oracle database instead.
Oracle developers claim this is not supported by the software.
Is there any way around this restriction?
Although not supported out-of-the-box by BI Publisher 11g, there is a workaround to the problem. It involves tricking the software into thinking it is making a standard PL/SQL call when in fact in reality it is executing a stored procedure on the SQL Server datasource.
1) Make sure you have the native MS SQL server library installed on your weblogic server running the BIP instance.
It can be downloaded from MSDN here: http://msdn.microsoft.com/en-us/sqlserver/aa937724.aspx - depending on your JRE version you'll want to use one or the other jar file:
For JRE 1.6 and above, use sqljdbc4.jar. For 1.5 and below, use sqljdbc.jar.
You should place this in your $MIDDLEWARE_HOME\user_projects\domains\$your_domain_here$\lib\ folder and remember to restart weblogic server afterwards.
2) Inside BI Publisher administration, create a new JDBC datasource.
Our example works with following properties:
Driver Type: Microsoft SQL Server 2008 Database Driver Class: com.microsoft.sqlserver.jdbc.SQLServerDriver Connection String: jdbc:weblogic:sqlserver://[hostname]:[port];databaseName=[database name]
Fill in username/pw and test connection (if driver is installed correctly, this should work just fine)
3) Create a new datamodel.
Choose SQL query as your dataset. Here, add in these properties:
Data Source: your JDBC data source
Type of SQL: Non-standard SQL
Row Tag Name: (choose one yourself) - for now just write test.
4) Under SQL query, we now need to convince BIP that it is calling an Oracle SP when in fact it is calling an existing stored procedure on your MS SQL datasource.
This part is assuming your stored procedure delivers N amount of rows and column labels over.
Here is how we solved it for our SP that is called nrdart_get_custody_holding_headers_sp '2014-11-25' where the parameter is a date supplied by the user.
declare #var1 datetime
declare #sql varchar(255)
set #var1 = '2014-11-25'
set #sql = 'nrdart_get_custody_holding_headers_sp' +'''' + cast(#var1 as varchar) + ''''
exec (#sql)
Here, we are declaring some SQL Server datatypes, and setting them as our date parameter and as our procedure call name using some creative use of the cast function and escape characters, before finally calling exec on the stored procedure.
Parameter var1 will also work if you use a standard BIP parameter instead of our hard-coded example above
i.e. :userDate where :userDate is referring to an existing parameter called userDate in the datamodel.
Don't worry if you don't see row/column labels after clicking OK. Instead, click on "view data" and there you go. Rows and columns with data from your SP on Microsoft SQL Server. Now proceed to save this as sample data and design report layout as you would normally do. For non-date parameters you might need to play around a little bit with datatypes, but I don't see why you shouldn't get it to work with integers or varchars as well.

Is there a way to insert an encrypted script into a SQL Server database?

My company considers database scripts we write part of our intellectual property.
With new releases, we deliver a 2-part setup for our users:
a desktop application
an executable that wraps up the complexities of initializing/updating a database (RedGate SQL Packager).
I know I can encrypt a stored procedure on a database once the script is present, but is there any way to insert it in an encrypted form? I don't want plain-text to be able to be intercepted across the "wire" (or more accurately, between the SQL script executable and the server).
I'm not really tied to the tool we're using - I just want to know if it's possible without having to resort to something hokey.
Try using Enctyptpassphrase and DecryptPassPharse functions.
Use ENCRYPTBYPASSPHRASE to encrypt all your DDL statements and then DECRYPTBYPASSPHRASE on the server to decrypt and execute.
declare #encrypt varbinary(200)
select #encrypt = EncryptByPassPhrase('key', 'your script goes here' )
select #encrypt
select convert(varchar(100),DecryptByPassPhrase('key', #encrypt ))
Create a procedure that would look like this
CREATE PROCEDURE DBO.ExecuteDDL
(
#script varbinary(max)
)
AS
BEGIN
DECLARE #SQL nvarchar(max)
SET #SQL = (select convert(varchar(max),DecryptByPassPhrase('key', #script )))
EXECUTE sp_executesql #SQL
END
Once this is in place you can publish scripts to your server like this
This isn't plain-text and last I checked, it still works:
declare #_ as varbinary(max)
set #_ =0x0D000A005000520049004E0054002000270054006800690073002000620069006E00610072007900200073007400720069006E0067002000770069006C006C002000650078006500630075007400650020002200530045004C0045004300540020002A002000460052004F004D0020005300590053002E004F0042004A00450043005400530022003A0027000D000A00530045004C0045004300540020002A002000460052004F004D0020005300590053002E004F0042004A0045004300540053000D000A00
exec (#_)
Technically, it's not encryption, but it's not plaintext either and it can server as the basis for some mild encryption pretty easily.
There's little you can do to reliably prevent the code in the database to be read by anyone who really wants. The WITH ENCRYPTION parameter is really just an obfuscation and many simple scripts are able to get it again in plain text, and when the database is being upgraded, ultimately the profiler will always be able to catch the ALTER PROCEDURE statement with the full text. Network tracers can be evaded by using an encrypted connection to the server.
The real problem comes from the fact that the database is installed in a server that your users own and fully control (correct me if that's not the case). No matter what you do, they'll have full access to the whole database, it's schema, and internal programming inside sprocs/functions.
The closest I can think of to prevent that is to switch to CLR stored procedures, which are installed by copying a DLL to the server and registering within SQL Server. They pose other problems, as they are totally different to program and may not be the best tool for what you use a sproc normally. Also, since the are made of standard .NET code, they can also be trivially decompiled.
The only way I can think of fully protecting the database structure and code would be to put it in a server of yours, that you expose to your customers though, say, a webservice or a handful of sprocs as wrappers, so no one can peek inside.

SQL Server cross database alias

I'm trying to understand how I can use an alias to reference another database in the same instance, without having to use a hardcoded name.
The scenario is as below:
I have a data db with stores data, an audit db which keeps all changes made. for various reason, i want to keep the audit data in a separate database, not least because it can get quite large and for reporting purposes.
In the data db, I don't want to reference this by a hardcoded name but an alias so that in different environments, I don't have to change the name and various sp's to reference the new name.
for example:
mydevdata
mydevaudit
If a sp exists in mydevdata such as which calls the mydevaudit, I don't want to change the sp when I go to test where the db's may be called mytestdata and mytestaudit. Again, for various reasons, the database names can change, more to do with spaces an instances etc.
So if I had procedure in mydevdata:
proc A
begin
insert into mydevaudit.table.abc(somecol)
select 1
end
when I go to test, I don't want to be change the procedure to reference another name, (assume for sake of argument that happened)
Instead I am looking to do something like:
proc A
begin
insert into AUDITEBALIAS.table.abc(somecol)
select 1
end
I am interested in finding out how I could do something like that, and the pro's and cons.
Also, dymnamic SQL is not an option.
thanks in advance for you help.
You may be able to use synonyms
CREATE SYNONYM WholeTableAliasWithDBetc FOR TheDB.dbo.TheTable
This means all object references in the local DB are local to that DB, except for synonyms that hide the other database from you.
You can also use stored procedures in the audit DB. There is a 3rd form of EXEC that is little used where you can parametrise the stored proc name
DECLARE #module_name_var varchar(100)
SET #module_name_var = 'mydevaudit.dbo.AuditProc'
-- SET #module_name_var = 'whatever.dbo.AuditProc'
EXEC #module_name_var #p1, #p2, ...
Obviously you can change module_name_var to use whatever DB you like
I've just posted this to How to create Sql Synonym or "Alias" for Database Name? which is a workaround for the same situation:
There is a way to simulate this using a linked server. This assumes you have two SQL servers with the same set of databases one for development/test and one live.
Open SQL Server Management Studio on your development/test server
Right click Server Objects > Linked Servers
Select New Linked Server...
Select the General page
Specify alias name in Linked server field - this would normally be the name of your live server
Select SQL Native Client as the provider
Enter sql_server for Product Name
In Data Source specify the name of the development server
Add Security and Server Options to taste
Click OK
The above is for SQL Server 2005 but should be similar for 2008
Once you've done that you can write SQL like this:
SELECT * FROM liveservername.databasename.dbo.tablename
Now when your scripts are run on the development server with the linked server back to itself they will work correctly pulling data from the development server and when the exact same scripts are run on the live server they will work normally.

Resources