I'm using prepared statements in the Cassandra Datastax C++ Driver. How do I bind an integer-value to the "USING TTL ?" part of a prepared statement?
My statement would be something like
INSERT INTO table (column1, column2, column3) VALUES (?, ?, ?) USING TTL ?
In other words, If I'm using the position to bind to TTL, what is its position? (In this example, is it 4?) If I'm using bind by column name, what is its column name?
It looks like this can be done in CQL, but I couldn't find any documentation about the C++ driver API for doing this.
In Cassandra CQL 2.0 you can have:
Cassandra 1.2 doesn't allow you to use a bind marker for the TIMESTAMP and TTL properties of update statements, nor for the LIMIT property of SELECT statements. This is now fixed and you can for instance prepare statements like:
SELECT * FROM myTable LIMIT ?;
UPDATE myTable USING TTL ? SET v = 2 WHERE k = 'foo';
See their blog for more.
Edit:
I found this pdf and it tells you more:
Bound parameters:
The driver supports two kinds of bound parameters: by marker and by name.
Binding parameters
The ? marker is used to denote the bind variables in a query string. This is used for both regular
and prepared parameterized queries. In addition to adding the bind marker to your query string,
your application must also provide the number of bind variables to
cass_statement_new() when constructing a new statement. If a query doesn’t require any bind variables then 0 can be used. The cass_statement_bind_*()
functions are then used to bind values to the statement’s variables.
Bind variables can be bound by the marker index or by name.
Bind by marker index example
CassString query = cass_string_init("SELECT * FROM table1 WHERE column1
= ?");
/* Create a statement with a single parameter */
CassStatement* statement = cass_statement_new(query, 1);
cass_statement_bind_string(statement, 0, cass_string_init("abc"));
/* Execute statement */
cass_statement_free(statement);
Bind by marker name example
Variables can only be bound by name for prepared statements. This limitation exists because query
metadata provided by Cassandra is required to map the variable name to the variable’s marker index.
/* Prepare statement */
/* The prepared query allocates the correct number of parameters
automatically */
CassStatement* statement = cass_prepared_bind(prepared);
/* The parameter can now be bound by name */
cass_statement_bind_string_by_name(statement, "column1",
cass_string_init("abc"));
/* Execute statement */
cass_statement_free(statement);
To answer your question you can use bind by index (works at least for sure):
CassString query = cass_string_init("INSERT INTO table (column1, column2, column3) VALUES (?, ?, ?) USING TTL ?");
/* Create a statement with a single parameter */
CassStatement* statement = cass_statement_new(query, 4); // Bind 4 variables.
cass_statement_bind_string(statement, 0, cass_string_init("abc")); // Bind abc to first column.
cass_statement_bind_string(statement, 1, cass_string_init("bcd")); // Bind bcd to second column.
cass_statement_bind_string(statement, 2, cass_string_init("cde")); // Bind cde to third column.
cass_statement_bind_string(statement, 3, cass_string_init(50)); // Bind 50 to TTL.
/* Execute statement */
cass_statement_free(statement);
Edit:
See https://docs.datastax.com/en/cql/3.3/cql/cql_using/useExpireExample.html where you see that in case of INSERT we have USING TTL as last part of query, as seen above.
I have experimented with Cassandra C++ driver 2.11. I have found following
TTL can be bound by position only and we should use (cass_int32_t) data for binding TTL value
Example: cass_statement_bind_int32(statement, 2, (cass_int32_t)20);
cass_statement_bind_int32_by_name won't work
Ex: cass_statement_bind_int32_by_name(statement, 2, (cass_int32_t)20); //won't work
Related
I'm working in c++ with SQLite, where I need to do some SELECT over a database. The problem is that the SELECT statement is one of the types
SELECT * FROM TABLE; //Unknown data type of columns
SELECT A,B FROM TABLE;//Unknown data type of columns
Where I don't know the types of the columns, but I need to store the retrieved values in corresponding c++ variables with a specific type. So the problem is that I don't know how to get the column data type of the result set given by the SQL SELECT statement after run the sqlite3_step to get the first result set.
In the code I have
//Prepare the statement
rc=sqlite3_prepare_v2
(
connection.database_handle,/* Database handle */
sql_command.c_str(), /* SQL statement, UTF-8 encoded */
sql_command.size(), /* Maximum length of zSql in bytes. */
&sql_statement_handle, /* OUT: Statement handle */
NULL /* OUT: Pointer to unused portion of zSql */
);
if(rc!=SQLITE_OK)
{
return -1;
}
To prepare the select command (in this case "SELECT * FROM TABLE;"), then I have the following to know the total columns in the result set
//Get the total number of columns
stmt_columns=sqlite3_column_count(sql_statement_handle);
if(stmt_columns<=0)
{
return -1;
}
sqlite_column_types=new int[stmt_columns];
After that iterating over the stmt_columns I have
sqlite_column_type=sqlite3_column_type(sql_statement_handle,i);
sqlite_column_types[i]=sqlite_column_type;
In order to retrieve the columns types. But the result is always the NULL data type which has no sense in this case. I tried running first the SQLite function sqlite3_step and then running the function sqlite3_column_type to get the columns type but the behavior is the same. So the question is how to know the columns data type of a SELECT command result set where I don't know in advance the columns types of the table or the query?
I have a table scheme2.central_id__new_numbers in Greenplum.
I need select data from scheme2.central_id__new_numbers in the form of a many-to-many relationship.
Also I write the code but must have made a wrong turn somewhere (the code doesn't work):
CREATE FUNCTION my_scheme.parse_new_numbers (varchar) RETURNS SETOF varchar as
$BODY$
declare
i int;
BEGIN
FOR i IN 1..10 LOOP
select
central_id,
(select regexp_split_to_table((select new_numbers
from scheme2.central_id__new_numbers limit 1 offset i), '\s+'))
from scheme2.central_id__new_numbers limit 1 offset i
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
I'd recommend using the UNNEST() function instead, i.e. assuming new_numbers column is of int[] data type,
SELECT central_id
, UNNEST(new_numbers) AS new_numbers
FROM central_id__new_numbers;
If new_columns column is not an array data type then you need to use i.e. string_to_array() or similar before using UNNEST().
IR based on PL/SQL Function Body returning SQL Query.
How do i can create Interactive reports based on multiple table and Deferent column name.
Exp :-
Select list item return three value
1 or 2 or 3
And the function return query basen on select list value
when Value equal 1
Select name, satate, country_id from cities
when value equal 2 Return
Select country, id from country
when value equal 3 Return
Select ocean,oc_id,from oceans
The three query return different column name and value.
Ok firstly, your question is poorly written. But from what I gather, you want an SQL query that returns different things based on an input.
I dont think you even need a plsql function body for this.
Simply do something like this:
SELECT * FROM
(SELECT name as name,
state as state,
country_id as id,
1 as value
FROM cities
UNION ALL
SELECT country as name,
NULL as state,
id as id,
2 as value
FROM country
UNION ALL
SELECT ocean as name,
NULL as state,
oc_id as id,
3 as value
FROM oceans)
WHERE value = :input_parameter_value;
Because if you are trying to display a variable number of columns and constantly changing their names and such. You are gonna have a bad time, it can be done, as can everything. But afaik its not exactly simple
No objections to what #TineO has said in their answer, I'd probably do it that way.
Though, yet another option: if your Apex version allows it, you can create three Interactive Report regions on the same page, each selecting values from its own table, keeping its own column labels.
Then create a server condition for each region; its type would be Function that returns a Boolean and look like
return :P1_LIST_ITEM = 1;
for the 1st region; = 2 for the 2nd and = 3 for the 3rd.
When you run the page, nothing would be displayed as P1_LIST_ITEM has no value. Once you set it, one of conditions would be met and appropriate region would be displayed.
I configured my firebird database to autoincrement the primary key of the table.
CREATE GENERATOR GEN_CHANNEL_PARAMETER_SET_ID;
SET GENERATOR GEN_CHANNEL_PARAMETER_SET_ID TO 0;
CREATE TRIGGER CHANNEL_PARAMETER_SETS_BI FOR CHANNEL_PARAMETER_SETS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
if (NEW.CHANNEL_PARAMETER_SET_ID is NULL) then NEW.CHANNEL_PARAMETER_SET_ID = GEN_ID(GEN_CHANNEL_PARAMETER_SET_ID, 1);
END
Now, in my C++ program using IBPP I have the following problem:
When inserting a dataset into an new row of this table I know all values in my C++ program exept the new primary key because the database creates it. How can I retrieve this key form the database?
Maybe someone else inserted an entry too - just a moment after I inserted one. So retrieve the PK with the highest value could create an error. How can I handle this?
Adopting Amir Rahimi Farahani's answer I found the following solution for my problem:
I use a generator:
CREATE GENERATOR GEN_CHANNEL_PARAMETER_SET_ID;
SET GENERATOR GEN_CHANNEL_PARAMETER_SET_ID TO 0;
and the following C++/IBPP/SQL code:
// SQL statement
m_DbStatement->Execute(
"SELECT NEXT VALUE FOR gen_channel_parameter_set_id FROM rdb$database"
);
// Retrieve Data
IBPP::Row ibppRow;
int64_t channelParameterSetId;
m_DbStatement->Fetch(ibppRow);
ibppRow->Get (1, channelParameterSetId);
// SQL statement
m_DbStatement->Prepare(
"INSERT INTO channel_parameter_sets "
"(channel_parameter_set_id, ...) "
"VALUES (?, ...) "
);
// Set variables
m_DbStatement->Set (1, channelParameterSetId);
...
...
// Execute
m_DbStatement->Execute ();
m_DbTransaction->CommitRetain ();
It is possible to generate and use the new id before inserting the new record:
SELECT NEXT VALUE FOR GEN_CHANNEL_PARAMETER_SET_ID FROM rdb$database
You now know the value for new primary key.
Update:
IBPP supports RETURNING too:
// SQL statement
m_DbStatement->Prepare(
"INSERT INTO channel_parameter_sets "
"(...) VALUES (...) RETURNING channel_parameter_set_id"
);
// Execute
m_DbStatement->Execute ();
m_DbTransaction->CommitRetain ();
// Get the generated id
m_DbStatement->Get (1, channelParameterSetId);
...
To retrieve the value of the generated key (or any other column) you can use INSERT ... RETURNING ....
For example:
INSERT INTO myTable (x, y, z) VALUES (1, 2, 3) RETURNING ID
Also a lot of drivers provide extra features to support RETURNING, but I don't know IBPP.
Note that from the perspective of a driver the use of RETURNING will make the insert act like an executable stored procedure; some drivers might require you to execute it in a specific way.
I got a query with bind variables where the same bind variable shows up more than once, for example:
select *
from some_table
where param1 = :parm1 and
applied_date = (select min(applied_date)
from some_table
where param1 = :parm1)
When I run this query in sqlplus Oracle appears to be binding by name. I.e. recognizes that the first and the second occurrence of parm1 is the same parameter and prompts me for the value of parm1 only once.
However, when in my C++ program I describe the bind variables into the bind descriptor, it always bind by position.
EXEC SQL DESCRIBE BIND VARIABLES FOR my_stmt INTO myBindDesc
The value of myBindDesc->F is 2 not 1, and the query won't execute properly until I populate
both of them, even though it's the same value.
My question is: is there a way to bind by name in PRO*C?
I can't tell for sure the cause of this problem, but you can rewrite the query to use only the :VAR only once in several ways. I hope this can help you -- if not understand, at least solve your problem:
SELECT *
FROM some_table tout
JOIN (
SELECT MIN(param1) AS "param1_min", MIN(applied_date) AS "applied_date_min"
FROM some_table
WHERE param1 = :parm1
) taux ON (1=1
AND tout.param1 = taux.param1_min
AND tout.applied_date = taux.applied_date_min
)