How to insert NULL/empty string in encrypted column - Always Encrypted - sql-server

I have encrypted existing data using the SQL Server 2016 always encrypt method, one of column we have is NULLABLE but while insert from screen its not accepting either NULL or empty String. how to make it work if encrypted column is not mandatory on screen?

The error that you are seeing is incorrect, please ensure that you are passing the parameter correctly. Here is some sample code on how to do so.
Schema:
CREATE TABLE [dbo].[SO](
[ssn] [nvarchar](9) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL
)
GO
CREATE PROCEDURE dbo.insertSP #ssn nvarchar(9)
AS
INSERT INTO [dbo].[SO] ([SSN]) VALUES (#SSN);
GO
C# code:
SqlConnectionStringBuilder strbldr = new SqlConnectionStringBuilder();
strbldr.DataSource = ".";
strbldr.InitialCatalog = #"exptdb";
strbldr.IntegratedSecurity = true;
strbldr.ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Enabled;
string ssn = "";
using (var conn = new SqlConnection(strbldr.ConnectionString))
using (var command = conn.CreateCommand()) {
command.CommandType = CommandType.StoredProcedure;
command.CommandText = #"dbo.insertSP";
SqlParameter paramSSN = command.CreateParameter();
paramSSN.ParameterName = "#ssn";
paramSSN.SqlDbType = SqlDbType.NVarChar;
paramSSN.Direction = ParameterDirection.Input;
paramSSN.Value = ssn;
paramSSN.Size = 9;
command.Parameters.Add(paramSSN);
conn.Open();
command.ExecuteNonQuery();
}
Note, that in the scenario mentioned above, if
string ssn = "";
then the query succeeds, however if
string ssn = null;
you should see a failure on execution
Additional information: Procedure or function 'insertSP' expects
parameter '#ssn', which was not supplied.
This failure will occur even when ssn column is plaintext
You can insert null value in the encrypted column as follows, since null values are not encrypted:
using (var conn = new SqlConnection(strbldr.ConnectionString))
using (var command = conn.CreateCommand()) {
command.CommandText = #"INSERT INTO [dbo].[SO] ([SSN]) VALUES (null)";
conn.Open();
command.ExecuteNonQuery();
}

Related

Translate result of DbDataReader to database model in ASP.NET MVC 4, coming from a stored procedure using ADO.NET [duplicate]

This question already has answers here:
How do I return multiple result sets with SqlCommand?
(7 answers)
Closed 1 year ago.
I have a user-defined stored procedure which returns multiple actual tables as result set:
CREATE PROCEDURE uspDemo
(#UserID BIGINT = 0,
#IsAdmin BIT = 0,
#Title VARCHAR(120) = '')
AS
BEGIN
------Retrieve Posts------
SELECT *
FROM tblPost AS MP
INNER JOIN tblUserProfile AS UP ON UP.ID = MP.UserID
WHERE UP.ID = #UserID
AND ((#IsAdmin = 0 AND MP.IsDeleted = 0 AND MP.IsApproved = 1)
OR (#IsAdmin = 1 OR MP.IsDeleted = 0 OR MP.IsApproved = 1))
----- Retrieve Tags------
SELECT *
FROM tblTagMasters AS MT
INNER JOIN tblPostTags AS MP ON MT.TagID = MP.TagID
--------Retrieve User likes-----
SELECT *
FROM tblUserLikes AS UV
INNER JOIN tblPost AS MP ON MP.PostId = UV.PostId
END
How to translate in ASP.NET MVC? Please help me.
Basically, you need something like this:
// define connection string and command for your query
string connectionString = "....."; // typically load from config
string storedProcedureName = "dbo.uspDemo";
// put your disposable ADO.NET objects into proper "using ()" blocks
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(storedProcedureName, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// define the parameters
cmd.Parameters.Add("#UserID", SqlDbType.BigInt).Value = .....;
cmd.Parameters.Add("#IsAdmin", SqlDbType.Bit).Value = .....;
cmd.Parameters.Add("#Title", SqlDbType.VarChar, 120).Value = ".....";
// open connection
conn.Open();
// execute stored procedure to get the data reader
using (SqlDataReader reader = cmd.ExecuteReader())
{
// read the first set of data returned
while (reader.Read())
{
// read the values, construct an object from it, store the object into a list or something
}
// get the next set of result data
reader.NextResult();
// read the second set of data returned
while (reader.Read())
{
// read the values, construct an object from it, store the object into a list or something
}
// get the next set of result data
reader.NextResult();
// read the third set of data returned
while (reader.Read())
{
// read the values, construct an object from it, store the object into a list or something
}
}
conn.Close();
}
I leave the remaining details up to you - do some research!

SQL Server stored procedure output parameter and return data from select

I have a stored procedure in SQL Server 2012:
CREATE PROCEDURE GetImmediateManager
#managerID INT OUTPUT
AS
BEGIN
SET #managerID = 6;
SELECT *
FROM Roles;
END
When I remove select * from Roles; the output value (#managerID) is returned correctly to my C# code. But when the procedure has select * .., the value returned by output parameter is null.
How can I return select and output at the same time?
In C# my code looks like this:
dbContext.Database.OpenConnection();
DbCommand cmd = dbContext.Database.GetDbConnection().CreateCommand();
cmd.CommandTimeout = 15;
cmd.CommandText = "GetImmediateManager";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
var rowsCountParam = new SqlParameter("#managerID", System.Data.SqlDbType.Int);
rowsCountParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(rowsCountParam);
using (var reader = cmd.ExecuteReader())
{
tasks = reader.MapToList<TaskManagerTask>();
//rowsCount = (int)rowsCountParam.Value;
}
The simplistic answer is to add #managerID to your select statement
For a less simplistic perhaps the following, I changed the names a bit to reflect the use, get parameter after it closes.
var managerIDParam = new SqlParameter("#managerID", System.Data.SqlDbType.Int);
managerIDParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(managerIDParam);
using (var reader = cmd.ExecuteReader())
{
tasks = reader.MapToList<TaskManagerTask>();
}
int managerIDParamUsed = (int)managerIDParam.Value;

ADO.NET - Trouble Getting Output Parameter

My DBA created the following Stored Proc which he insists works fine when called in SQL Server:
CREATE procedure [dbo].[GetParentID]
#SSHIP_AppID as varchar(50),
#ParentID as varchar(150) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #ParentID = a.iBuild_GUID
FROM dbo.XRef_iBuild_SSHIP as a
WHERE a.SSHIP_appId = #SSHIP_AppID
AND a.SSHIP_appId <> ''
END
I have created the following ADO.NET Wrapper but I am having trouble getting the output parameter. I keep getting back "OUTPUT" as its value:
private string GetParentId(string appId)
{
var connection = new SqlConnection();
string parentId = String.Empty;
try
{
connection.ConnectionString = "...)
var command = new SqlCommand("GetParentId", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#SSHIP_AppID", appId));
command.Parameters.Add(new SqlParameter("#ParentID", ParameterDirection.Output));
connection.Open();
command.ExecuteNonQuery();
parentId = (command.Parameters["#ParentId"].Value).ToString();
}
catch (Exception ex)
{
LogError(appId, ex.ToString(), "Interface12 - Cannot get ParentId", null, 0);
}
finally
{
connection.Close();
}
return parentId;
}
}
What am I doing wrong?
In new SqlParameter("#ParentID", ParameterDirection.Output) the 2nd argument is treated as the object value argument and apparently converted to a string.
(This implicit conversion is, in my opinion, a design flaw in ADO.NET. It should throw an exception for any unknown input type.).
Choose a better overload.

flex local database lastInsertId = 0

var insertReq:SQLStatement = new SQLStatement();
insertReq.addEventListener(SQLErrorEvent.ERROR, dbErrorHandler);
insertReq.sqlConnection = conn;
insertReq.text = "INSERT INTO table1 (inputTime) VALUES (DATETIME('now'))";
insertReq.execute();
insertReq.text = "SELECT last_insert_rowid() as ID";
insertReq.execute();
var lastInsertId:int = insertReq.getResult().data[0].id;
trace(lastInsertId);
I made a local database and i am trying to insert some data but
I get lastInsertId zero?! Where I mess up things!?
You don't need to make additional execution of query for retrieving last inserted row's id.There is a built-in .lastInsertRowID property of SQLResult class for that purpose. Just use it like this:
var insertReq:SQLStatement = new SQLStatement();
insertReq.addEventListener(SQLErrorEvent.ERROR, dbErrorHandler);
insertReq.sqlConnection = conn;
insertReq.text = "INSERT INTO table1 (inputTime) VALUES (DATETIME('now'))";
insertReq.execute();
var lastInsertId:int = insertReq.getResult().lastInsertRowID;
trace(lastInsertId);

How to save byte[] using a procedure?

This stored procedure does not save the data, it seems to be a problem with the VARBINARY. I am passing a byte[] to it, but then it doesn't work. If I send this parameter as NULL it works.
I'm calling the procedure with the following code:
public Community AddCommunity(string name, string description, byte[] picture, User owner, int? venue, int communityID)
{
using (var database = new Database())
{
return database.Scope.GetSqlQuery<Community>("QP_AddCommunity ?, ?, ?, ?, ?, ?", "VARCHAR Name, VARCHAR Description, VARBINARY Picture, INTEGER Owner, INTEGER Venue, INTEGER ID").GetResult(name, description, picture, owner.ID, venue, communityID);
}
}
The procedure is the following:
CREATE PROCEDURE [dbo].[QP_AddCommunity]
#Name VARCHAR(120),
#Description VARCHAR(MAX),
#Picture VARBINARY(MAX),
#Owner INTEGER,
#Venue INTEGER,
#ID INTEGER
AS
BEGIN
SET NOCOUNT ON;
IF(SELECT COUNT(*) FROM QT_Community WHERE ID = #ID) = 0
INSERT INTO QT_Community(Name, [Description], Picture, [Owner], Venue) VALUES(#Name, #Description, #Picture, #Owner, #Venue);
ELSE
UPDATE QT_Community SET Name = #Name, [Description] = #Description, Picture = #Picture, [Owner] = #Owner, Venue = #Venue WHERE ID = #ID;
SELECT * FROM QT_Community WHERE ID = ##IDENTITY;
END
What's wrong with this code? Isn't VARBINARY a byte[] ?
This code works when executing on SQL Server Management Studio.
DECLARE #X varbinary(20)
Set #X = CAST('Testing' As varbinary(20))
EXECUTE [QP_AddCommunity] 'aaaaa', 'descricao', #X, 216, NULL, 0;
But when calling from the GetSqlQuery method with something on the byte[] the transaction says it's not active and not dirty. BUT if the byte[] is null it works as it should.
i found that it is impossible as this answer shows
Hello gaurav, currently our
GetSqlQuery method cannot operate
properly with parameters of type
LongVarBinary or VarBinary, thus
making it impossible for the stored
procedure to work as expected. We are
aware of this problem and we are
working on fixing it. As a work around
you should try and use Linq to achieve
your goal. Greetings, Petar the
Telerik team
Accordingly to this table it seems either BLOB, BINARY, VARBINARY would be valid types for [] of primitive type.
You could try to ask on their forums, maybe someone will be able to help you.
Try using the .WRITE method. On your INSERT, insert 0x for Picture, then update independently.
UPDATE QT_Community
SET Picture.Write (#Picture, 0, DATALENGTH(Picture))
WHERE ID = #ID
Example (Ado.Net):
byte[] ba = UlongsToBytes(ul);
try
{
string source = #"packet size=4096;integrated security=SSPI;data source=MyPC\MyNamedInstance;persist security info=False;initial catalog=Sandbox";
SqlConnection conn = new SqlConnection(source);
conn.Open();
SqlCommand a = new SqlCommand("INSERT BigintsTarget(bi) SELECT * FROM dbo.ParseImageIntoBIGINTs(#BIGINTs)", conn);
a.CommandType = System.Data.CommandType.Text;
a.Parameters.Add(new SqlParameter("#BIGINTs", System.Data.SqlDbType.Image,2147483647));
for(int q=0; q<10; q++)
{
a.Parameters[0].Value = ba;
int res = a.ExecuteNonQuery();
}
d2 = DateTime.Now;
SqlCommand b = new SqlCommand("INSERT BigintsTarget1(bi) SELECT * FROM dbo.ParseVarcharMAXIntoBIGINTs(#BIGINTs)", conn);
b.CommandType = System.Data.CommandType.Text;
b.Parameters.Add(new SqlParameter("#BIGINTs", System.Data.SqlDbType.VarChar,2147483647));
for(int q=0; q<10; q++)
{
b.Parameters[0].Value = sss;
int res = b.ExecuteNonQuery();
}
//b.ExecuteNonQuery();
conn.Close();
}
catch(Exception ex)
{
string s = ex.Message;
int t=0;
t++;
}
}

Resources