template<> StrVec
GncDbiProviderImpl<DbType::DBI_MYSQL>::get_index_list (dbi_conn conn)
{
    StrVec retval;
    const char* errmsg;
    auto tables = get_table_list(conn, "");
    for (auto table_name : tables)
    {
        auto result = dbi_conn_queryf (conn,
                                       "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'",
                                       table_name.c_str());
        if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
        {
            PWARN ("Index Table Retrieval Error: %s on table %s\n",
                   errmsg, table_name.c_str());
            continue;
        }

        while (dbi_result_next_row (result) != 0)
        {
            std::string index_name {dbi_result_get_string_idx (result, 3)};
            retval.push_back(index_name + " " + table_name);
        }
        dbi_result_free (result);
    }

    return retval;
}
Exemple #2
0
time_t SMSDDBI_GetDate(GSM_SMSDConfig * Config, SQL_result *res, unsigned int field)
{
	unsigned int type;
	const char *date;

	field++;
	type = dbi_result_get_field_type_idx(res->dbi, field);

	switch (type) {
		case DBI_TYPE_INTEGER:
		case DBI_TYPE_DECIMAL:
#ifdef DBI_TYPE_XDECIMAL
		case DBI_TYPE_XDECIMAL:
#endif
			return SMSDDBI_GetNumber(Config, res, field);
		case DBI_TYPE_STRING:
			date = dbi_result_get_string_idx(res->dbi, field);
			return SMSDSQL_ParseDate(Config, date);
		case DBI_TYPE_DATETIME:
			return dbi_result_get_datetime_idx(res->dbi, field);
		case DBI_TYPE_ERROR:
		default:
			SMSD_Log(DEBUG_ERROR, Config, "Wrong field type for date from DBI: %d", type);
			return -1;
	}
}
/**
	@brief Return a boolean value from a database result.
	@param result The database result.
	@param i Index of the column in the result, starting with 1 );
	@return 1 if true, or 0 for false.

	Null values and error conditions are interpreted as FALSE.
*/
static int oils_result_get_bool_idx( dbi_result result, int i ) {
	if( result ) {
		const char* str = dbi_result_get_string_idx( result, i );
		return (str && *str == 't' ) ? 1 : 0;
	} else
		return 0;
}
Exemple #4
0
gboolean SMSDDBI_GetBool(GSM_SMSDConfig * Config, SQL_result *res, unsigned int field)
{
	unsigned int type;
	const char *value;
	int num;

	field++;
	type = dbi_result_get_field_type_idx(res->dbi, field);

	switch (type) {
		case DBI_TYPE_INTEGER:
		case DBI_TYPE_DECIMAL:
#ifdef DBI_TYPE_XDECIMAL
		case DBI_TYPE_XDECIMAL:
#endif
			num = SMSDDBI_GetNumber(Config, res, field);
			if (num == -1) {
				return -1;
			} else if (num == 0) {
				return FALSE;
			} else {
				return TRUE;
			}
		case DBI_TYPE_STRING:
			value = dbi_result_get_string_idx(res->dbi, field);
			return GSM_StringToBool(value);
		case DBI_TYPE_ERROR:
		default:
			SMSD_Log(DEBUG_ERROR, Config, "Wrong field type for boolean from DBI: %d", type);
			return -1;
	}
}
Exemple #5
0
static xmlNodePtr
query_doc(dbi_result *result, char *query_name)
{
    char *elt;
    unsigned long mylong;
    char buffer[100];
    unsigned int i;

    xmlDocPtr doc = NULL;
    xmlNodePtr top_query = NULL, query_row = NULL;
    doc = xmlNewDoc(BAD_CAST "1.0");
    top_query = xmlNewNode(NULL, BAD_CAST query_name);
    xmlDocSetRootElement(doc, top_query);

    while (dbi_result_next_row(result))
    {

        query_row = xmlNewChild(top_query, NULL, BAD_CAST query_name,NULL);
        for (i=1; i < dbi_result_get_numfields(result) + 1; i++)
        {
            elt = strdup(dbi_result_get_field_name(result,i));
            if (dbi_result_get_field_type_idx(result,i) == 3) {
                if (dbi_result_get_string_idx(result,i))
                {
                    xmlNewChild(query_row, NULL, BAD_CAST elt, BAD_CAST dbi_result_get_string_idx(result,i));
                }
            }
            if (dbi_result_get_field_type_idx(result,i) == 1) {
                if (dbi_result_get_ulonglong_idx(result,i))
                {
                    mylong = dbi_result_get_ulonglong_idx(result,i);
                    sprintf(buffer, "%ld", mylong);
                    xmlNewChild(query_row, NULL, BAD_CAST elt, BAD_CAST buffer);
                }
            }
        }

    }

    return xmlDocGetRootElement(doc);

    xmlFreeDoc(doc);
    xmlCleanupParser();

}
Exemple #6
0
static int cdbi_result_get_field (dbi_result res, /* {{{ */
    unsigned int index, char *buffer, size_t buffer_size)
{
  unsigned short src_type;

  src_type = dbi_result_get_field_type_idx (res, index);
  if (src_type == DBI_TYPE_ERROR)
  {
    ERROR ("dbi plugin: cdbi_result_get: "
        "dbi_result_get_field_type_idx failed.");
    return (-1);
  }

  if (src_type == DBI_TYPE_INTEGER)
  {
    long long value;

    value = dbi_result_get_longlong_idx (res, index);
    ssnprintf (buffer, buffer_size, "%lli", value);
  }
  else if (src_type == DBI_TYPE_DECIMAL)
  {
    double value;

    value = dbi_result_get_double_idx (res, index);
    ssnprintf (buffer, buffer_size, "%63.15g", value);
  }
  else if (src_type == DBI_TYPE_STRING)
  {
    const char *value;

    value = dbi_result_get_string_idx (res, index);
    if (value == NULL)
      sstrncpy (buffer, "", buffer_size);
    else if (strcmp ("ERROR", value) == 0)
      return (-1);
    else
      sstrncpy (buffer, value, buffer_size);
  }
  /* DBI_TYPE_BINARY */
  /* DBI_TYPE_DATETIME */
  else
  {
    const char *field_name;

    field_name = dbi_result_get_field_name (res, index);
    if (field_name == NULL)
      field_name = "<unknown>";

    ERROR ("dbi plugin: Column `%s': Don't know how to handle "
        "source type %hu.",
        field_name, src_type);
    return (-1);
  }

  return (0);
} /* }}} int cdbi_result_get_field */
static double rrd_fetch_dbi_double(dbi_result *result,int idx) {
  char *ptmp="";
  double value=DNAN;
  /* get the attributes for this filed */
  unsigned int attr=dbi_result_get_field_attribs_idx(result,idx);
  unsigned int type=dbi_result_get_field_type_idx(result,idx);
  /* return NAN if NULL */
  if(dbi_result_field_is_null_idx(result,idx)) { return DNAN; }
  /* do some conversions */
  switch (type) {
    case DBI_TYPE_STRING:
      ptmp=(char*)dbi_result_get_string_idx(result,idx);
      value=strtod(ptmp,NULL);
      break;
    case DBI_TYPE_INTEGER:
      if        (attr & DBI_INTEGER_SIZE1) { value=dbi_result_get_char_idx(result,idx);
      } else if (attr & DBI_INTEGER_SIZE2) { value=dbi_result_get_short_idx(result,idx);
      } else if (attr & DBI_INTEGER_SIZE3) { value=dbi_result_get_int_idx(result,idx);
      } else if (attr & DBI_INTEGER_SIZE4) { value=dbi_result_get_int_idx(result,idx);
      } else if (attr & DBI_INTEGER_SIZE8) { value=dbi_result_get_longlong_idx(result,idx);
      } else {                               value=DNAN;
        if (getenv("RRDDEBUGSQL")) { fprintf(stderr,"RRDDEBUGSQL: %li: column %i unsupported attribute flags %i for type INTEGER\n",time(NULL),idx,attr ); }
      }
      break;
    case DBI_TYPE_DECIMAL:
      if        (attr & DBI_DECIMAL_SIZE4) { value=dbi_result_get_float_idx(result,idx);
      } else if (attr & DBI_DECIMAL_SIZE8) { value=dbi_result_get_double_idx(result,idx);
      } else {                               value=DNAN;
        if (getenv("RRDDEBUGSQL")) { fprintf(stderr,"RRDDEBUGSQL: %li: column %i unsupported attribute flags %i for type DECIMAL\n",time(NULL),idx,attr ); }
      }
      break;
    case DBI_TYPE_BINARY:
      attr=dbi_result_get_field_length_idx(result,idx);
      ptmp=(char*)dbi_result_get_binary_copy_idx(result,idx);
      ptmp[attr-1]=0;
      /* check for "known" libdbi error */
      if (strncmp("ERROR",ptmp,5)==0) {
	if (!getenv("RRD_NO_LIBDBI_BUG_WARNING")) {
	  fprintf(stderr,"rrdtool_fetch_libDBI: you have possibly triggered a bug in libDBI by using a (TINY,MEDIUM,LONG) TEXT field with mysql\n  this may trigger a core dump in at least one version of libdbi\n  if you are not touched by this bug and you find this message annoying\n  please set the environment-variable RRD_NO_LIBDBI_BUG_WARNING to ignore this message\n");
	}
      }
      /* convert to number */
      value=strtod(ptmp,NULL);
      /* free pointer */
      free(ptmp);
      break;
    case DBI_TYPE_DATETIME:
       value=dbi_result_get_datetime_idx(result,idx);
       break;
    default:
      if (getenv("RRDDEBUGSQL")) { fprintf(stderr,"RRDDEBUGSQL: %li: column %i unsupported type: %i with attribute %i\n",time(NULL),idx,type,attr ); }
      value=DNAN;
      break;
  }
  return value;
}
Exemple #8
0
//*******************************************************************
// Get the results of the MySQL query into our probe_def structure
//*******************************************************************
static void mysql_set_def_fields(trx *t, struct probe_def *probedef, dbi_result result)
{
  struct mysql_def *def = (struct mysql_def *) probedef;

  if (dbi_result_next_row(result)) {
    def->ipaddress = dbi_result_get_string_copy_idx(result, 0);
    def->description = dbi_result_get_string_copy_idx(result, 1);
    def->server   = dbi_result_get_uint_idx(result, 2);
    def->yellow   = dbi_result_get_float_idx(result, 3);
    def->red      = dbi_result_get_float_idx(result, 4);
    def->contact  = dbi_result_get_float_idx(result, 5);
    if (dbi_result_get_string_idx(result, 6)) {
      strcpy(def->hide, dbi_result_get_string_idx(result, 6));
    } else {
      strcpy(def->hide, "no");
    }
    if (dbi_result_get_string_idx(result, 7)) {
      strcpy(def->email, dbi_result_get_string_idx(result, 7));
    } else {
      strcpy(def->email, "");
    }
    if (dbi_result_get_string_idx(result, 8)) {
      strcpy(def->sms, dbi_result_get_string_idx(result, 8));
    } else {
      strcpy(def->sms, "");
    }
    def->delay = dbi_result_get_uint_idx(result, 9);
    def->dbname = dbi_result_get_string_copy_idx(result, 10);
    def->dbuser = dbi_result_get_string_copy_idx(result, 11);
    def->dbpasswd = dbi_result_get_string_copy_idx(result, 12);
    def->query = dbi_result_get_string_copy_idx(result, 13);
  }
}
Exemple #9
0
const char *dbi_result_get_string(dbi_result Result, const char *fieldname) {
  const char *ERROR = "ERROR";
  unsigned int fieldidx;
  dbi_error_flag errflag;

  fieldidx = _find_field(RESULT, fieldname, &errflag);
  if (errflag != DBI_ERROR_NONE) {
    dbi_conn_t *conn = RESULT->conn;
    _error_handler(conn, DBI_ERROR_BADNAME);
    return ERROR;
  }
  return dbi_result_get_string_idx(Result, fieldidx+1);
}
Exemple #10
0
/**
 * SQL callback. Return an integer from a query
 *
 * @param return_integer integer pointer cast to void* which holds the integer to be returned
 * @param result dbi_result pointer
 * @return 0 (always, due to SQLite policy, may change in the future)
 */
int tagsistant_return_integer(void *return_integer, dbi_result result)
{
	uint32_t *buffer = (uint32_t *) return_integer;
	*buffer = 0;

	unsigned int type = dbi_result_get_field_type_idx(result, 1);
	if (type == DBI_TYPE_INTEGER) {
		unsigned int size = dbi_result_get_field_attribs_idx(result, 1);
		unsigned int is_unsigned = size & DBI_INTEGER_UNSIGNED;
		size = size & DBI_INTEGER_SIZEMASK;
		switch (size) {
			case DBI_INTEGER_SIZE8:
				if (is_unsigned)
					*buffer = dbi_result_get_ulonglong_idx(result, 1);
				else
					*buffer = dbi_result_get_longlong_idx(result, 1);
				break;
			case DBI_INTEGER_SIZE4:
			case DBI_INTEGER_SIZE3:
				if (is_unsigned)
					*buffer = dbi_result_get_uint_idx(result, 1);
				else
					*buffer = dbi_result_get_int_idx(result, 1);
				break;
			case DBI_INTEGER_SIZE2:
				if (is_unsigned)
					*buffer = dbi_result_get_ushort_idx(result, 1);
				else
					*buffer = dbi_result_get_short_idx(result, 1);
				break;
			case DBI_INTEGER_SIZE1:
				if (is_unsigned)
					*buffer = dbi_result_get_uchar_idx(result, 1);
				else
					*buffer = dbi_result_get_char_idx(result, 1);
				break;
		}
	} else if (type == DBI_TYPE_DECIMAL) {
		return (0);
	} else if (type == DBI_TYPE_STRING) {
		const gchar *int_string = dbi_result_get_string_idx(result, 1);
		*buffer = atoi(int_string);
		dbg('s', LOG_INFO, "tagsistant_return_integer called on non integer field");
	}

	dbg('s', LOG_INFO, "Returning integer: %d", *buffer);

	return (0);
}
static StrVec
conn_get_table_list (dbi_conn conn, const std::string& dbname,
                     const std::string& table)
{
    StrVec retval;
    const char* tableptr = (table.empty() ? nullptr : table.c_str());
    auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), tableptr);
    while (dbi_result_next_row (tables) != 0)
    {
        std::string table_name {dbi_result_get_string_idx (tables, 1)};
        retval.push_back(table_name);
    }
    dbi_result_free (tables);
    return retval;
}
Exemple #12
0
/* checks mysql sql_options and adjusts if necessary */
static void
adjust_sql_options (dbi_conn connection)
{
    dbi_result result = dbi_conn_query( connection, "SELECT @@sql_mode");
    if (result == nullptr)
    {
        const char* errmsg;
        int err = dbi_conn_error(connection, &errmsg);
        PERR("Unable to read sql_mode %d : %s", err, errmsg);
        return;
    }
    dbi_result_first_row(result);
    std::string str{dbi_result_get_string_idx(result, 1)};
    dbi_result_free(result);
    if (str.empty())
    {
        const char* errmsg;
        int err = dbi_conn_error(connection, &errmsg);
	if (err)
	    PERR("Unable to get sql_mode %d : %s", err, errmsg);
	else
	    PINFO("Sql_mode isn't set.");
        return;
    }
    PINFO("Initial sql_mode: %s", str.c_str());
    if(str.find(SQL_OPTION_TO_REMOVE) == std::string::npos)
        return;

    std::string adjusted_str{adjust_sql_options_string(str)};
    PINFO("Setting sql_mode to %s", adjusted_str.c_str());
    std::string set_str{"SET sql_mode=" + std::move(adjusted_str)};
    dbi_result set_result = dbi_conn_query(connection,
                                           set_str.c_str());
    if (set_result)
    {
        dbi_result_free(set_result);
    }
    else
    {
        const char* errmsg;
        int err = dbi_conn_error(connection, &errmsg);
        PERR("Unable to set sql_mode %d : %s", err, errmsg);
    }
}
Exemple #13
0
int dbiw_res_get_string_ndx(db_wrap_result * self, unsigned int ndx, char const ** val, size_t * len)
{
	RES_DECL(DB_WRAP_E_BAD_ARG);
	if (! val) return DB_WRAP_E_BAD_ARG;
	char const * str = dbi_result_get_string_idx(dbires, ndx +1);
	if (len)
	{
		*len = (str && *str) ? strlen(str) : 0;
	}
	if (!str || (0==strcmp("ERROR",str)))
	{
		/* libdbi is JUST WRONG here. The convention of using the string
		   "ERROR" to report an error is downright broken, because it
		   prohibits that string as a value in my db.
		*/
		return DB_WRAP_E_CHECK_DB_ERROR;
	}
	*val = str;
	return 0;
}
template<> StrVec
GncDbiProviderImpl<DbType::DBI_SQLITE>::get_index_list (dbi_conn conn)
{
    StrVec retval;
    const char* errmsg;
    dbi_result result = dbi_conn_query (conn,
                                        "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'");
    if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
    {
        PWARN ("Index Table Retrieval Error: %s\n", errmsg);
        return retval;
    }
    while (dbi_result_next_row (result) != 0)
    {
        std::string index_name {dbi_result_get_string_idx (result, 1)};
        retval.push_back(index_name);
    }
    dbi_result_free (result);
    return retval;
}
template<> StrVec
GncDbiProviderImpl<DbType::DBI_PGSQL>::get_index_list (dbi_conn conn)
{
    StrVec retval;
    const char* errmsg;
    PINFO ("Retrieving postgres index list\n");
    auto result = dbi_conn_query (conn,
                                  "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'");
    if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
    {
        PWARN("Index Table Retrieval Error: %s\n", errmsg);
        return retval;
    }
    while (dbi_result_next_row (result) != 0)
    {
        std::string index_name {dbi_result_get_string_idx (result, 1)};
        retval.push_back(index_name);
    }
    dbi_result_free (result);
    return retval;
}
static SelectItem* constructSelectItem( BuildSQLState* state, dbi_result result ) {

	// Get the column values
	int id                   = dbi_result_get_int_idx( result, 1 );
	int stored_query_id      = dbi_result_get_int_idx( result, 2 );
	int seq_no               = dbi_result_get_int_idx( result, 3 );
	int expression_id        = dbi_result_get_int_idx( result, 4 );
	const char* column_alias = dbi_result_get_string_idx( result, 5 );
	int grouped_by           = oils_result_get_bool_idx( result, 6 );
	
	// Construct an Expression
	Expression* expression = getExpression( state, expression_id );
	if( !expression ) {
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to fetch expression for id = %d", expression_id ));
		return NULL;
	};

	// Allocate a SelectItem: from the free list if possible, from the heap if necessary

	SelectItem* sel;
	if( free_select_item_list ) {
		sel = free_select_item_list;
		free_select_item_list = free_select_item_list->next;
	} else
		sel = safe_malloc( sizeof( SelectItem ) );

	sel->next            = NULL;
	sel->id              = id;
	sel->stored_query_id = stored_query_id;
	sel->seq_no          = seq_no;
	sel->expression      = expression;
	sel->column_alias    = column_alias ? strdup( column_alias ) : NULL;
	sel->grouped_by      = grouped_by;

	return sel;
}
Exemple #17
0
const char *SMSDDBI_GetString(GSM_SMSDConfig * Config, SQL_result *res, unsigned int col)
{
	return dbi_result_get_string_idx(res->dbi, col+1);
}
static StoredQ* constructStoredQ( BuildSQLState* state, dbi_result result ) {

	// Get the column values from the result
	int id               = dbi_result_get_int_idx( result, 1 );
	const char* type_str = dbi_result_get_string_idx( result, 2 );

	QueryType type;
	if( !strcmp( type_str, "SELECT" ))
		type = QT_SELECT;
	else if( !strcmp( type_str, "UNION" ))
		type = QT_UNION;
	else if( !strcmp( type_str, "INTERSECT" ))
		type = QT_INTERSECT;
	else if( !strcmp( type_str, "EXCEPT" ))
		type = QT_EXCEPT;
	else {
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
			"Invalid query type \"%s\"", type_str ));
		return NULL;
	}

	int use_all             = oils_result_get_bool_idx( result, 3 );
	int use_distinct        = oils_result_get_bool_idx( result, 4 );

	int from_clause_id;
	if( dbi_result_field_is_null_idx( result, 5 ) )
		from_clause_id = -1;
	else
		from_clause_id = dbi_result_get_int_idx( result, 5 );

	int where_clause_id;
	if( dbi_result_field_is_null_idx( result, 6 ) )
		where_clause_id = -1;
	else
		where_clause_id = dbi_result_get_int_idx( result, 6 );

	int having_clause_id;
	if( dbi_result_field_is_null_idx( result, 7 ) )
		having_clause_id = -1;
	else
		having_clause_id = dbi_result_get_int_idx( result, 7 );

	FromRelation* from_clause = NULL;
	if( QT_SELECT == type ) {
		// A SELECT query needs a FROM clause; go get it
		if( from_clause_id != -1 ) {
			from_clause = getFromRelation( state, from_clause_id );
			if( !from_clause ) {
				osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to construct FROM clause for id = %d", from_clause_id ));
				return NULL;
			}
		}
	} else {
		// Must be one of UNION, INTERSECT, or EXCEPT
		if( from_clause_id != -1 )
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"FROM clause found and ignored for %s query in query #%d", type_str, id ));
	}

	// If this is a SELECT query, we need a SELECT list.  Go get one.
	SelectItem* select_list = NULL;
	QSeq* child_list = NULL;
	if( QT_SELECT == type ) {
		select_list = getSelectList( state, id );
		if( !select_list ) {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"No SELECT list found for query id = %d", id ));
			fromRelationFree( from_clause );
			return NULL;
		}
	} else {
		// Construct child queries of UNION, INTERSECT, or EXCEPT query
		child_list = loadChildQueries( state, id, type_str );
		if( !child_list ) {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"Unable to load child queries for %s query # %d", type_str, id ));
			state->error = 1;
			fromRelationFree( from_clause );
			return NULL;
		}
	}

	// Get the WHERE clause, if there is one
	Expression* where_clause = NULL;
	if( where_clause_id != -1 ) {
		where_clause = getExpression( state, where_clause_id );
		if( ! where_clause ) {
			// shouldn't happen due to foreign key constraint
			osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
				"Unable to fetch WHERE expression for query id = %d", id ));
			freeQSeqList( child_list );
			fromRelationFree( from_clause );
			selectListFree( select_list );
			return NULL;
		}
	}

	// Get the ORDER BY clause, if there is one
	OrderItem* order_by_list = getOrderByList( state, id );
	if( state->error ) {
		osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to load ORDER BY clause for query %d", id ));
		expressionFree( where_clause );
		freeQSeqList( child_list );
		fromRelationFree( from_clause );
		selectListFree( select_list );
		return NULL;
	}
	
	// Allocate a StoredQ: from the free list if possible, from the heap if necessary

	StoredQ* sq;
	if( free_storedq_list ) {
		sq = free_storedq_list;
		free_storedq_list = free_storedq_list->next;
	} else
		sq = safe_malloc( sizeof( StoredQ ) );

	// Populate the StoredQ
	sq->next = NULL;
	sq->id = id;

	sq->type = type;
	sq->use_all = use_all;
	sq->use_distinct = use_distinct;
	sq->from_clause = from_clause;
	sq->where_clause = where_clause;
	sq->select_list = select_list;
	sq->child_list = child_list;
	sq->order_by_list = order_by_list;

	return sq;
}
static FromRelation* constructFromRelation( BuildSQLState* state, dbi_result result ) {
	// Get the column values from the result
	int id                  = dbi_result_get_int_idx( result, 1 );
	const char* type_str    = dbi_result_get_string_idx( result, 2 );

	FromRelationType type;
	if( !strcmp( type_str, "RELATION" ))
		type = FRT_RELATION;
	else if( !strcmp( type_str, "SUBQUERY" ))
		type = FRT_SUBQUERY;
	else if( !strcmp( type_str, "FUNCTION" ))
		type = FRT_FUNCTION;
	else
		type = FRT_RELATION;     // shouldn't happen due to database constraint

	const char* table_name  = dbi_result_get_string_idx( result, 3 );
	const char* class_name  = dbi_result_get_string_idx( result, 4 );

	int subquery_id;
	if( dbi_result_field_is_null_idx( result, 5 ) )
		subquery_id          = -1;
	else
		subquery_id          = dbi_result_get_int_idx( result, 5 );

	int function_call_id;
	if( dbi_result_field_is_null_idx( result, 6 ) )
		function_call_id     = -1;
	else
		function_call_id     = dbi_result_get_int_idx( result, 6 );

	const char* table_alias  = dbi_result_get_string_idx( result, 7 );

	int parent_relation_id;
	if( dbi_result_field_is_null_idx( result, 8 ) )
		parent_relation_id   = -1;
	else
		parent_relation_id   = dbi_result_get_int_idx( result, 8 );

	int seq_no               = dbi_result_get_int_idx( result, 9 );

	JoinType join_type;
	const char* join_type_str = dbi_result_get_string_idx( result, 10 );
	if( !join_type_str )
		join_type = JT_NONE;
	else if( !strcmp( join_type_str, "INNER" ) )
		join_type = JT_INNER;
	else if( !strcmp( join_type_str, "LEFT" ) )
		join_type = JT_LEFT;
	else if( !strcmp( join_type_str, "RIGHT" ) )
		join_type = JT_RIGHT;
	else if( !strcmp( join_type_str, "FULL" ) )
		join_type = JT_FULL;
	else
		join_type = JT_NONE;     // shouldn't happen due to database constraint

	int on_clause_id;
	if( dbi_result_field_is_null_idx( result, 11 ) )
		on_clause_id   = -1;
	else
		on_clause_id   = dbi_result_get_int_idx( result, 11 );

	StoredQ* subquery = NULL;

	switch ( type ) {
		case FRT_RELATION :
			break;
		case FRT_SUBQUERY :
			if( -1 == subquery_id ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Internal error: no subquery specified for FROM relation # %d", id ));
				state->error = 1;
				return NULL;
			}
			if( ! table_alias ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Subquery needs alias in FROM relation # %d", id ));
				state->error = 1;
				return NULL;
			}
			subquery = getStoredQuery( state, subquery_id );
			if( ! subquery ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to load subquery for FROM relation # %d", id ));
				state->error = 1;
				return NULL;
			}
			break;
		case FRT_FUNCTION :
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"Functions in FROM clause not yet supported" ));
			state->error = 1;
			return NULL;
	}

	FromRelation* join_list = getJoinList( state, id );
	if( state->error ) {
		osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to load join list for FROM relation # %d", id ));
		return NULL;
	}

	Expression* on_clause = NULL;
	if( on_clause_id != -1 ) {
		on_clause = getExpression( state, on_clause_id );
		if( !on_clause ) {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"Unable to load ON condition for FROM relation # %d", id ));
			joinListFree( join_list );
			return NULL;
		}
		else
			PRINT( "\tGot an ON condition\n" );
	}

	// Allocate a FromRelation: from the free list if possible, from the heap if necessary

	FromRelation* fr;
	if( free_from_relation_list ) {
		fr = free_from_relation_list;
		free_from_relation_list = free_from_relation_list->next;
	} else
		fr = safe_malloc( sizeof( FromRelation ) );

	// Populate the FromRelation

	fr->next = NULL;
	fr->id = id;
	fr->type = type;
	fr->table_name = table_name ? strdup( table_name ) : NULL;
	fr->class_name = class_name ? strdup( class_name ) : NULL;
	fr->subquery_id = subquery_id;
	fr->subquery = subquery;
	fr->function_call_id = function_call_id;
	fr->table_alias = table_alias ? strdup( table_alias ) : NULL;
	fr->parent_relation_id = parent_relation_id;
	fr->seq_no = seq_no;
	fr->join_type = join_type;
	fr->on_clause = on_clause;
	fr->join_list = join_list;

	return fr;
}
static Expression* constructExpression( BuildSQLState* state, dbi_result result ) {

	int id = dbi_result_get_int_idx( result, 1 );
	const char* type_str = dbi_result_get_string_idx( result, 2 );
	
	ExprType type;
	if( !strcmp( type_str, "xbet" ))
		type = EXP_BETWEEN;
	else if( !strcmp( type_str, "xbool" ))
		type = EXP_BOOL;
	else if( !strcmp( type_str, "xcase" ))
		type = EXP_CASE;
	else if( !strcmp( type_str, "xcast" ))
		type = EXP_CAST;
	else if( !strcmp( type_str, "xcol" ))
		type = EXP_COLUMN;
	else if( !strcmp( type_str, "xex" ))
		type = EXP_EXIST;
	else if( !strcmp( type_str, "xfld" ))
		type = EXP_FIELD;
	else if( !strcmp( type_str, "xfunc" ))
		type = EXP_FUNCTION;
	else if( !strcmp( type_str, "xin" ))
		type = EXP_IN;
	else if( !strcmp( type_str, "xnbet" ))
		type = EXP_NOT_BETWEEN;
	else if( !strcmp( type_str, "xnex" ))
		type = EXP_NOT_EXIST;
	else if( !strcmp( type_str, "xnin" ))
		type = EXP_NOT_IN;
	else if( !strcmp( type_str, "xnull" ))
		type = EXP_NULL;
	else if( !strcmp( type_str, "xnum" ))
		type = EXP_NUMBER;
	else if( !strcmp( type_str, "xop" ))
		type = EXP_OPERATOR;
	else if( !strcmp( type_str, "xstr" ))
		type = EXP_STRING;
	else if( !strcmp( type_str, "xsubq" ))
		type = EXP_SUBQUERY;
	else
		type = EXP_NULL;     // shouldn't happen due to database constraint

	int parenthesize = oils_result_get_bool_idx( result, 3 );

	int parent_expr_id;
	if( dbi_result_field_is_null_idx( result, 4 ))
		parent_expr_id = -1;
	else
		parent_expr_id = dbi_result_get_int_idx( result, 4 );
	
	int seq_no = dbi_result_get_int_idx( result, 5 );
	const char* literal = dbi_result_get_string_idx( result, 6 );
	const char* table_alias = dbi_result_get_string_idx( result, 7 );
	const char* column_name = dbi_result_get_string_idx( result, 8 );

	int left_operand_id;
	if( dbi_result_field_is_null_idx( result, 9 ))
		left_operand_id = -1;
	else
		left_operand_id = dbi_result_get_int_idx( result, 9 );

	const char* operator = dbi_result_get_string_idx( result, 10 );

	int right_operand_id;
	if( dbi_result_field_is_null_idx( result, 11 ))
		right_operand_id = -1;
	else
		right_operand_id = dbi_result_get_int_idx( result, 11 );

	int function_id;
	if( dbi_result_field_is_null_idx( result, 12 ))
		function_id = -1;
	else
		function_id = dbi_result_get_int_idx( result, 12 );

	int subquery_id;
	if( dbi_result_field_is_null_idx( result, 13 ))
		subquery_id = -1;
	else
		subquery_id = dbi_result_get_int_idx( result, 13 );

	int cast_type_id;
	if( dbi_result_field_is_null_idx( result, 14 ))
		cast_type_id = -1;
	else
		cast_type_id = dbi_result_get_int_idx( result, 14 );

	Expression* left_operand = NULL;
	Expression* right_operand = NULL;
	StoredQ* subquery = NULL;

	if( EXP_OPERATOR == type ) {
		// Load left and/or right operands
		if( -1 == left_operand_id && -1 == right_operand_id ) {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"Expression # %d is an operator with no operands", id ));
			state->error = 1;
			return NULL;
		}

		if( left_operand_id != -1 ) {
			left_operand = getExpression( state, left_operand_id );
			if( !left_operand ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to get left operand in expression # %d", id ));
				state->error = 1;
				return NULL;
			}
		}

		if( right_operand_id != -1 ) {
			right_operand = getExpression( state, right_operand_id );
			if( !right_operand ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to get right operand in expression # %d", id ));
				state->error = 1;
				expressionFree( left_operand );
				return NULL;
			}
		}
	} else if( EXP_IN == type ) {
		if( -1 == left_operand_id ) {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"IN condition has no left operand in expression # %d", id ));
			state->error = 1;
			return NULL;
		} else {
			left_operand = getExpression( state, left_operand_id );
			if( !left_operand ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to get left operand for IN condition in expression # %d", id ));
				state->error = 1;
				return NULL;
			}
		}

		if( -1 == subquery_id ) {
			// To do: load IN list of subexpressions
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"IN lists not yet supported for expression # %d", id ));
			state->error = 1;
			return NULL;
		} else {
			subquery = getStoredQuery( state, subquery_id );
			if( !subquery ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to load subquery for IN expression # %d", id ));
				state->error = 1;
				return NULL;
			}
		}
	} else if( EXP_EXIST == type ) {
		if( -1 == subquery_id ) {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"Internal error: No subquery found for EXIST expression # %d", id ));
			state->error = 1;
			return NULL;
		} else {
			subquery = getStoredQuery( state, subquery_id );
			if( !subquery ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to load subquery for EXIST expression # %d", id ));
				state->error = 1;
				return NULL;
			}
		}
	} else if( EXP_SUBQUERY == type ) {
		if( -1 == subquery_id ) {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"Subquery expression # %d has no query id", id ));
			state->error = 1;
			return NULL;
		} else {
			// Load a subquery, if there is one
			subquery = getStoredQuery( state, subquery_id );
			if( !subquery ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to load subquery for expression # %d", id ));
				state->error = 1;
				return NULL;
			}
			if( subquery->select_list && subquery->select_list->next ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"Subquery # %d as expression returns more than one column", subquery_id ));
				state->error = 1;
				return NULL;
			}
			PRINT( "\tExpression is subquery %d\n", subquery_id );
		}
	}

	// Allocate an Expression: from the free list if possible, from the heap if necessary
	Expression* exp = NULL;
	if( free_expression_list ) {
		exp = free_expression_list;
		free_expression_list = free_expression_list->next;
	} else
		exp = safe_malloc( sizeof( Expression ) );

	// Populate the Expression
	exp->next = NULL;
	exp->id = id;
	exp->type = type;
	exp->parenthesize = parenthesize;
	exp->parent_expr_id = parent_expr_id;
	exp->seq_no = seq_no;
	exp->literal = literal ? strdup( literal ) : NULL;
	exp->table_alias = table_alias ? strdup( table_alias ) : NULL;
	exp->column_name = column_name ? strdup( column_name ) : NULL;
	exp->left_operand = left_operand;
	exp->op = operator ? strdup( operator ) : NULL;
	exp->right_operand = right_operand;
	exp->function_id = function_id;
	exp->subquery_id = subquery_id;
	exp->subquery = subquery;
	exp->cast_type_id = subquery_id;

	return exp;
}