class Item_POS;
class Item_URI;
class Item_variable;
class Item_blank_node;
class Item_POS_string;
class Item_POS_int;
class Item_POS_decimal;
class Item_POS_float;
class Alias_info;
class GraphContext;
class BindingGraphContext;
class RootGraphContext;

class sparqlFrob {
private:
  void* parser;
  List<Item_URI> uris;
  List<Item_variable> variables;
  List<Item_blank_node> blank_nodes;
  List<Item_POS_string> strings;
  List<Item_POS_int> ints;
  List<Item_POS_decimal> decimals;
  List<Item_POS_float> floats;
  List<Item_POS> subjects;
  List<Item_POS> predicates;
  List<GraphContext> contexts;
  List<Item> root_constraints;
  List<List<BindingGraphContext> > need_selects;
  bool distinct;
  GraphContext *last_graph_context;
  GraphContext *next_graph_context;
  byte next_union_alias_index;

public:
  sparqlFrob(THD *thd, char** ptr);
  ~sparqlFrob();
  int parse();

  Item_variable* ensure_variable (const char *var);
  Item_URI* ensure_URI (LEX_STRING uristr);
  Item_blank_node* make_blank_node ();
  Item_blank_node* ensure_blank_node (const char *label);
  Item_POS_string* ensure_string (LEX_STRING str, Item_POS *lang_or_datatype);
  Item_POS_int* ensure_int (LEX_STRING str, Item_POS *lang_or_datatype);
  Item_POS_decimal* ensure_decimal (LEX_STRING str, Item_POS *lang_or_datatype);
  Item_POS_float* ensure_float (LEX_STRING str, Item_POS *lang_or_datatype);
  void push_subject (Item_POS *subject);
  Item_POS* pop_subject ();
  void push_predicate (Item_POS *predicate);
  void pop_predicate ();
  bool object (Item_POS *object);
  bool type_list ();
  bool add_listElement (Item_POS  *item);
  const char* get_primary_key(const char *table_name);
  void push_context(GraphContext *gc) {contexts.push_front(gc);}
  GraphContext* head_context() {return contexts.head();}
  GraphContext* pop_context() {return last_graph_context = contexts.pop();}
  void add_root_constraints (Item *constraint) {
    if (constraint)
      root_constraints.push_front(constraint);
  }
  Item* get_root_constraints () {
    return root_constraints.elements == 0 ? 
      NULL : 
      root_constraints.elements == 1 ? 
      root_constraints.pop() : 
      new Item_cond_and(root_constraints);
  }
  void needs_select (List<BindingGraphContext> *contexts) {
    need_selects.push_back(contexts); // Must iterate backwards through list.
  }
  void select_variables();
  void set_distinct (bool distinct_parm) {distinct= distinct_parm;}
  bool get_distinct () {return distinct;}
  GraphContext *last_context () {return last_graph_context;}
  void set_next_GC (GraphContext *gc) {next_graph_context= gc;}
  GraphContext *was_next_GC () {GraphContext *ret= next_graph_context; next_graph_context= NULL; return ret;}
  LEX_STRING* next_union_alias ();

  THD *thd;
  LEX *lex;
};
