예제 #1
0
/**
	@brief Load the child queries subordinate to a UNION, INTERSECT, or EXCEPT query.
	@param state Pointer to the query-building context.
	@param parent ID of the UNION, INTERSECT, or EXCEPT query.
	@param type_str The type of the query ("UNION", "INTERSECT", or "EXCEPT").
	@return If successful, a pointer to a linked list of QSeq, each bearing a pointer to a
		StoredQ; otherwise NULL.

	The @a type_str parameter is used only for building error messages.
*/
static QSeq* loadChildQueries( BuildSQLState* state, int parent_id, const char* type_str ) {
	QSeq* child_list = NULL;
	
	// The ORDER BY is in descending order so that we can build the list by adding to
	// the head, and it will wind up in the right order.
	dbi_result result = dbi_conn_queryf( state->dbhandle,
		"SELECT id, parent_query, seq_no, child_query "
		"FROM query.query_sequence WHERE parent_query = %d ORDER BY seq_no DESC", parent_id );
	if( result ) {
		if( dbi_result_first_row( result ) ) {
			int count = 0;
			while( 1 ) {
				++count;
				QSeq* seq = constructQSeq( state, result );
				if( seq ) {
					PRINT( "Found a child query\n" );
					PRINT( "\tid: %d\n", seq->id );
					PRINT( "\tparent id: %d\n", seq->parent_query_id );
					PRINT( "\tseq_no: %d\n", seq->seq_no );
					// Add to the head of the list
					seq->next = child_list;
					child_list = seq;
				} else{
					freeQSeqList( child_list );
					return NULL;
				}
				if( !dbi_result_next_row( result ))
					break;
			}
			if( count < 2 ) {
				osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
					"%s query # %d has only one child query", type_str, parent_id ));
				state->error = 1;
				freeQSeqList( child_list );
				return NULL;
			}
		} else {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"%s query # %d has no child queries within it", type_str, parent_id ));
			state->error = 1;
			return NULL;
		}
	} else {
		const char* msg;
		int errnum = dbi_conn_error( state->dbhandle, &msg );
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to query query.query_sequence table: # %d %s",
			errnum, msg ? msg : "No description available" ));
		state->error = 1;
		return NULL;
	}

	return child_list;
}
예제 #2
0
/**
	@brief Load a stored query.
	@param state Pointer to the query-building context.
	@param query_id ID of the query in query.stored_query.
	@return A pointer to the newly loaded StoredQ if successful, or NULL if not.

	The calling code is responsible for freeing the StoredQ by calling storedQFree().
*/
StoredQ* getStoredQuery( BuildSQLState* state, int query_id ) {
	if( !state )
		return NULL;

	// Check the stack to see if the current query is nested inside itself.  If it is, then
	// abort in order to avoid infinite recursion.  If it isn't, then add it to the stack.
	// (Make sure to pop it off the stack before returning.)
	if( searchIdStack( state->query_stack, query_id, NULL )) {
		osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
			"Infinite recursion detected; query # %d is nested within itself", query_id ));
		state->error = 1;
		return NULL;
	} else
		push_id( &state->query_stack, query_id, NULL );

	StoredQ* sq = NULL;
	dbi_result result = dbi_conn_queryf( state->dbhandle,
		"SELECT id, type, use_all, use_distinct, from_clause, where_clause, having_clause "
		"FROM query.stored_query WHERE id = %d;", query_id );
	if( result ) {
		if( dbi_result_first_row( result ) ) {
			sq = constructStoredQ( state, result );
			if( sq ) {
				PRINT( "Got a query row\n" );
				PRINT( "\tid: %d\n", sq->id );
				PRINT( "\ttype: %d\n", (int) sq->type );
				PRINT( "\tuse_all: %s\n", sq->use_all ? "true" : "false" );
				PRINT( "\tuse_distinct: %s\n", sq->use_distinct ? "true" : "false" );
			} else
				osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to build a query for id = %d", query_id ));
		} else {
			sqlAddMsg( state, "Stored query not found for id %d", query_id );
		}

		dbi_result_free( result );
	} else {
		const char* msg;
		int errnum = dbi_conn_error( state->dbhandle, &msg );
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state, 
			"Unable to query query.stored_query table: #%d %s",
			errnum, msg ? msg : "No description available" ));
	}

	pop_id( &state->query_stack );
	return sq;
}
예제 #3
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);
    }
}
예제 #4
0
static SelectItem* getSelectList( BuildSQLState* state, int query_id ) {
	SelectItem* select_list = NULL;

	// The ORDER BY is in descending order so that we can build the list by adding to
	// the head, and it will wind up in the right order.
	dbi_result result = dbi_conn_queryf( state->dbhandle,
		"SELECT id, stored_query, seq_no, expression, column_alias, grouped_by "
		"FROM query.select_item WHERE stored_query = %d ORDER BY seq_no DESC", query_id );
	if( result ) {
		if( dbi_result_first_row( result ) ) {
			while( 1 ) {
				SelectItem* item = constructSelectItem( state, result );
				if( item ) {
					PRINT( "Found a SELECT item\n" );
					PRINT( "\tid: %d\n", item->id );
					PRINT( "\tstored_query_id: %d\n", item->stored_query_id );
					PRINT( "\tseq_no: %d\n", item->seq_no );
					PRINT( "\tcolumn_alias: %s\n",
							item->column_alias ? item->column_alias : "(none)" );
					PRINT( "\tgrouped_by: %d\n", item->grouped_by );

					item->next = select_list;
					select_list = item;
				} else {
					osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
						"Unable to build select list for query id #%d", query_id ));
					selectListFree( select_list );
					select_list = NULL;
					break;
				}
				if( !dbi_result_next_row( result ) )
					break;
			};
		}
	} else {
		const char* msg;
		int errnum = dbi_conn_error( state->dbhandle, &msg );
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
					  "Unable to query query.select_list table: #%d %s",
					  errnum, msg ? msg : "No description available" ));
	}

	return select_list;
}
예제 #5
0
static Expression* getExpression( BuildSQLState* state, int id ) {
	
	// Check the stack to see if the current expression is nested inside itself.  If it is,
	// then abort in order to avoid infinite recursion.  If it isn't, then add it to the
	// stack.  (Make sure to pop it off the stack before returning.)
	if( searchIdStack( state->expr_stack, id, NULL )) {
		osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
			"Infinite recursion detected; expression # %d is nested within itself", id ));
		state->error = 1;
		return NULL;
	} else
		push_id( &state->expr_stack, id, NULL );

		Expression* exp = NULL;
	dbi_result result = dbi_conn_queryf( state->dbhandle,
		"SELECT id, type, parenthesize, parent_expr, seq_no, literal, table_alias, "
		"column_name, left_operand, operator, right_operand, function_id, subquery, cast_type "
		"FROM query.expression WHERE id = %d;", id );
	if( result ) {
		if( dbi_result_first_row( result ) ) {
			exp = constructExpression( state, result );
			if( exp ) {
				PRINT( "Got an expression\n" );
				PRINT( "\tid = %d\n", exp->id );
				PRINT( "\ttype = %d\n", exp->type );
				PRINT( "\tparenthesize = %d\n", exp->parenthesize );
				PRINT( "\tcolumn_name = %s\n", exp->column_name ? exp->column_name : "(none)" );
			} else 
				osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to construct an Expression for id = %d", id ));
		}
	} else {
		const char* msg;
		int errnum = dbi_conn_error( state->dbhandle, &msg );
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to query query.expression table: #%d %s",
			errnum, msg ? msg : "No description available" ));
	}

	pop_id( &state->expr_stack );
	return exp;
}
예제 #6
0
/**
	@brief Build a list of joined relations.
	@param state Pointer to the query-building context.
	@param id ID of the parent relation.
	@return A pointer to the first in a linked list of FromRelations, if there are any; or
		NULL if there aren't any, or in case of an error.

	Look for relations joined directly to the parent relation, and make a list of them.
*/
static FromRelation* getJoinList( BuildSQLState* state, int id ) {
	FromRelation* join_list = NULL;
	
	// The ORDER BY is in descending order so that we can build the list by adding to
	// the head, and it will wind up in the right order.
	dbi_result result = dbi_conn_queryf( state->dbhandle,
		"SELECT id, type, table_name, class_name, subquery, function_call, "
		"table_alias, parent_relation, seq_no, join_type, on_clause "
		"FROM query.from_relation WHERE parent_relation = %d ORDER BY seq_no DESC", id );

	if( result ) {
		if( dbi_result_first_row( result ) ) {
			while( 1 ) {
				FromRelation* relation = constructFromRelation( state, result );
				if( relation ) {
					PRINT( "Found a joined relation\n" );
					PRINT( "\tjoin_type: %d\n", relation->join_type );
					PRINT( "\ttable_name: %s\n", relation->table_name );
					relation->next = join_list;
					join_list = relation;
				} else {
					osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
						"Unable to build join list for from relation id #%d", id ));
					joinListFree( join_list );
					join_list = NULL;
					break;
				}
				if( !dbi_result_next_row( result ) )
					break;
			};
		}
	} else {
		const char* msg;
		int errnum = dbi_conn_error( state->dbhandle, &msg );
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to query query.from_relation table for join list: #%d %s",
			errnum, msg ? msg : "No description available" ));
	}

	return join_list;
}
예제 #7
0
static OrderItem* getOrderByList( BuildSQLState* state, int query_id ) {
	OrderItem* ord_list = NULL;

	// The ORDER BY is in descending order so that we can build the list by adding to
	// the head, and it will wind up in the right order.
	dbi_result result = dbi_conn_queryf( state->dbhandle,
		"SELECT id, stored_query, seq_no, expression "
		"FROM query.order_by_item WHERE stored_query = %d ORDER BY seq_no DESC", query_id );
	if( result ) {
		if( dbi_result_first_row( result ) ) {
			while( 1 ) {
				OrderItem* item = constructOrderItem( state, result );
				if( item ) {
					PRINT( "Found an ORDER BY item\n" );

					item->next = ord_list;
					ord_list = item;
				} else {
					osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
						"Unable to build ORDER BY item for query id #%d", query_id ));
					orderItemListFree( ord_list );
					ord_list = NULL;
					break;
				}
				if( !dbi_result_next_row( result ) )
					break;
			};
		}
	}  else {
		const char* msg;
		int errnum = dbi_conn_error( state->dbhandle, &msg );
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to query query.order_by_list table: #%d %s",
			errnum, msg ? msg : "No description available" ));
	}

	return ord_list;
}
예제 #8
0
파일: dbi.c 프로젝트: 4thAce/collectd
static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */
    udb_query_t *q, udb_query_preparation_area_t *prep_area)
{
  const char *statement;
  dbi_result res;
  size_t column_num;
  char **column_names;
  char **column_values;
  int status;
  size_t i;

  /* Macro that cleans up dynamically allocated memory and returns the
   * specified status. */
#define BAIL_OUT(status) \
  if (column_names != NULL) { sfree (column_names[0]); sfree (column_names); } \
  if (column_values != NULL) { sfree (column_values[0]); sfree (column_values); } \
  if (res != NULL) { dbi_result_free (res); res = NULL; } \
  return (status)

  column_names = NULL;
  column_values = NULL;

  statement = udb_query_get_statement (q);
  assert (statement != NULL);

  res = dbi_conn_query (db->connection, statement);
  if (res == NULL)
  {
    char errbuf[1024];
    ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
        "dbi_conn_query failed: %s",
        db->name, udb_query_get_name (q),
        cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
    BAIL_OUT (-1);
  }
  else /* Get the number of columns */
  {
    unsigned int db_status;

    db_status = dbi_result_get_numfields (res);
    if (db_status == DBI_FIELD_ERROR)
    {
      char errbuf[1024];
      ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
          "dbi_result_get_numfields failed: %s",
          db->name, udb_query_get_name (q),
          cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
      BAIL_OUT (-1);
    }

    column_num = (size_t) db_status;
    DEBUG ("cdbi_read_database_query (%s, %s): There are %zu columns.",
        db->name, udb_query_get_name (q), column_num);
  }

  /* Allocate `column_names' and `column_values'. {{{ */
  column_names = calloc (column_num, sizeof (*column_names));
  if (column_names == NULL)
  {
    ERROR ("dbi plugin: calloc failed.");
    BAIL_OUT (-1);
  }

  column_names[0] = calloc (column_num, DATA_MAX_NAME_LEN);
  if (column_names[0] == NULL)
  {
    ERROR ("dbi plugin: calloc failed.");
    BAIL_OUT (-1);
  }
  for (i = 1; i < column_num; i++)
    column_names[i] = column_names[i - 1] + DATA_MAX_NAME_LEN;

  column_values = calloc (column_num, sizeof (*column_values));
  if (column_values == NULL)
  {
    ERROR ("dbi plugin: calloc failed.");
    BAIL_OUT (-1);
  }

  column_values[0] = calloc (column_num, DATA_MAX_NAME_LEN);
  if (column_values[0] == NULL)
  {
    ERROR ("dbi plugin: calloc failed.");
    BAIL_OUT (-1);
  }
  for (i = 1; i < column_num; i++)
    column_values[i] = column_values[i - 1] + DATA_MAX_NAME_LEN;
  /* }}} */

  /* Copy the field names to `column_names' */
  for (i = 0; i < column_num; i++) /* {{{ */
  {
    const char *column_name;

    column_name = dbi_result_get_field_name (res, (unsigned int) (i + 1));
    if (column_name == NULL)
    {
      ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
          "Cannot retrieve name of field %zu.",
          db->name, udb_query_get_name (q), i + 1);
      BAIL_OUT (-1);
    }

    sstrncpy (column_names[i], column_name, DATA_MAX_NAME_LEN);
  } /* }}} for (i = 0; i < column_num; i++) */

  udb_query_prepare_result (q, prep_area, (db->host ? db->host : hostname_g),
      /* plugin = */ "dbi", db->name,
      column_names, column_num, /* interval = */ (db->interval > 0) ? db->interval : 0);

  /* 0 = error; 1 = success; */
  status = dbi_result_first_row (res); /* {{{ */
  if (status != 1)
  {
    char errbuf[1024];
    ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
        "dbi_result_first_row failed: %s. Maybe the statement didn't "
        "return any rows?",
        db->name, udb_query_get_name (q),
        cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
    udb_query_finish_result (q, prep_area);
    BAIL_OUT (-1);
  } /* }}} */

  /* Iterate over all rows and call `udb_query_handle_result' with each list of
   * values. */
  while (42) /* {{{ */
  {
    status = 0;
    /* Copy the value of the columns to `column_values' */
    for (i = 0; i < column_num; i++) /* {{{ */
    {
      status = cdbi_result_get_field (res, (unsigned int) (i + 1),
          column_values[i], DATA_MAX_NAME_LEN);

      if (status != 0)
      {
        ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
            "cdbi_result_get_field (%zu) failed.",
            db->name, udb_query_get_name (q), i + 1);
        status = -1;
        break;
      }
    } /* }}} for (i = 0; i < column_num; i++) */

    /* If all values were copied successfully, call `udb_query_handle_result'
     * to dispatch the row to the daemon. */
    if (status == 0) /* {{{ */
    {
      status = udb_query_handle_result (q, prep_area, column_values);
      if (status != 0)
      {
        ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): "
            "udb_query_handle_result failed.",
            db->name, udb_query_get_name (q));
      }
    } /* }}} */

    /* Get the next row from the database. */
    status = dbi_result_next_row (res); /* {{{ */
    if (status != 1)
    {
      if (dbi_conn_error (db->connection, NULL) != 0)
      {
        char errbuf[1024];
        WARNING ("dbi plugin: cdbi_read_database_query (%s, %s): "
            "dbi_result_next_row failed: %s.",
            db->name, udb_query_get_name (q),
            cdbi_strerror (db->connection, errbuf, sizeof (errbuf)));
      }
      break;
    } /* }}} */
  } /* }}} while (42) */

  /* Tell the db query interface that we're done with this query. */
  udb_query_finish_result (q, prep_area);

  /* Clean up and return `status = 0' (success) */
  BAIL_OUT (0);
#undef BAIL_OUT
} /* }}} int cdbi_read_database_query */
예제 #9
0
static FromRelation* getFromRelation( BuildSQLState* state, int id ) {
	FromRelation* fr = NULL;
	dbi_result result = dbi_conn_queryf( state->dbhandle,
		"SELECT id, type, table_name, class_name, subquery, function_call, "
		"table_alias, parent_relation, seq_no, join_type, on_clause "
		"FROM query.from_relation WHERE id = %d;", id );
	if( result ) {
		if( dbi_result_first_row( result ) ) {
			fr = constructFromRelation( state, result );
			if( fr ) {
				PRINT( "Got a from_relation row\n" );
				PRINT( "\tid: %d\n", fr->id );
				PRINT( "\ttype: %d\n", (int) fr->type );
				PRINT( "\ttable_name: %s\n", fr->table_name ? fr->table_name : "(none)" );
				PRINT( "\tclass_name: %s\n", fr->class_name ? fr->class_name : "(none)" );
				PRINT( "\tsubquery_id: %d\n", fr->subquery_id );
				PRINT( "\tfunction_call_id: %d\n", fr->function_call_id );
				PRINT( "\ttable_alias: %s\n", fr->table_alias ? fr->table_alias : "(none)" );
				PRINT( "\tparent_relation_id: %d\n", fr->parent_relation_id );
				PRINT( "\tseq_no: %d\n", fr->seq_no );
				PRINT( "\tjoin_type = %d\n", fr->join_type );
				// Check the stack to see if the current from clause is nested inside itself.
				// If it is, then abort in order to avoid infinite recursion.  If it isn't,
				// then add it to the stack.  (Make sure to pop it off the stack before
				// returning.)
				const char* effective_alias = fr->table_alias;
				if( !effective_alias )
					effective_alias = fr->class_name;
				const IdNode* node = searchIdStack( state->from_stack, id, effective_alias );
				if( node ) {
					if( node->id == id )
						osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
							"Infinite recursion detected; from clause # %d is nested "
							"within itself", id ));
					else
						osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
							"Conflicting nested table aliases \"%s\" in from clause # %d",
							effective_alias, node->id ));
					state->error = 1;
					return NULL;
				} else
					push_id( &state->from_stack, id, effective_alias );
			} else
				osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
					"Unable to build a FromRelation for id = %d", id ));
		} else {
			osrfLogWarning( OSRF_LOG_MARK, sqlAddMsg( state,
				"FROM relation not found for id = %d", id ));
		}
		dbi_result_free( result );
	} else {
		const char* msg;
		int errnum = dbi_conn_error( state->dbhandle, &msg );
		osrfLogError( OSRF_LOG_MARK, sqlAddMsg( state,
			"Unable to query query.from_relation table: #%d %s",
			errnum, msg ? msg : "No description available" ));
	}

	if( fr )
		pop_id( &state->from_stack );

	return fr;
}