How to read the firebird databases query result size? - c

I am doing C interface with firebird databases. I did some query operations. I would like to know how to read the result size?
Below is the code. I have created and inserted some values into the table.I would like to read the size of the result.
#include <stdio.h>
#include "/Library/Frameworks/Firebird.framework/Versions/A/Headers/ibase.h"
static char *createTable="CREATE TABLE newex (Id int)"; //query for creating data table
static char *Insertvalues="INSERT INTO newex values (1)";//doing insertion into the
//above created table
int SQLOpen(void)
{
ISC_STATUS status_vector[20];
isc_tr_handle transactionHandle = NULL; //transaction handle
isc_db_handle database = SQLGetDatabase();//database handle
char logInData [256], *dpb, *p;
short bufferLength;
User_Credentials credentials;
sprintf(logInData, "%c%c%c%c%c%c%s%c%c%s", isc_dpb_version1,
isc_dpb_num_buffers,
1,
90,
isc_dpb_user_name,
strlen("SYSDBA"),
"SYSDBA",
isc_dpb_password,
strlen("masterkey"),
"masterkey"); //passing user //credentials to connect to the database
bufferLength = strlen(logInData);
if (isc_attach_database(status_vector, strlen(DATABASE_PATH), DATABASE_PATH, &DatabaseHandle,bufferLength, logInData)) // connecting to database
{
SQLTestForErrors(status_vector);
throw(ConnectionError, "");
}
return 1;
}
char** SQLQuery(char *query, uint maxRows)
{
isc_tr_handle transactionHandle = NULL;
isc_db_handle database = SQLGetDatabase();
short bufferLength;
char dpb_buffer[256], *dpb, *p;
ISC_STATUS status_vector[20];
isc_start_transaction(status_vector, &transactionHandle, 1, &database, 0, NULL);
if (isc_dsql_execute_immediate(status_vector, &database, &transactionHandle, 0, query, 1, NULL)) //query operations 'create/insert'
{
SQLTestForErrors(status_vector);
throw(QueryError, "");
}
isc_commit_transaction(status_vector, &transactionHandle);
return testString;
}
int main()
{
//struct Folder_table;
e4c_using_context(E4C_TRUE)
{
SQLOpen();
SQLQuery(createTable);
SQLQuery(Insertvalues);
}
}

You can't in advance: the result set is materialized while you are reading rows (using isc_fetch): the final number of rows is not known until you have read all rows (at which point you can either have counted it yourself, or query it with an info request).
However I notice that you try to use isc_dsql_execute_immediate. You can only use isc_dsql_execute_immediate for ddl and for queries that produce one row (you need to prepare and execute for multiple rows).

Related

How to set sub table name while using tdengine's schemaless insert

I know that tdengine support schemaless insert. And there are three line protocols that tdengine supports. The follow is the sample code from taosdata's website schemaless chapeter.
#include <stdlib.h>
#include <stdio.h>
#include <taos.h>
int main() {
const char* host = "127.0.0.1";
const char* user = "root";
const char* passwd = "taosdata";
// connect to server
TAOS* taos = taos_connect(host, user, passwd, "test", 0);
// prepare the line string
char* lines1[] = {
"stg,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000",
"stg,t1=4i64,t3=\"t4\",t2=5f64,t4=5f64 c1=3i64,c3=L\"passitagin\",c2=true,c4=5f64,c5=5f64 1626006833641000000"
};
// schema-less insert
TAOS_RES* res = taos_schemaless_insert(taos, lines1, 2, TSDB_SML_LINE_PROTOCOL, TSDB_SML_TIMESTAMP_NANO_SECONDS);
if (taos_errno(res) != 0) {
printf("failed to insert schema-less data, reason: %s\n", taos_errstr(res));
}
taos_free_result(res);
// close the connection
taos_close(taos);
return (code);
}
I know this will create the stable "stg" and create substable for the incoming data record. I want to ask can I control the subtable's name and how to configure the name?
No, you cannot configure subtable name in TDengine database
Please refer this link for how subtable name is generated: https://docs.tdengine.com/reference/schemaless/#main-processing-logic-for-schemaless-writing

EXC_BAD_ACCESS While trying to access OS X Keychain

I wrote a sample code (with help received earlier) to add and retrieve a password from OS X keychain. I am able to successfully add the password but when I try to retrieve it I get a EXC_BAD_ACCESS (code=EXC_I386_GPFLT). I tried doing this two ways:
Using the SecItemCopyMatching API that uses a query based approach to access the keychain.
Using the SecKeychainFindGenericPassword.
The BAD ACCESS error happens only withe first approach, the second one succeeds. I am trying to use the first approach so that I can ensure that I am using the SecKeychainItemFreeContent to clean up once I am done.
Note - this is a sample code and hence I haven't put any checks for return values. Though I have been keeping an eye on them in the debugger and see no errors there.
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
int main(int argc, const char * argv[])
{
char acc_name[20];
char password[20];
CFStringRef keys[3];
printf("Enter account name - ");
scanf("%s", acc_name);
printf("\nEnter password - ");
scanf("%s", password);
keys[0] = kSecClass;
keys[1] = kSecAttrAccount;
keys[2] = kSecValueData;
CFTypeRef values[3];
values[0] = kSecClassGenericPassword;
values[1] = CFStringCreateWithCString(kCFAllocatorDefault, acc_name, kCFStringEncodingUTF8);
values[2] = CFStringCreateWithCString(kCFAllocatorDefault, password, kCFStringEncodingUTF8);
CFDictionaryRef query;
query = CFDictionaryCreate(kCFAllocatorDefault, (const void**) keys, (const void**) values, 3, NULL, NULL);
OSStatus result = SecItemAdd(query, NULL);
printf("%d\n", result);
printf("Retrieve\n");
SecKeychainItemRef pitem = NULL;
SecKeychainItemRef kch_ref = NULL;
CFStringRef qkeys[6];
qkeys[0] = kSecClass;
qkeys[1] = kSecAttrAccount;
qkeys[2] = kSecMatchLimit;
qkeys[3] = kSecReturnAttributes;
qkeys[4] = kSecReturnData;
qkeys[5] = kSecReturnRef;
CFTypeRef qvalues[6];
qvalues[0] = kSecClassGenericPassword;
qvalues[1] = CFStringCreateWithCString(kCFAllocatorDefault, acc_name, kCFStringEncodingUTF8);
qvalues[2] = kSecMatchLimitOne;
qvalues[3] = kCFBooleanTrue;
qvalues[4] = kCFBooleanTrue;
qvalues[5] = kCFBooleanTrue;
unsigned int plength = 0;
char *pdata = NULL;
unsigned int plength2 = 0;
void *pdata2 = NULL;
CFDictionaryRef extract_query = CFDictionaryCreate(kCFAllocatorDefault, (const void **)qkeys, (const void **)qvalues, 6, NULL, NULL);
result = SecItemCopyMatching(extract_query, (CFTypeRef *)&kch_ref);
SecKeychainItemCopyAttributesAndData(kch_ref, NULL, NULL, NULL, &plength2, &pdata2); // <-- EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
//result = SecKeychainFindGenericPassword(NULL, 0, NULL, (uint32)strlen(acc_name), acc_name, &plength, (void **)&pdata, &pitem);
if (result)
{
//return error;
}
printf("password - %s\n", pdata);
return 0;
}
You seem to be passing a bad parameter to SecKeychainItemCopyAttributesAndData.
In your query dictionary, you specify three different return types: kSecReturnAttributes, kSecReturnData, and kSecReturnRef. The documentation for SecItemCopyMatching has this to say:
Use the keys found in Item Return Result Keys to indicate whether you seek the item’s attributes, the item’s data, a reference to the data, a persistent reference to the data, or a combination of these. When you specify more than one return type, the search returns a dictionary containing each of the types you request. When your search allows multiple results, they’re all returned together in an array of items.
So, the type returned by SecItemCopyMatching (since you limit to one result) will be a CFDictionary containing the item data, item attributes and a reference to the item.
You then pass it to SecKeychainItemCopyAttributesAndData, but the documentation for the first parameter says:
itemRef
A reference to the keychain item from which you wish to retrieve data or attributes.
If you modify your query dictionary to only include the kSecReturnRef return type (removing kSecReturnAttributes and kSecReturnData), your code will work.
(Or, extract the reference from the dictionary that SecItemCopyMatching is returning and pass that to SecKeychainItemCopyAttributesAndData)

How to get COUNT(*) value from sqlite3_exec()?

In my C program I have to check if count of a table in database is one or zero and to do that i am executing query as follows:
char *sql = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name=family;";
int table_count = sqlite3_exec(db, sql, 0, 0, &err_msg);
printf("\n%d\n", table_count);
I'm expecting table_count to be 1 as only one table exists with name family but printf outputs table_count as '21' which is incorrect. How can we get the COUNT(*) value from C/C++ API in C program the right/correct way?
After reading SQLite Documentation and following other kind implicit/explicit suggestions in the comments on the question, I have realized my mistakes in that code snippet quoted in the question.
Mistake 1:
I did not implement callback function to receive the result set after the SQL query gets executed. [Have implemented this callback: see checkTable_Callback in code below]
Mistake 2:
That output of '21' is actually the error code and as per the SQLite documentation that error code corresponds to SQLite_MISUSE Which was being generated, perhaps, because I was using a separate function to open my test database file and instance of that opened database, i assume, stayed inside that openDb function, and when i used another function checkTableCount from where i took that messy snippet to quote in my question, there db instance perhaps was null, hence 21. Experts can elaborate further if that's why i was receiving error code 21. Anyways, now i have fixed that function and made that openDb return an opened db instance (better word?) and now 21 error is gone. [see code below]
Here is fixed and 'adapted-for-my-case' code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sqlite3.h" /* sqlite3.dll and sqlite3.h both reside in
my <program_source.c>'s folder */
static int checkTable_Callback(
void *unnecessary_here,
int number_of_columns_in_result_row, /* will always be 1 in this case */
char **value_of_count, /* will be either 0 or 1 in this case */
char **label_for_count) { /* will be COUNT(*) normally,
but modified via 'AS table_tablename' in this case*/
printf("COUNT(*) %s\t=>\t%s\n", label_for_count[0], value_of_count[0] );
return 0;
} // end of checkTable_Callback()
char * build_sql(const char *sql_partA, const char *sql_partB) {
size_t size = strlen(sql_partA) + strlen(sql_partB);
char *sql_final = malloc(size + 1);
strcpy(sql_final, sql_partA);
strcat(sql_final, sql_partB);
return sql_final; /* allocated memory to be freed at the end of calling function */
} // end of build_sql()
checkTableCount(sqlite3 *db, char *tablename) {
char *sql = build_sql(
build_sql(
build_sql(
build_sql(
"SELECT COUNT(*) AS table_",
tablename),
" FROM sqlite_master WHERE type='table' AND name='"),
tablename),
"';");
sqlite3_exec(db, sql, checkTable_Callback, 0, NULL);
/* error checking sacrificed for brevity of sample */
free(sql);
}// end of checkTableCount()
sqlite3 * openDb(char * db_name){
sqlite3 *db;
int result_code = sqlite3_open(db_name, &db);
if( result_code != 0 )
fprintf(stderr, "\tError: %s\n\n", sqlite3_errmsg(db));
return db;
} // end of openDb()
int main() {
sqlite3 * db = openDb("testing.db"); /* testing.db already has one table 'family'*/
checkTableCount(db, "family");
checkTableCount(db, "fam"); /* no such table exist */
sqlite3_close(db);
return 0;
} // end of main()
Now this quoted 'adapted-for-my-case' code rightly and correctly outputs the COUNT(*) as follows:
OUTPUT
COUNT(*) table_family => 1
COUNT(*) table_fam => 0
Note that I didn't bother to write a for-loop inside my callback function named checkTable_Callback to iterate through columns as shown in the official sample of callback function on this page because of the fact that our expected result row is certainly going to be only one containing only one column with label modified, via 'AS' clause, into 'table_tablename'. If not modified via 'AS clause', the returned column label would be 'COUNT(*)' in the result row.

SQLite3: the database was created empty?

I'm trying to create a database with a table using sqlite3 on my C program, however the database is always created as empty, though it was created non-empty using the sqlite shell,
here is my code below:
int main(void)
{
printf("hello\n");
sqlite3 *sqdb;
sqlite3_initialize();
const char* db = "test";
sqlite3_open(db, &sqdb);
const char* stmt = "CREATE TABLE IF NOT EXISTS testtable(creationdate DATE, data VARCHAR);";
sqlite3_stmt *ppstmt;
if (sqlite3_prepare_v2(sqdb, stmt, -1, &ppstmt, 0)!=SQLITE_OK)printf("error!\n");
sqlite3_finalize(ppstmt);
getch();
return 0;
}
please help me to solve the problem.
sqlite3_prepare_v2() alone just compiles the SQL but does not run it. Call sqlite3_step() on the compiled statement to run it, or use sqlite3_exec() that combines prepare+step+finalize into one function call.
Try this:
int main(void)
{
printf("hello\n");
sqlite3 *sqdb;
int ret;
sqlite3_initialize();
const char* db = "test.sqlite3";
sqlite3_open(db, &sqdb);
const char* stmt = "CREATE TABLE IF NOT EXISTS testtable(creationdate DATE, data VARCHAR);";
sqlite3_stmt *ppstmt=NULL;
ret=sqlite3_exec(sqdb,stmt,0,0,0);
if(ret!=SQLITE_OK)printf("error!\n");
else printf("Table added\n");
sqlite3_finalize(ppstmt);
sqlite3_close(sqdb);
return 0;
}
Please do remember to close the DB after operation.

Generic SQLite Result Function? (C)

I'm programming server software in C, and I'll have around 8 functions that select data from an SQLite database and handle it in some way. I'm considering making one function to send any kind of SQLite SELECT command and return its results as a 2D array of pointers to integers and strings then having all the functions use that, but I'm worried that the performance cost might be so large that it's not worth the extra expandability. Reading ahead, is performance a valid concern here?
SQLite has no way of counting the rows of a result ahead of time, so I'd have to either run two queries or use a dynamically-allocated array. Not good! Here is what I have for my implementation of the latter option. I'm a newbie, so please tell me if there is anything slow, unclean, or (most importantly) unreliable about this before I commit to using it:
//emalloc and erealloc are just error-detecting malloc and realloc
ptrdiff_t** databaseSelect(char* command){ //returns null upon error
sqlite3_stmt *stmt;
int retval = -1; retval = sqlite3_prepare(db,command,sizeof(command),&stmt,NULL);
if(retval!=SQLITE_OK){
printf("Selecting data from database failed! Error: %s\n", sqlite3_errmsg(db));
return NULL;
}
int retRows = 10; //number of rows in returned array for now
ptrdiff_t** ret = emalloc(sizeof(ptrdiff_t*)*retRows); //make the array representing rows
int result = SQLITE_ROW;
int rowIndex = 0;
while (result != SQLITE_DONE && result != SQLITE_ERROR){
result = sqlite3_step (stmt);
if (result == SQLITE_ROW) { //begin row loop
if ((rowIndex+1)>retRows){ //must reallocate the outer (row) array
retRows*=2;
ret = erealloc(ret, sizeof(ptrdiff_t*)*retRows);
}
const int numCols = sqlite3_column_count(stmt);
ptrdiff_t* row = emalloc(sizeof(ptrdiff_t)*numCols); //make the array representing a row of columns
for (int colIndex = 0; colIndex<numCols; colIndex++){ //begin column loop
switch (sqlite3_column_type(stmt, colIndex)){
case SQLITE_INTEGER:{
const int col = sqlite3_column_int(stmt, colIndex);
memcpy(row[colIndex], &col, sizeof(col));
break;
}
case SQLITE_TEXT:{
const unsigned char* textResult = sqlite3_column_text(stmt, colIndex);
const size_t textSize = (strlen(textResult)+1)*sizeof(char); //edited from before
row[colIndex] = emalloc(textSize);
memcpy(row[colIndex], textResult, textSize);
break;
}
default:{
//perhaps warn about an error since it should either be integer or text
break;
}
}
} //end column loop
ret[rowIndex] = row; //add on the row to the array of rows
rowIndex++;
} //end row loop
}
sqlite3_free(stmt);
return ret;
}
… And then whatever calls this function has to loop through the 2D array and free everything once it's done with it.
For smallish results, performance does not matter.
Reallocating with a constant factor is one of the most efficient ways of creating a dynamc-sized array. Creating a linked would be faster, but not as easy to access later.
A cursor would be an object that allows access (only) to the current record, but this does not work if you need random access to all result records.
Please note that the most efficient way to determine a text value's length is sqlite3_column_bytes:
char *textResult = (char *)sqlite3_column_text(stmt, colIndex);
if (!textResult) textResult = ""; // handle NULL (if needed)
int textSize = sqlite3_column_bytes(stmt, colIndex) + 1;

Resources