int
main(int argc, char *argv[]) 
{
  const char *program = rasqal_basename(argv[0]);
  rasqal_rowsource *rowsource = NULL;
  rasqal_rowsource *left_rs = NULL;
  rasqal_rowsource *right_rs = NULL;
  rasqal_world* world = NULL;
  rasqal_query* query = NULL;
  int count;
  raptor_sequence* seq = NULL;
  int failures = 0;
  rasqal_variables_table* vt;
  int size;
  int expected_size = EXPECTED_COLUMNS_COUNT;
  int i;
  raptor_sequence* vars_seq = NULL;
  int test_count;
  
  world = rasqal_new_world(); rasqal_world_open(world);
  
  query = rasqal_new_query(world, "sparql", NULL);
  
  vt = query->vars_table;

  for(test_count = 0; test_count < JOIN_TESTS_COUNT; test_count++) {
    rasqal_join_type join_type = join_test_config[test_count].join_type;
    int expected_count = join_test_config[test_count].expected;
    int vars_count;

    fprintf(stderr, "%s: test #%d  join type %d\n", program, test_count,
            RASQAL_GOOD_CAST(int, join_type));

    /* 2 variables and 3 rows */
    vars_count = 2;
    seq = rasqal_new_row_sequence(world, vt, join_1_data_2x3_rows, vars_count,
                                  &vars_seq);
    if(!seq) {
      fprintf(stderr,
              "%s: failed to create left sequence of %d vars\n", program,
              vars_count);
      failures++;
      goto tidy;
    }

    left_rs = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
    if(!left_rs) {
      fprintf(stderr, "%s: failed to create left rowsource\n", program);
      failures++;
      goto tidy;
    }
    /* vars_seq and seq are now owned by left_rs */
    vars_seq = seq = NULL;

    /* 3 variables and 2 rows */
    vars_count = 3;
    seq = rasqal_new_row_sequence(world, vt, join_2_data_3x2_rows, vars_count,
                                  &vars_seq);
    if(!seq) {
      fprintf(stderr,
              "%s: failed to create right sequence of %d rows\n", program,
              vars_count);
      failures++;
      goto tidy;
    }

    right_rs = rasqal_new_rowsequence_rowsource(world, query, vt, seq, vars_seq);
    if(!right_rs) {
      fprintf(stderr, "%s: failed to create right rowsource\n", program);
      failures++;
      goto tidy;
    }
    /* vars_seq and seq are now owned by right_rs */
    vars_seq = seq = NULL;

    rowsource = rasqal_new_join_rowsource(world, query, left_rs, right_rs,
                                          join_type, NULL);
    if(!rowsource) {
      fprintf(stderr, "%s: failed to create join rowsource\n", program);
      failures++;
      goto tidy;
    }
    /* left_rs and right_rs are now owned by rowsource */
    left_rs = right_rs = NULL;

    seq = rasqal_rowsource_read_all_rows(rowsource);
    if(!seq) {
      fprintf(stderr,
              "%s: read_rows returned a NULL seq for a join rowsource\n",
              program);
      failures++;
      goto tidy;
    }
    count = raptor_sequence_size(seq);
    if(count != expected_count) {
      fprintf(stderr,
              "%s: read_rows returned %d rows for a join rowsource, expected %d\n",
              program, count, expected_count);
      failures++;
      goto tidy;
    }

    size = rasqal_rowsource_get_size(rowsource);
    if(size != expected_size) {
      fprintf(stderr,
              "%s: read_rows returned %d columns (variables) for a join rowsource, expected %d\n",
              program, size, expected_size);
      failures++;
      goto tidy;
    }
    for(i = 0; i < expected_size; i++) {
      rasqal_variable* v;
      const char* name = NULL;
      const char *expected_name = join_result_vars[i];

      v = rasqal_rowsource_get_variable_by_offset(rowsource, i);
      if(!v) {
        fprintf(stderr,
              "%s: read_rows had NULL column (variable) #%d expected %s\n",
                program, i, expected_name);
        failures++;
        goto tidy;
      }
      name = RASQAL_GOOD_CAST(const char*, v->name);
      if(strcmp(name, expected_name)) {
        fprintf(stderr,
              "%s: read_rows returned column (variable) #%d %s but expected %s\n",
                program, i, name, expected_name);
        failures++;
        goto tidy;
      }
    }

#ifdef RASQAL_DEBUG
    rasqal_rowsource_print_row_sequence(rowsource, seq, DEBUG_FH);
#endif

    raptor_free_sequence(seq); seq = NULL;
    rasqal_free_rowsource(rowsource); rowsource = NULL;
    
    /* end test_count loop */
  }
  
  tidy:
  if(seq)
    raptor_free_sequence(seq);
  if(left_rs)
    rasqal_free_rowsource(left_rs);
  if(right_rs)
    rasqal_free_rowsource(right_rs);
  if(rowsource)
    rasqal_free_rowsource(rowsource);
  if(query)
    rasqal_free_query(query);
  if(world)
    rasqal_free_world(world);

  return failures;
}
int
main(int argc, char *argv[]) 
{
  const char *program = rasqal_basename(argv[0]);
  rasqal_rowsource *rowsource = NULL;
  rasqal_world* world = NULL;
  rasqal_query* query = NULL;
  raptor_sequence* row_seq = NULL;
  raptor_sequence* expr_args_seq = NULL;
  int failures = 0;
  rasqal_variables_table* vt;
  rasqal_rowsource *input_rs = NULL;
  raptor_sequence* vars_seq = NULL;
  raptor_sequence* exprs_seq = NULL;
  int test_id;

  world = rasqal_new_world();
  if(!world || rasqal_world_open(world)) {
    fprintf(stderr, "%s: rasqal_world init failed\n", program);
    return(1);
  }
  
  query = rasqal_new_query(world, "sparql", NULL);

  vt = query->vars_table;
  
  for(test_id = 0; test_id < AGGREGATION_TESTS_COUNT; test_id++) {
    int input_vars_count = test_data[test_id].input_vars;
    int output_rows_count = test_data[test_id].output_rows;
    int output_vars_count = test_data[test_id].output_vars;
    const int* input_group_ids = test_data[test_id].group_ids;
    const int* result_int_data = test_data[test_id].result_data;
    const char* const* result_string_data = test_data[test_id].result_string_data;
    rasqal_op op  = test_data[test_id].op;
    raptor_sequence* seq = NULL;
    int count;
    int size;
    int i;
    char* output_var_name;
    rasqal_variable* output_var;
    rasqal_expression* expr;
    int output_row_size = (input_vars_count + output_vars_count);
    
    if(output_vars_count != 1) {
      fprintf(stderr,
              "%s: test %d expects %d variables which is not supported. Test skipped\n",
              program, test_id, output_vars_count);
      failures++;
      goto tidy;
    }

    row_seq = rasqal_new_row_sequence(world, vt, test_data[test_id].data,
                                      test_data[test_id].input_vars, &vars_seq);
    if(row_seq) {
      for(i = 0; i < test_data[test_id].input_rows; i++) {
        rasqal_row* row = (rasqal_row*)raptor_sequence_get_at(row_seq, i);
        row->group_id = input_group_ids[i];
      }
      
      input_rs = rasqal_new_rowsequence_rowsource(world, query, vt, 
                                                  row_seq, vars_seq);
      /* vars_seq and row_seq are now owned by input_rs */
      vars_seq = row_seq = NULL;
    }
    if(!input_rs) {
      fprintf(stderr, "%s: failed to create rowsequence rowsource\n", program);
      failures++;
      goto tidy;
    }

    expr_args_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_expression,
                                        (raptor_data_print_handler)rasqal_expression_print);

    if(test_data[test_id].expr_agg_vars[0] != NULL) {
      int vindex;
      const unsigned char* var_name;
      
      for(vindex = 0;
          (var_name = (const unsigned char*)test_data[test_id].expr_agg_vars[vindex] );
          vindex++) {
        rasqal_variable* v;
        rasqal_literal *l = NULL;
        rasqal_expression* e = NULL;

        v = rasqal_variables_table_get_by_name(vt, var_name);
        if(v)
          l = rasqal_new_variable_literal(world, v);

        if(l)
          e = rasqal_new_literal_expression(world, l);

        if(e)
          raptor_sequence_push(expr_args_seq, e);
        else {
          fprintf(stderr, "%s: failed to create variable %s\n", program,
                  (const char*)var_name);
          failures++;
          goto tidy;
        }
        
      }
    } /* if vars */


    output_var_name = (char*)RASQAL_MALLOC(cstring, 5);
    memcpy(output_var_name, "fake", 5);
    output_var = rasqal_variables_table_add(vt, RASQAL_VARIABLE_TYPE_ANONYMOUS, 
                                            (const unsigned char*)output_var_name, NULL);

    expr = make_test_expr(world, expr_args_seq, op);
    /* expr_args_seq is now owned by expr */
    expr_args_seq = NULL;

    exprs_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_expression,
                                    (raptor_data_print_handler)rasqal_expression_print);
    raptor_sequence_push(exprs_seq, expr);
    /* expr is now owned by exprs_seq */
    expr = NULL;
    
    vars_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_variable,
                                   (raptor_data_print_handler)rasqal_variable_print);
    output_var = rasqal_new_variable_from_variable(output_var);
    raptor_sequence_push(vars_seq, output_var);

    rowsource = rasqal_new_aggregation_rowsource(world, query, input_rs,
                                                 exprs_seq, vars_seq);
    /* exprs_seq, vars_seq and input_rs are now owned by rowsource */
    exprs_seq = NULL; vars_seq = NULL; input_rs = NULL;

    if(!rowsource) {
      fprintf(stderr, "%s: failed to create aggregation rowsource\n", program);
      failures++;
      goto tidy;
    }


    /* Test the rowsource */
    seq = rasqal_rowsource_read_all_rows(rowsource);
    if(!seq) {
      fprintf(stderr,
              "%s: test %d rasqal_rowsource_read_all_rows() returned a NULL seq for a aggregation rowsource\n",
              program, test_id);
      failures++;
      goto tidy;
    }
    count = raptor_sequence_size(seq);
    if(count != output_rows_count) {
      fprintf(stderr,
              "%s: test %d rasqal_rowsource_read_all_rows() returned %d rows for a aggregation rowsource, expected %d\n",
              program, test_id, count, output_rows_count);
      failures++;
      goto tidy;
    }

    size = rasqal_rowsource_get_size(rowsource);
    if(size != output_row_size) {
      fprintf(stderr,
              "%s: test %d rasqal_rowsource_get_size() returned %d columns (variables) for a aggregation rowsource, expected %d\n",
              program, test_id, size, output_row_size);
      failures++;
      goto tidy;
    }

    if(result_int_data) {
      for(i = 0; i < output_rows_count; i++) {
        rasqal_row* row = (rasqal_row*)raptor_sequence_get_at(seq, i);
        rasqal_literal* value;
        int integer;
        int expected_integer = result_int_data[i];
        int vc;
        
        if(row->size != output_row_size) {
          fprintf(stderr,
                  "%s: test %d row #%d is size %d expected %d\n",
                  program, test_id, i, row->size, output_row_size);
          failures++;
          goto tidy;
        }
        
        /* Expected variable ordering in output row is:
         * {input vars} {output_vars}
         */
        for(vc = 0; vc < output_vars_count; vc++) {
          rasqal_variable* row_var;
          int offset = input_vars_count + vc;
          
          row_var = rasqal_rowsource_get_variable_by_offset(rowsource, offset);
          value = row->values[offset]; 

          if(!value) {
            fprintf(stderr,
                    "%s: test %d row #%d %s value #%d result is NULL\n",
                    program, test_id, i, row_var->name, vc);
            failures++;
            goto tidy;
          }

          if(value->type != RASQAL_LITERAL_INTEGER) {
            fprintf(stderr,
                    "%s: test %d row #%d %s value #%d result is type %s expected integer\n",
                    program, test_id, i, row_var->name, vc,
                    rasqal_literal_type_label(value->type));
            failures++;
            goto tidy;
          }

          integer = rasqal_literal_as_integer(value, NULL);

          if(integer != expected_integer) {
            fprintf(stderr,
                    "%s: test %d row #%d %s value #%d result is %d expected %d\n",
                    program, test_id, i, row_var->name, vc,
                    integer, expected_integer);
            failures++;
            goto tidy;
          }
        }
        
      }
    }
    
    if(result_string_data) {
      for(i = 0; i < output_rows_count; i++) {
        rasqal_row* row = (rasqal_row*)raptor_sequence_get_at(seq, i);
        rasqal_literal* value;
        const unsigned char* str;
        const char* expected_string = result_string_data[i];
        int vc;
        
        if(row->size != output_row_size) {
          fprintf(stderr,
                  "%s: test %d row #%d is size %d expected %d\n",
                  program, test_id, i, row->size, output_row_size);
          failures++;
          goto tidy;
        }
        
        /* Expected variable ordering in output row is:
         * {input vars} {output_vars}
         */
        for(vc = 0; vc < output_vars_count; vc++) {
          rasqal_variable* row_var;
          int offset = input_vars_count + vc;

          row_var = rasqal_rowsource_get_variable_by_offset(rowsource, offset);
          value = row->values[offset]; 

          if(!value) {
            fprintf(stderr,
                    "%s: test %d row #%d %s value #%d result is NULL\n",
                    program, test_id, i, row_var->name, vc);
            failures++;
            goto tidy;
          }

          if(value->type != RASQAL_LITERAL_STRING) {
            fprintf(stderr,
                    "%s: test %d row #%d %s value #%d is type %s expected integer\n",
                    program, test_id, i, row_var->name, vc,
                    rasqal_literal_type_label(value->type));
            failures++;
            goto tidy;
          }

          str = rasqal_literal_as_string(value);

          if(strcmp((const char*)str, expected_string)) {
            fprintf(stderr,
                    "%s: test %d row #%d %s value #%d is %s expected %s\n",
                    program, test_id, i, row_var->name, vc,
                    str, expected_string);
            failures++;
            goto tidy;
          }
        }
        
      }
    }
    

#ifdef RASQAL_DEBUG
    rasqal_rowsource_print_row_sequence(rowsource, seq, stderr);
#endif

    raptor_free_sequence(seq); seq = NULL;

    rasqal_free_rowsource(rowsource); rowsource = NULL;

    if(expr_args_seq)
      raptor_free_sequence(expr_args_seq);
    expr_args_seq = NULL;
  }
  
  
  tidy:
  if(exprs_seq)
    raptor_free_sequence(exprs_seq);
  if(vars_seq)
    raptor_free_sequence(vars_seq);
  if(expr_args_seq)
    raptor_free_sequence(expr_args_seq);
  if(rowsource)
    rasqal_free_rowsource(rowsource);
  if(input_rs)
    rasqal_free_rowsource(input_rs);
  if(query)
    rasqal_free_query(query);
  if(world)
    rasqal_free_world(world);

  return failures;
}
int
main(int argc, char *argv[]) 
{
  const char *program = rasqal_basename(argv[0]);
  rasqal_rowsource *rowsource = NULL;
  rasqal_world* world = NULL;
  rasqal_query* query = NULL;
  raptor_sequence* row_seq = NULL;
  raptor_sequence* expr_seq = NULL;
  int failures = 0;
  rasqal_variables_table* vt;
  rasqal_rowsource *input_rs = NULL;
  int vars_count;
  raptor_sequence* vars_seq = NULL;
  int test_id;

  world = rasqal_new_world();
  if(!world || rasqal_world_open(world)) {
    fprintf(stderr, "%s: rasqal_world init failed\n", program);
    return(1);
  }
  
  query = rasqal_new_query(world, "sparql", NULL);

  vt = query->vars_table;
  
  for(test_id = 0; test_id < GROUP_TESTS_COUNT; test_id++) {
    int expected_rows_count = test_data[test_id].rows;
    int expected_vars_count = test_data[test_id].vars;
    const int* expected_group_ids = test_data[test_id].group_ids;
    int expected_ngroups = test_data[test_id].ngroups;
    raptor_sequence* seq = NULL;
    int count;
    int size;
    int i;
    int groups_counted;
    int last_group_id;
    
    vars_count = expected_vars_count;
    row_seq = rasqal_new_row_sequence(world, vt, test_data[test_id].data,
                                      vars_count, &vars_seq);
    if(row_seq) {
      input_rs = rasqal_new_rowsequence_rowsource(world, query, vt, 
                                                  row_seq, vars_seq);
      /* vars_seq and row_seq are now owned by input_rs */
      vars_seq = row_seq = NULL;
    }
    if(!input_rs) {
      fprintf(stderr, "%s: failed to create rowsequence rowsource\n", program);
      failures++;
      goto tidy;
    }


#ifdef HAVE_RAPTOR2_API
    expr_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_expression,
                                   (raptor_data_print_handler)rasqal_expression_print);
#else
    expr_seq = raptor_new_sequence((raptor_sequence_free_handler*)rasqal_free_expression,
                                   (raptor_sequence_print_handler*)rasqal_expression_print);
#endif

    if(test_data[test_id].expr_vars[0] != NULL) {
      int vindex;
      const unsigned char* var_name;
      
      for(vindex = 0;
          (var_name = (const unsigned char*)test_data[test_id].expr_vars[vindex] );
          vindex++) {
        rasqal_variable* v;
        rasqal_literal *l = NULL;
        rasqal_expression* e = NULL;

        v = rasqal_variables_table_get_by_name(vt, var_name);
        if(v)
          l = rasqal_new_variable_literal(world, v);

        if(l)
          e = rasqal_new_literal_expression(world, l);

        if(e)
          raptor_sequence_push(expr_seq, e);
        else {
          fprintf(stderr, "%s: failed to create variable %s\n", program,
                  (const char*)var_name);
          failures++;
          goto tidy;
        }
        
      }
    }
    
    rowsource = rasqal_new_groupby_rowsource(world, query, input_rs, expr_seq);
    /* input_rs is now owned by rowsource */
    input_rs = NULL;
   
    if(!rowsource) {
      fprintf(stderr, "%s: failed to create groupby rowsource\n", program);
      failures++;
      goto tidy;
    }

    seq = rasqal_rowsource_read_all_rows(rowsource);
    if(!seq) {
      fprintf(stderr,
              "%s: test %d rasqal_rowsource_read_all_rows() returned a NULL seq for a groupby rowsource\n",
              program, test_id);
      failures++;
      goto tidy;
    }
    count = raptor_sequence_size(seq);
    if(count != expected_rows_count) {
      fprintf(stderr,
              "%s: test %d rasqal_rowsource_read_all_rows() returned %d rows for a groupby rowsource, expected %d\n",
              program, test_id, count, expected_rows_count);
      failures++;
      goto tidy;
    }

    size = rasqal_rowsource_get_size(rowsource);
    if(size != expected_vars_count) {
      fprintf(stderr,
              "%s: test %d rasqal_rowsource_get_size() returned %d columns (variables) for a groupby rowsource, expected %d\n",
              program, test_id, size, expected_vars_count);
      failures++;
      goto tidy;
    }

    groups_counted = 0;
    last_group_id = -1;
    for(i = 0; i < count; i++) {
      rasqal_row* row = raptor_sequence_get_at(seq, i);

      if(row->group_id != last_group_id) {
        groups_counted++;
        last_group_id = row->group_id;
      }

      if(row->group_id != expected_group_ids[i]) {
        fprintf(stderr, "%s: test %d row #%d has group_id %d, expected %d\n",
                program, test_id, i, row->group_id, expected_group_ids[i]);
        failures++;
        goto tidy;
      }
      
    }
    
    if(groups_counted != expected_ngroups) {
        fprintf(stderr, "%s: test %d returnd %d groups, expected %d\n",
                program, test_id, groups_counted, expected_ngroups);
        failures++;
        goto tidy;
      }

#ifdef RASQAL_DEBUG
    rasqal_rowsource_print_row_sequence(rowsource, seq, stderr);
#endif

    raptor_free_sequence(seq); seq = NULL;

    rasqal_free_rowsource(rowsource); rowsource = NULL;

    if(expr_seq)
      raptor_free_sequence(expr_seq);
    expr_seq = NULL;
  }
  
  tidy:
  if(expr_seq)
    raptor_free_sequence(expr_seq);
  if(rowsource)
    rasqal_free_rowsource(rowsource);
  if(input_rs)
    rasqal_free_rowsource(input_rs);
  if(query)
    rasqal_free_query(query);
  if(world)
    rasqal_free_world(world);

  return failures;
}