We have a table in cassandra with below structure:
cities_in_state(state TEXT, zip TEXT, cities SET<TEXT>, PRIMARY KEY ((zip,
state)))
I need to upsert the value of cities for the state with the java driver,
Have this code:
BoundStatement bound = session().prepare("UPDATE cities_in_state SET cities
= cities + ? WHERE zip = ? and state = ?").bind();
bound.setSet(1, cities);
bound.setString(2, "ZIP1");
bound.setString(3, "state1");
which is giving error like "HashSet can not be cast to String"
And i should always need to add more cities to the existing cities.
So how would i append the set column in cassandra with bound parameters.
Following piece of code works just fine:
PreparedStatement prepared = session.prepare("UPDATE test.st SET cities = cities + ? WHERE zip = ? and state = ?");
BoundStatement bound = prepared.bind(Collections.singleton("t2"), "2", "1");
session.execute(bound);
Your problem is that you're starting counting with 1, while the Java driver uses 0-based indexes. Following piece of code works just find if I decrease every index by 1:
BoundStatement bound2 = prepared.bind();
bound2.setSet(0, Collections.singleton("t3"));
bound2.setString(1, "2");
bound2.setString(2, "1");
session.execute(bound2);
Related
I am trying to fetch all the data from my dynamodb table but unable to get as all the methods for Query / Scan operates with input parameter. so i tried getting all the rows which having primary key greater than 0.
var table = Table.LoadTable(client,Utilities.Utility.EmployeeTable);
ScanFilter filter = new ScanFilter();
filter.AddCondition("iemp_id", ScanOperator.GreaterThan, 0);
ScanOperationConfig config = new ScanOperationConfig()
{
Filter = filter,
// Optional parameters.
Select = SelectValues.SpecificAttributes,
AttributesToGet = new List<string> { "iemp_id", "demp_salary", "semp_name" }
//ConsistentRead = true
};
Search search = table.Scan(config);`
Here i am getting search.Matches = 0 where it should return data from my table.
You have only two options
1.Query : You need to supply Partition Key(mandatory) and optionally Range key.
2.Scan: Full scan of the table with out Partition key/Range Key.
In your case you will have to do full scan of the table.
DynamoDBQScanExpression scanExpression = new DynamoDBScanExpression();
scanExpression .withFilterExpression(filterexpression)
.withExpressionAttributeValues(expression values);
I would like to encrypt an existing database column with always encrypted. My project is a ASP.NET project using code first and database is SQL Server. The database has already data. I created a migration to achieve my goal.
First I tried to alter the column type, using the following.
ALTER TABLE [dbo].[TestDecrypted] ALTER COLUMN [FloatCol] [float] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL
I got the following error.
Operand type clash: float is incompatible with float encrypted with (encryption_type = 'RANDOMIZED', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'TestEncrypt')
Then I decided to created another column and migrate the data.
ALTER TABLE [dbo].[TestDecrypted] ADD [FloatCol2] [float] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = [FloatCol]
And I got the same error.
After I looked at this, I noticed that it is possible to insert data like the following
DECLARE #floatCol FLOAT = 1.1
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = #floatCol
But if I try to obtain the value from my existing column, it fails.
DECLARE #floatCol FLOAT = (SELECT TOP 1 FloatCol FROM TestDecrypted)
UPDATE [dbo].[TestDecrypted] SET FloatCol2 = #floatCol
The error follows.
Encryption scheme mismatch for columns/variables '#floatCol'. The encryption scheme for the columns/variables is (encryption_type = 'PLAINTEXT') and the expression near line '4' expects it to be (encryption_type = 'RANDOMIZED', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'TestEncrypt').
Does anyone knows how can I achieve my goal?
Update 1
#Nikhil-Vithlani-Microsoft did some interesting suggestions.
Always Encrypted Wizard in SSMS - I would like to achieve my goal with code first migrations, so this idea does not fit.
SqlBulkCopy - It does not work inside migrations, because the new column will only exist after all 'Up' method is run. Therefore we cannot insert data into this column in this way inside this method.
Anyway, his suggestions drove me to another attempt: obtain the decrypted values and update the encrypted column with them.
var values = new Dictionary<Guid, double>();
var connectionString = ConfigurationManager.ConnectionStrings["MainDb"].ConnectionString;
using (var sourceConnection = new SqlConnection(connectionString))
{
var myCommand = new SqlCommand("SELECT * FROM dbo.TestDecrypted", sourceConnection);
sourceConnection.Open();
using (var reader = myCommand.ExecuteReader())
{
while (reader.Read())
{
values.Add((Guid)reader["Id"], (double)reader["FloatCol"]);
}
}
}
Sql("ALTER TABLE [dbo].[TestDecrypted] ADD [FloatCol2] [float] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL");
foreach (var valuePair in values)
{
// The error occurs here
Sql($#"DECLARE #value FLOAT = {valuePair.Value}
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = #value WHERE Id = '{valuePair.Key}'");
}
In fact, I did not try to create another column and to migrate the data, as mentioned in an example above. I tried it only on SSMS.
And now I got a different error.
Transaction (Process ID 57) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
I tried to do it without encrypting the new column, and it worked properly.
Any idea why this error occurs?
You will have to do the always encrypted related migration outside of entity framework. This blog should help
https://blogs.msdn.microsoft.com/sqlsecurity/2015/08/27/using-always-encrypted-with-entity-framework-6/
If you want to encrypt an existing column, you can use Always Encrypted Wizard in SSMS, or use this article that explains how to migrate existing data.
Also, please note that doing bulk inserts through a C# (.NET 4.6.1+ client) app is supported.
You can do this in c# using SqlBulkCopy specifically using SqlBulkCopy.WriteToServer(IDataReader) Method.
Create a new table (encryptedTable) with the same schema as that of your plaintext table (unencryptedTable) but with the encryption turned on for the desired columns.
Do select * from unencryptedTable to load the data in a SqlDataReader then use SqlBulkCopy to load it to the encryptedTable using SqlBulkCopy.WriteToServer(IDataReader) Method
For example,
Plaintext Table
CREATE TABLE [dbo].[Patients](
[PatientId] [int] IDENTITY(1,1),
[SSN] [char](11) NOT NULL)
Encrypted Table
CREATE TABLE [dbo].[Patients](
[PatientId] [int] IDENTITY(1,1),
[SSN] [char](11) COLLATE Latin1_General_BIN2
ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC,
ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256',
COLUMN_ENCRYPTION_KEY = CEK1) NOT NULL)
As for why your method does not work,
when you use parameterization for always encrypted, the right hand side (RHS) of the declare statement needs to be a literal. Because the driver will identify the literal and encrypt it for you. So, the following will not work, since RHS is a sql expression and cannot be encrypted by the driver
DECLARE #floatCol FLOAT = (SELECT TOP 1 FloatCol FROM TestDecrypted)
UPDATE [dbo].[TestDecrypted] SET FloatCol2 = #floatCol
Update:
The following code will not work because parameterization for Always Encrypted only applies to SSMS
foreach (var valuePair in values)
{
// The error occurs here
Sql($#"DECLARE #value FLOAT = {valuePair.Value}
UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = #value WHERE Id = '{valuePair.Key}'");
}
However, if you rewrite your code as follows, that should work
foreach (var valuePair in values)
{
SqlCommand cmd = _sqlconn.CreateCommand();
cmd.CommandText = #"UPDATE [dbo].[TestDecrypted] SET [FloatCol2] = #FloatVar WHERE Id = '{valuePair.Key}'");";
SqlParameter paramFloat = cmd.CreateParameter();
paramFloat.ParameterName = #"#FloatVar";
paramFloat.DbType = SqlDbType.Float;
paramFloat.Direction = ParameterDirection.Input;
paramFloat.Value = floatValue;
cmd.Parameters.Add(paramFloat);
cmd.ExecuteNonQuery();
}
Hope that helps, if you have additional question, please leave them in the comments.
String SQL = "INSERT INTO Employee (name, age, salary) VALUES (:name,:age,:salary)";
Map namedParameters = new HashMap();
namedParameters.put("name", name);
namedParameters.put("age", age);
namedParameters.put("salary", salary);
namedParameterJdbcTemplate.update(SQL, namedParameters);
String SQL = "UPDATE Employee SET age = :age WHERE empid = :empid";
SqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("age", age);
namedParameters.addValue("empid", empid);
namedParameterJdbcTemplate.update(SQL, namedParameters);
Seems both Map and SqlParameterSource are same. But why did API developers added these API's ? Is there any particular scenario to use Map or SqlParameterSource which makes execution faster? Please explain me clearly. Thanks in advance.
Using a Map is fine for simple cases, but there are two benefits to using SqlParamaterSource over a Map.
The first is simply the builder pattern allowing you to add multiple values inline (namedParameters.addValue().addValue().addValue() etc).
The second is more powerful. The jdbcTemplate will auto-determine the sqlType of your map values while the SqlParamaterSource allows you to explicitly use the sqlType of your choice. This can be an issue depending on your database, indexes and parameters.
An example would be Integers and Longs with an Oracle database. The jdbc template will add these objects to your query with surrounding quotes '' making them effectively strings in your database query. If you have a number in your database with leading 0's it will not be found because '0XXXX' will not match 'XXXX'. If you pass in the right sqlType, the jdbc template will do a number comparison without quotes so XXXX will equal XXXX.
When my place holder values were of different datatypes, this (MapSqlParameterSource) really helped me:
String SQL = "UPDATE Employee SET joindate = :joinDate WHERE empid = :empid";
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("date", joinDate, Types.Date);
namedParameters.addValue("empid", empid, Types.Integer);
namedParameterJdbcTemplate.update(SQL, namedParameters);
I'm creating a game and when it finishes it stores it in a database (code below that adds it)
-- open SQLite database, if it doesn't exist, create database
local path = system.pathForFile("leaderboards.sqlite", system.DocumentsDirectory)
db = sqlite3.open( path )
print(path)
-- setup the table if it doesn't exist
local tablesetup = "CREATE TABLE IF NOT EXISTS leaderboards (id INTEGER PRIMARY KEY, score INDEXED);"
db:exec( tablesetup )
print(tablesetup)
-- save student data to database
local tablefill = "INSERT INTO leaderboards VALUES (NULL,'" .. score .. "');"
print(tablefill)
db:exec( tablefill )
-- close database
db:close()
print("db closed")
Then I want at the top of the screen to display the highest score so this is my display function
local function highScore()
-- open database
local path = system.pathForFile("leaderboards.sqlite", system.DocumentsDirectory)
db = sqlite3.open( path )
print(path)
--print all the table contents
local sql = "SELECT MAX(score) FROM leaderboards"
local val = db:exec(sql)
local t = display.newText("Best: "..val, 300, -20, nil, 28)
print(val)
t:setTextColor(255,255,255)
db:close()
end
Right now on the screen it is just saying 0 and not the high score or any screen. The values are being entered in the database but my sql statement isn't displaying it.
The simplest method is
local val
for x in db:urows "SELECT MAX(score) FROM leaderboards" do val = x end
Or
local sql = "SELECT MAX(score) FROM leaderboards"
for val in db:urows(sql)
local t = display.newText("Best: "..val, 300, -20, nil, 28)
print(val)
t:setTextColor(255,255,255)
end
See the urows documentation here.
From the docs:
db:exec
db:exec(sql[,func[,udata]])
db:execute(sql[,func[,udata]])
Compiles and executes the SQL statement(s) given in string sql. The
statements are simply executed one after the other and not stored. The
function returns sqlite3.OK on success or else a numerical error code
(see Numerical error and result codes).
If one or more of the SQL statements are queries, then the callback
function specified in func is invoked once for each row of the query
result (if func is nil, no callback is invoked). The callback receives
four arguments: udata (the third parameter of the db:exec() call), the
number of columns in the row, a table with the column values and
another table with the column names. The callback function should
return 0. If the callback returns a non-zero value then the query is
aborted, all subsequent SQL statements are skipped and db:exec()
returns sqlite3.ABORT.
In your code, the local val receives sqlite3.OK, which probably equals 0. You need to provide a callback function to receive row data, for example
local function maxscorecb(udata, ncols, colvals, colnames)
--Assuming that it's always one row and value
udata[1] = colvals[1]
return 0
end
--print all the table contents
local sql = "SELECT MAX(score) FROM leaderboards"
local scoretab = {}
local val = db:exec(sql, maxscorecb, scoretab)
local t = display.newText("Best: "..scoretab[1], 300, -20, nil, 28)
print(val)
t:setTextColor(255,255,255)
db:close()
P.S. Haven't tested it, just based on reading the docs.
I want to insert a record and then update the record according to scope_identity of inserted record.
I'm doing this but when I want to update my record encounter an error.
WorkshopDataContext Dac = new WorkshopDataContext();
Dac.Connection.ConnectionString = "Data Source=dpsxxx-xxx;Initial Catalog=kar;User ID=sa;Password=xxxx";
Tbl_workshop Workshop = new Tbl_workshop();
Workshop.StateCode = Bodu.BduStateCode;
Workshop.CityCode = Bodu.BduCityCode;
Workshop.Co_workshop=12222;
Dac.Tbl_workshop.InsertOnSubmit(Workshop);
Dac.SubmitChanges();
Int64 Scope = Workshop.id;
var query = from record in Dac.Tbl_workshop where record.id == Scope select record;
query.First().co_Workshop = Scope;
Dac.SubmitChanges();
and this is the error:
Value of member 'co_Workshop' of an object of type 'Tbl_Workshop' changed.
A member defining the identity of the object cannot be changed.
Consider adding a new object with new identity and deleting the existing one instead.
If you have properly configured your Linq-to-SQL model to reflect the IDENTITY column in your table, you should have the new value available right after .SubmitChanges():
Tbl_workshop Workshop = new Tbl_workshop();
Workshop.StateCode = Bodu.BduStateCode;
Workshop.CityCode = Bodu.BduCityCode;
Workshop.Co_workshop=12222;
Dac.Tbl_workshop.InsertOnSubmit(Workshop);
Dac.SubmitChanges();
Int64 workshopID = Workshop.Id; // you should get new ID value here - automatically!!
You don't need to do anything like reading out that new value from SQL Server or anything - Linq-to-SQL should automagically update your Workshop object with the proper value.
Update: to update your co_workshop value to the value given by the IDENTITY ID, do this (just set the value of co_workshop and save again - that's really all there is):
Dac.Tbl_workshop.InsertOnSubmit(Workshop);
Dac.SubmitChanges();
Int64 workshopID = Workshop.Id; // you should get new ID value here - automatically!!
Workshop.Co_workshop = workshopID;
Dac.SubmitChanges();
As it said on the error, you can't change co_Workshop because its identity (auto increment value). To freely edit it, you need to edit the database and remove this setting.
What probably is happening is that both id and co_Workshop are set as identity. Just disable the identity checkbox from co_Workshop.