Cassandra is not retrieving the correct integer value - cassandra

I am using cql 3.0.0
I have executed the query:
INSERT INTO emp (empID, deptID, first_name, last_name)
VALUES (104, 15, 'jane', 'smith')
On retrieving this record, I get the following values:
empid = h
deptid = (blank value)
first_name = 'jane'
last_name = 'smith'
On searching for it, I found that h is equivalent to utf-8 character 104. Also 15 in utf-8 is blank.
(Reference Link: http://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=dec&unicodeinhtml=dec )
I have set the column types to int during create table, but on retrieving I am not getting the int values.
How do I get the correct values to be retrieved. I do not want the utf-8 values.
Thanks
I am using cassandra 1.2.4
Below is my code written in phpcassa:
require_once(__DIR__.'/../lib/autoload.php');
use phpcassa\Connection\ConnectionPool;
use phpcassa\ColumnFamily;
use phpcassa\SystemManager;
use phpcassa\Schema\StrategyClass;
use cassandra\Compression;
use cassandra\ConsistencyLevel;
$pool = new ConnectionPool("prod",array('X.X.X.X','X.X.X.X'));
$raw = $pool->get();
$rows = $raw->client->set_cql_version("3.0.0");
$rows = $raw->client->execute_cql3_query('USE prod;', Compression::NONE, ConsistencyLevel::ONE );
$rows = $raw->client->execute_cql3_query('CREATE TABLE emp (
empID int,
deptID int,
first_name varchar,
last_name varchar,
PRIMARY KEY (empID, deptID));
', Compression::NONE, ConsistencyLevel::ONE );
$rows = $raw->client->execute_cql3_query('INSERT INTO emp (empID, deptID, first_name, last_name)
VALUES (104, 15, \'jane\', \'smith\');
', Compression::NONE, ConsistencyLevel::ONE );
$rows = $raw->client->execute_cql3_query('SELECT * FROM emp WHERE empID IN (2,104) ORDER BY deptID ASC;', Compression::NONE, ConsistencyLevel::ONE );
echo "<pre>";
print_r($rows);
echo "<pre>";
The output generated is:
cassandra\CqlRow Object
(
[key] =>
[columns] => Array
(
[0] => cassandra\Column Object
(
[name] => empid
[value] => h
[timestamp] =>
[ttl] =>
)
[1] => cassandra\Column Object
(
[name] => deptid
[value] =>
[timestamp] =>
[ttl] =>
)
[2] => cassandra\Column Object
(
[name] => first_name
[value] => jane
[timestamp] =>
[ttl] =>
)
[3] => cassandra\Column Object
(
[name] => last_name
[value] => smith
[timestamp] =>
[ttl] =>
)
)
)

Though a bit late answer, but I was desperately searching for the solution while writing my own cassandra-wrapper for Yii framework. I came up with something like the following class that eliminates the problem of incorrect binary to different data types in cassandra including integer types:
Yii::import('ext.phpcassa.autoload');
require_once('protected/extensions/phpcassa/autoload.php');
use phpcassa\Connection\ConnectionPool;
use phpcassa\ColumnFamily;
use phpcassa\ColumnSlice;
use phpcassa\SystemManager;
use phpcassa\Schema\StrategyClass;
use phpcassa\Schema\DataType;
class ACassandraConnection extends CApplicationComponent {
protected $_pool = null;
public $keyspace = null;
public $servers = null;
/**
* Establish connection to cassandra cluster
* #return object
*/
private function _get_raw() {
if ($this->_pool === null) {
$this->_pool = new ConnectionPool($this->keyspace, $this->servers);
}
return $this->_pool->get();
}
public function cql_query($query) {
$raw = $this->_get_raw();
$cql_result = $raw->client->execute_cql3_query($query, cassandra\Compression::NONE, cassandra\ConsistencyLevel::ONE);
$this->_pool->return_connection($raw);
return $cql_result;
}
public function cql_get_rows($cql_result) {
if ($cql_result->type == 1) {
$rows = array();
foreach ($cql_result->rows as $rowIndex => $cqlRow) {
$cols = array();
foreach ($cqlRow->columns as $colIndex => $column) {
$type = DataType::get_type_for($cql_result->schema->value_types[$column->name]);
$cols[$column->name] = $type->unpack($column->value);
}
$rows[] = $cols;
}
return $rows;
} else {
return null;
}
}
/**
* Perform garbage collection
*/
public function __destruct() {
if($this->_pool !== null) {
$this->_pool->close();
}
}
}

I will say please review your solution, i have tried exactly the same thing you described as your problem, but its working normal for me. Might be at the time of creation you have used utf-8 as their type.
Schema
CREATE COLUMNFAMILY test(empID int, deptID int, first_name text, last_name text, PRIMARY KEY(empID));
Insert
INSERT INTO emp (empID, deptID, first_name, last_name) VALUES (104, 15, 'jane', 'smith');
Retrieve
SELECT * FROM test ;
empid | deptid | first_name | last_name
-------+--------+------------+-----------
104 | 15 | jane | smith

Related

How to fix [Error: While query - conversion error from string "pending" ] when trying to insert a new record into firebird database?

I've created a table with the following schema:
CREATE TABLE orders (
id INTEGER NOT NULL PRIMARY KEY,
status VARCHAR(30) NOT NULL CHECK(status IN('ordered', 'paid', 'pending', 'complete')),
order_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
delivery_id INTEGER,
client_id INTEGER,
operator_id INTEGER,
FOREIGN KEY(delivery_id)
REFERENCES delivery_info(id) ON DELETE CASCADE,
FOREIGN KEY(client_id) REFERENCES client(id) ON DELETE CASCADE,
FOREIGN KEY(operator_id) REFERENCES operator(id)
);
However, when I'm trying to insert new data into the table using a node.js application, I get the following error:
Console output
Generated query looks okay to me:
INSERT INTO orders VALUES (793771, 'pending', '1612387572153', 590931, 3923, 0);
Application code:
class Order {
static DEFAULT_OPERATOR_ID = 0;
constructor(id, status, time, delivery, client,
operatorId = Order.DEFAULT_OPERATOR_ID)
{
this.id = id;
this.status = status;
this.time = time;
this.delivery = delivery;
this.client = client;
this.operatorId = operatorId
}
save() {
console.log(this);
const insertQuery = `
INSERT INTO orders
VALUES (${this.id}, '${this.status}', '${this.time}', ${this.delivery.id}, ${this.client.id}, ${this.operatorId});
`;
console.log(insertQuery);
dbConnection.query(insertQuery, (error, result) => {
if (error) throw error;
console.log('Inserted new order');
});
}
}
Issue is fixed when I specify the column list during insertion. Thanks, #Mark Rotteveel.

Cassandra insert after delete fails

In a specific case of deleting and reinserting rows to a table does not work as intended when replication factor is more than 1 (say 3).
I have tried using quorum for read as well as write and timestamp in the query with no success.
If the replication factor is set to 1, all works well. I have 5 nodes in my cluster.
Issue becomes visible when tried to read after the delete and insert operation. The read does not return rows that should have been inserted.
Could someone please share their thoughts on this?
Edit:
Following is what I have tried from code
Database create script:
DROP KEYSPACE IF EXISTS consistency_check;
CREATE KEYSPACE IF NOT EXISTS consistency_check WITH replication = {'class': 'NetworkTopologyStrategy', 'Cassandra': 3} AND durable_writes = true;
USE consistency_check;
CREATE TABLE IF NOT EXISTS resource (
id uuid,
col1 text,
col2 text,
col3 text,
col4 text,
PRIMARY KEY(id, col1)
);
C# Unit test code:
public class Resource
{
public Guid Id { get; set; }
public string Col1 { get; set; }
public string Col2 { get; set; }
public string Col3 { get; set; }
public string Col4 { get; set; }
}
public class MyMappings : Mappings
{
public MyMappings()
{
For<Resource>()
.TableName("resource")
.PartitionKey(u => u.Id)
.Column(u => u.Id, cm => cm.WithName("id"))
.Column(u => u.Col1, cm => cm.WithName("col1"))
.Column(u => u.Col2, cm => cm.WithName("col2"))
.Column(u => u.Col3, cm => cm.WithName("col3"))
.Column(u => u.Col4, cm => cm.WithName("col4"));
}
}
//Following test fails always
[TestMethod]
public async Task DeleteInsert()
{
var table = new Table<Resource>(_session);
_session.Execute("truncate resource");
for (int i = 0; i < 10; i++)
{
var id = Guid.NewGuid();
await table.Insert(new Resource { Id = id, Col1 = id.ToString(), Col2 = id.ToString(), Col3 = id.ToString(), Col4 = id.ToString() }).ExecuteAsync().ConfigureAwait(false);
}
var data = (await table.ExecuteAsync().ConfigureAwait(false)).ToList();
foreach (var datum in data)
{
await table.Where(e => e.Id == datum.Id).Delete().ExecuteAsync().ConfigureAwait(false);
}
foreach (var datum in data)
{
await table.Insert(datum).ExecuteAsync().ConfigureAwait(false);
}
var data1 = (await table.ExecuteAsync().ConfigureAwait(false)).ToList();
Console.WriteLine("data length: {0}", data.Count);
Console.WriteLine("data1 length: {0}", data1.Count);
Assert.IsTrue(data.Count == 10);
Assert.IsTrue(data1.Count == 10);
}
Where are you setting the consistency level? If you use quorum for reads and writes, you shouldn't get this problem.
Looks like your running the inserts and deletes asynchronously - so the delete could have run before the inserts. In the case the delete clause will not be met and not rows will be deleted.
I am not super familiar with the C# async/await construct so i might be missing something

Retrieving data from composite key via astyanax

I am very naive in cassandra & am using astyanax
CREATE TABLE employees (empID int, deptID int, first_name varchar,
last_name varchar, PRIMARY KEY (empID, deptID));
i want to get the values of query:
select * from employees where empID =2 and deptID = 800;
public void read(Integer empID, String deptID) {
OperationResult<ColumnList<String>> result;
try {
columnFamilies = ColumnFamily.newColumnFamily("employees", IntegerSerializer.get(), StringSerializer.get());
result = keyspace.prepareQuery(columnFamilies).getKey(empID).execute();
ColumnList<String> cols = result.getResult();
//Other stuff
}
how should i achieve this
As far as I can find, there isn't a super clean way to do this. You have to do it by executing a cql query and then iterating through the rows. This code is taken from the astynax examples file
public void read(int empId) {
logger.debug("read()");
try {
OperationResult<CqlResult<Integer, String>> result
= keyspace.prepareQuery(EMP_CF)
.withCql(String.format("SELECT * FROM %s WHERE %s=%d;", EMP_CF_NAME, COL_NAME_EMPID, empId))
.execute();
for (Row<Integer, String> row : result.getResult().getRows()) {
logger.debug("row: "+row.getKey()+","+row); // why is rowKey null?
ColumnList<String> cols = row.getColumns();
logger.debug("emp");
logger.debug("- emp id: "+cols.getIntegerValue(COL_NAME_EMPID, null));
logger.debug("- dept: "+cols.getIntegerValue(COL_NAME_DEPTID, null));
logger.debug("- firstName: "+cols.getStringValue(COL_NAME_FIRST_NAME, null));
logger.debug("- lastName: "+cols.getStringValue(COL_NAME_LAST_NAME, null));
}
} catch (ConnectionException e) {
logger.error("failed to read from C*", e);
throw new RuntimeException("failed to read from C*", e);
}
}
You just have to tune the cql query to return what you want. This is a bit frustrating because according to the documentation, you can do
Column<String> result = keyspace.prepareQuery(CF_COUNTER1)
.getKey(rowKey)
.getColumn("Column1")
.execute().getResult();
Long counterValue = result.getLongValue();
However I don't know what rowkey is. I've posted a question about what rowkey can be. Hopefully that will help

SubSonic How to provide a column name in a generic method

Using SubSonic3, I have this generic method (thanks to linq guy, James Curran):
public List<T> GetFromList<T>( List<Guid> _IDs,
Func<T, Guid> GetID,
Func<IQueryable<T>> GetAll )
where T : class, IActiveRecord
{
List<T> rc = null;
var Results =
from item in GetAll( )
where ( _IDs as IEnumerable<Guid> ).Contains( GetID( item ) )
select item;
rc = Results.ToList<T>( );
return rc;
}
It is called with something like
List<Job> jresults = GetFromList( IDList,
item => item.JobID,
( ) => Job.All( ) );
Where IDList is a List of guids that are keys to the table.
When not generic, the linq looks like this and works perfectly. I was quite impressed that SubSonic's linq provider could take this code and turn it into SELECT * FROM Job WHERE JobID IN (a, b, c):
var Results =
from item in Job.All( )
where ( _IDs as IEnumerable<Guid> ).Contains( item.JobID )
select item;
I want to be able to call this method on tables other than Job, with keys other than JobID. The GetAll Func works because it returns the same IQueryable that Job.All( ) does, but GetID throws a run-time exception, "LINQ expression node of type Invoke is not supported". GetID returns a value, but what I really need from it is something that Contains( item.JobID) would recognize as a column name and that the "where" syntax would accept. (I don't show it here, but I have the same problem with orderby.)
Is that possible, with what you know of SubSonic3?
My solution was to pass in the expression that Where needed:
public List<T> GetFromList( List<Guid> _IDs,
Func<IQueryable<T>> GetAll,
Expression<Func<T, bool>> _where )
where T : class, U, IActiveRecord
{
List<T> rc = new List<T>( );
if ( 0 < _IDs.Count )
{
if ( MAX_ITEMS > _IDs.Count )
{
var Results = GetAll( ).Where( _where );
rc = Results.ToList( );
}
else
{
var Results =
from id in _IDs
join item in GetAll( ) on id equals item.KeyValue( )
select item;
rc = Results.ToList( );
}
}
return rc;
}
called by
rc = GetFromList(
IDList,
( ) => Job.All( ),
( item => ( IDList as IEnumerable<Guid> ).Contains( item.JobID ) ) );

Reengineer SQL into SubSonic LINQ

I have 11 records in the Menu table, only 1 with a PageID set however if I use
var test = Menu.All().Where(
x => x.WebPages.Any(
pages => pages.Roles.Contains(Roles.GetRolesForUser()[0])
I get 11 records as the SQL run is this
SELECT [t0].[CategoryID], [t0].[CreatedBy], [t0].[CreatedOn],
[t0].[ID], [t0].[ImageID], [t0].[ImageIDHover], [t0].[Locale],
[t0].[ModifiedBy], [t0].[ModifiedOn], [t0].[OrderID], [t0].[PageID],
[t0].[ParentID], [t0].[Title], [t0].[URL], [t0].[Visible]
FROM [dbo].[Menu] AS t0
WHERE EXISTS(
SELECT NULL
FROM [dbo].[WebPage] AS t1
WHERE ([t1].[Roles] LIKE '%' + 'User' + '%')
)
If I run this I get the 1 record
var test = Menu.All().Where(
x => x.WebPages.Any(
pages => pages.Roles.Contains(
Roles.GetRolesForUser()[0]) && pages.ID == x.PageID));
The SQL for this is
SELECT [t0].[CategoryID], [t0].[CreatedBy], [t0].[CreatedOn],
[t0].[ID], [t0].[ImageID], [t0].[ImageIDHover], [t0].[Locale],
[t0].[ModifiedBy], [t0].[ModifiedOn], [t0].[OrderID], [t0].[PageID],
[t0].[ParentID], [t0].[Title], [t0].[URL], [t0].[Visible]
FROM [dbo].[Menu] AS t0
WHERE EXISTS (
SELECT NULL
FROM [dbo].[WebPage] AS t1
WHERE (([t1].[Roles] LIKE '%' + 'User' + '%') AND
([t1].[ID] = [t0].[PageID]))
)
The problem with Any() is that in the SQL as long as one record exits, doesn't matter which record it will return data.
I think effectively I am wanting an UNION SQL like below but I don't know how I re-engineer that into C#/Subsonic
select m.* from menu m where pageid is null
union
select m.* from menu m
join webpage p
on p.id = m.pageid
where p.roles like '%User%'
I want to return all menu records and for those with a PageID set that the corresponding WebPage has the user's role in it. If the user's role is not in the WebPage then I don't want to see it in my results.
Here are my cutodwn classes that Subsonic generates
public partial class Menu: IActiveRecord
{
public int ID {get; set;}
public int CategoryID {get;set;}
public bool Visible {get;set;}
public int PageID {get;set;}
public IQueryable<WebPage> WebPages
{
get
{
var repo=NorthCadburyWebsite.Models.WebPage.GetRepo();
return from items in repo.GetAll()
where items.ID == _PageID
select items;
}
}
}
public partial class WebPage: IActiveRecord
{
public int ID {get;set;}
public string Roles {get;set;}
}
It sure seems like you could just add an alternative test to the where clause to do this.
var test = Menu.All()
.Where(x => x.PageID == null
|| x.WebPages
.Any(pages => pages.Roles.Contains(Roles.GetRolesForUser()[0])
&& pages.ID == x.PageID));
EDIT:
Try using the the Intersect method to see if there is an overlap between the roles in the DB and the roles for the user.
var test = Menu.All()
.Where(x => x.PageID == null
|| x.WebPages
.Any(pages => pages.Roles.Intersect(Roles.GetRolesForUser().Split(','))
&& pages.ID == x.PageID));

Resources