I am attempting to perform a select query where a varchar column has a particular value. This works if I hard-code in the search string (e.g., name='max'), but is not working when I attempt to bind the parameter as a SQL_TEXT+1 or a SQL_VARYING+1 parameter. In my attempt to get it to work, I have also tried changing it to a like query, or even wrapping the search term in single quotes (which, I know, should only be used for hard-coded strings). An example is included below. As always, any help would be appreciated.
#################################################################
#include <stdlib.h>
#include <string.h>
#include <ibase.h>
#include <stdio.h>
#include <set>
#include <iostream>
#include <vector>
#define RC_OK 0
#define STRING_SIZE 256
using namespace std;
#define SQL_DIALECT_VERSION 3
#define DB_HANDLE_COUNT 1
#define USE_XSQLDA 1
#ifndef NDEBUG
#Â Â define ASSERT(condition, message) \
   do { \
       if (! (condition)) { \
           std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \
                     << " line " << __LINE__ << ": " << message << std::endl; \
           std::terminate(); \
       } \
   } while (false)
#else
#Â Â define ASSERT(condition, message) do { } while (false)
#endif
typedef struct DB_ENTRY {
   string data;
   string name;
   DB_ENTRY(const string &my_data, const string &my_name) {
       data = my_data ;
       name = my_name;
   }
   DB_ENTRY() {}
} db_entry;
typedef struct SQL_VARCHAR {
   short len;
   char data[STRING_SIZE+1];
} sql_varchar;
isc_db_handle db = NULL;
isc_stmt_handle stmt = NULL;
size_t num_cols;
void bind_varchar(XSQLVAR *param, int &i, sql_varchar *val, short *is_null, bool write = false) {
   param->sqltype = SQL_VARYING + 1;
   param->sqldata = (char*)val;
   param->sqlind = is_null;
   if(write) {
       param->sqllen = val->len;
   }
   i++;            Â
}
void bind_text(XSQLVAR *param, int &i, char *val, short *is_null, bool write = false, long unsigned int size = 0) {
   param->sqltype = SQL_TEXT + 1;
   param->sqldata = val;
   param->sqlind = is_null;
   if(write) {
       param->sqllen = size;
   }
   i++;            Â
}
int initialize_db() {
   int rc;
   ISC_STATUS_ARRAY status; /* status vector */
   isc_tr_handle trans = NULL; /* transaction handle */
   //fix
   string db_name = "correctness_test_varchar.fdb";
   string create_db_query = "CREATE DATABASE '" + db_name + "' PAGE_SIZE=8192";
   /*
    *   Create a new database.
    *   The database handle is zero.
    */
      if (isc_dsql_execute_immediate(status, &db, &trans, 0, create_db_query.c_str(), SQL_DIALECT_VERSION,
                                  NULL))
   {
       /* Extract SQLCODE from the status vector. */
       long sqlcode = isc_sqlcode(status);
       /* Print a descriptive message based on the SQLCODE. */
       if (sqlcode == -902)
       {
           printf("\nDatabase already exists.\n");
           // printf("Remove %s before running this program.\n\n", new_dbname);
           rc = isc_attach_database(status, 0, db_name.c_str(), &db, 0, NULL);
           ASSERT(rc == RC_OK, isc_print_status(status));
       }
   }
   isc_commit_transaction(status, &trans);
   printf("Created database '%s'.\n\n", db_name.c_str());
   return rc;
}
//designed to create one at a time, so we don't have to worry about cross-table interference
int create_table() {
   int rc;
   ISC_STATUS_ARRAY status; /* status vector */
   isc_tr_handle trans = NULL; /* transaction handle */
   string create_table_query;
   char query_buffer[512] = "recreate table my_table (name varchar (50) not null, data varchar(256))";
   /* Create table. */
   isc_start_transaction(status, &trans, DB_HANDLE_COUNT, &db, 0, NULL);
   rc = isc_dsql_execute_immediate(status, &db, &trans, 0, query_buffer, SQL_DIALECT_VERSION, NULL);
   ASSERT(rc == RC_OK, isc_print_status(status));
   isc_commit_transaction(status, &trans);
   return rc;
}
      Â
int prepare_statements() {
   int rc;
   ISC_STATUS_ARRAY status; /* status vector */
   isc_tr_handle trans = NULL; /* transaction handle */
   rc = isc_dsql_allocate_statement(status, &db, &stmt);
   string query = "insert into my_table (name, data) values (?, ?)";
   num_cols = 2;
   rc = isc_dsql_prepare(status, &trans, &stmt, 0, query.c_str(), SQL_DIALECT_VERSION, NULL);
   ASSERT(rc == RC_OK, isc_print_status(status));
   return rc;
}
XSQLDA *init_stmt_input_params(int num_input_params) {
   XSQLDA *stmt_input_params = (XSQLDA *) malloc(XSQLDA_LENGTH(num_input_params));
   stmt_input_params->sqln = stmt_input_params->sqld = num_input_params;
   stmt_input_params->version = 1;
   return stmt_input_params;
}
XSQLDA *init_stmt_output_params(int num_output_params) {
   XSQLDA *stmt_output_params = (XSQLDA *) malloc(XSQLDA_LENGTH(num_output_params));
   stmt_output_params->sqln = stmt_output_params->sqld = num_output_params;
   stmt_output_params->version = 1;
   return stmt_output_params;
}
int perform_write(const db_entry &entry) {
   int rc;
   ISC_STATUS_ARRAY status; /* status vector */
   isc_tr_handle trans = NULL; /* transaction handle */
   short is_null[num_cols];
   size_t length[num_cols];
   sql_varchar name_buffer;
   sql_varchar data_buffer;
   XSQLDA *stmt_input_params = (XSQLDA *) malloc(XSQLDA_LENGTH(num_cols));
   stmt_input_params->sqln = stmt_input_params->sqld = num_cols;
   stmt_input_params->version = 1;
   int i = 0;
   strncpy(name_buffer.data, entry.name.c_str(), entry.name.size()+1); /* string */
   name_buffer.len = entry.name.size();
   is_null[i] = (name_buffer.len == 0);
   bind_varchar(&stmt_input_params->sqlvar[i], i, &name_buffer, &is_null[i], true);
   strncpy(data_buffer.data, entry.data.c_str(), entry.data.size()+1); /* string */
   data_buffer.len = entry.data.size();
   is_null[i] = (data_buffer.len == 0);
   bind_varchar(&stmt_input_params->sqlvar[i], i, &data_buffer, &is_null[i], true);
   /* Declare the cursor. */
   isc_dsql_set_cursor_name(status, &stmt, "write md", 0);
   rc = isc_start_transaction(status, &trans, DB_HANDLE_COUNT, &db, 0, NULL);
   ASSERT(rc == RC_OK, isc_print_status(status));
   rc = isc_dsql_execute(status, &trans, &stmt, SQL_DIALECT_VERSION, stmt_input_params);
   ASSERT(rc == RC_OK, isc_print_status(status));
   rc = isc_commit_transaction(status, &trans);
   ASSERT(rc == RC_OK, isc_print_status(status));
   free(stmt_input_params);
   return rc;
}
void print_db_entry(const db_entry &entry) {
   std::cout << "\t\tentry - name: " <<
entry.name << ", data: " << entry.data << endl;
}
void print_db_entries(const std::vector<db_entry> &entries) {
   for(const db_entry &entry : entries) {
       print_db_entry(entry);
   }
   cout << endl;
}
int retrieve_matching_entries(isc_stmt_handle *stmt, XSQLDA *stmt_input_params, vector<db_entry> &entries) {
   int rc;
   ISC_STATUS_ARRAY status; /* status vector */
   isc_tr_handle trans = NULL; /* transaction handle */
   db_entry entry;
   sql_varchar name_buffer;
   sql_varchar data_buffer;
   short is_null[num_cols];
   XSQLDA *stmt_output_params = init_stmt_output_params(num_cols);
   rc = isc_dsql_describe(status, stmt, USE_XSQLDA, stmt_output_params);
   ASSERT(rc == RC_OK, isc_print_status(status));
   int i = 0;
   bind_varchar(&stmt_output_params->sqlvar[i], i, &name_buffer, &is_null[i]);
   bind_varchar(&stmt_output_params->sqlvar[i], i, &data_buffer, &is_null[i]);
   rc = isc_start_transaction(status, &trans, DB_HANDLE_COUNT, &db, 0, NULL);
   ASSERT(rc == RC_OK, isc_print_status(status));
   rc = isc_dsql_execute(status, &trans, stmt, USE_XSQLDA, stmt_input_params);
   ASSERT(rc == RC_OK, isc_print_status(status));
   while (!isc_dsql_fetch(status, stmt, USE_XSQLDA, stmt_output_params)) {
      Â
entry.name = name_buffer.data;
       entry.data = data_buffer.data;
       entries.push_back(entry);
   }
   rc = isc_dsql_free_statement (status, stmt, DSQL_close);
   ASSERT(rc == RC_OK, isc_print_status(status));
   rc = isc_commit_transaction(status, &trans);
   ASSERT(rc == RC_OK, isc_print_status(status));
   free(stmt_output_params);
   return rc;
}
void print_query_results(const string &query) {
   int rc;
   vector<db_entry> entries;
   ISC_STATUS_ARRAY status; /* status vector */
   isc_tr_handle trans = NULL; /* transaction handle */
   isc_stmt_handle stmt = NULL;
   isc_dsql_allocate_statement(status, &db, &stmt);   Â
   rc = isc_dsql_prepare(status, &trans, &stmt, 0, query.c_str(), SQL_DIALECT_VERSION, NULL);
 Â
   rc = retrieve_matching_entries(&stmt, NULL, entries);
   cout << "db entries where name = 'max':" << endl;
   print_db_entries(entries);
}
void find_matching() {
   string query;
   query = "select * from my_table where name = 'max'";
   print_query_results(query);
}
void find_matching_w_bound_params(const string &to_search_for, bool use_varchar, bool like = false) {
   int rc, i = 0;
   vector<db_entry> matching_entries;
   ISC_STATUS_ARRAY status; /* status vector */
   isc_tr_handle trans = NULL; /* transaction handle */
   isc_stmt_handle stmt = NULL;
   size_t num_input_params = 1;
   string query;
   if(like) {
       query = "select * from my_table where name like ?";      Â
   }
   else {
       query = "select * from my_table where name = ?";      Â
   }
   isc_dsql_allocate_statement(status, &db, &stmt);   Â
   rc = isc_dsql_prepare(status, &trans, &stmt, 0, query.c_str(), SQL_DIALECT_VERSION, NULL);
   XSQLDA *stmt_input_params = init_stmt_input_params(num_input_params);
   short is_null[num_input_params];
   if(use_varchar) {
       sql_varchar text_buffer;
       strncpy(text_buffer.data, to_search_for.c_str(), to_search_for.size()+1);
       text_buffer.len = to_search_for.size();
       bind_varchar(&stmt_input_params->sqlvar[i], i, &text_buffer, &is_null[i], true);      Â
   }
   else {
       char text_buffer[256];
       strncpy(text_buffer, to_search_for.c_str(), to_search_for.size()+1);
       long unsigned int str_len = to_search_for.size();
       bind_text(&stmt_input_params->sqlvar[i], i, text_buffer, &is_null[i], str_len);
   }
   rc = retrieve_matching_entries(&stmt, stmt_input_params, matching_entries);
   if(use_varchar) {
       cout << "using varchar, ";
   }
   else {
       cout << "using text, ";
   }
   if(like) {
       cout << "db entries where have bound name like " << to_search_for << ":" << endl;
   }
   else {
       cout << "db entries where have bound name = " << to_search_for << ":" << endl;
   }
   print_db_entries(matching_entries);
}
 Â
int main() {
   string name_buffer0 = "max";
   string name_buffer1 = "note_freq";
   string data_buffer_str = "I discovered made a very interesting observation that XXXXXX";
   string data_buffer_dim0_min = "7830992237.586059";
   string data_buffer_dim0_max = "2777747108.031878";
   string data_buffer_dim1_min = "
5134009101.956155";
   string data_buffer_dim1_max = "
6069688762.570586";
   string data_buffer_dim2_min = "4009443942.461835";
   db_entry entry0(data_buffer_dim0_min, name_buffer0);
   db_entry entry1(data_buffer_str, name_buffer1);
   db_entry entry2(data_buffer_dim0_max, name_buffer0);
   db_entry entry3(data_buffer_dim1_min, name_buffer0);
   db_entry entry4(data_buffer_str, name_buffer1);
   db_entry entry5(data_buffer_dim1_max, name_buffer0);
   db_entry entry6(data_buffer_dim2_min, name_buffer0);
   initialize_db();
   create_table();
   prepare_statements();
   perform_write(entry0);
   perform_write(entry1);
   perform_write(entry2);
   perform_write(entry3);
   perform_write(entry4);
   perform_write(entry5);
   perform_write(entry6);
   find_matching();
   find_matching_w_bound_params("max", true);
   find_matching_w_bound_params("'max'", true);
   find_matching_w_bound_params("%max%", true, true);
   find_matching_w_bound_params("'%max%'", true, true);
   find_matching_w_bound_params("max", false);
   find_matching_w_bound_params("'max'", false);
   find_matching_w_bound_params("%max%", false, true);
   find_matching_w_bound_params("'%max%'", false, true);
}