Пример #1
0
/**
 * rasqal_row_compatible_check:
 * @map: row compatible map object
 * @first_row: first row
 * @second_row: second row
 *
 * Test if two rows have SPARQL Algebra "Compatible Mappings"
 * 
 *   "Two solution mappings μ1 and μ2 are compatible if, for every
 *   variable v in dom(μ1) and in dom(μ2), μ1(v) = μ2(v)."
 *  -- SPARQL Query Language 20080115, 12.3 Basic Graph Patterns
 *
 * interpretation:
 *  for all variables in both rows
 *    the values for both rows must either
 *      a) be the same defined value
 *      b) both be undefined
 */
int
rasqal_row_compatible_check(rasqal_row_compatible* map,
                            rasqal_row *first_row, rasqal_row *second_row)
{
  int i;
  int count = map->variables_count;
  int compatible = 1;

  /* If no variables in common, always compatible */
  if(!map->variables_in_both_rows_count)
    return 1;
  
  for(i = 0; i < count; i++) {
#ifdef RASQAL_DEBUG
    rasqal_variable *v = rasqal_variables_table_get(map->variables_table, i);
    const unsigned char *name = v->name;
#endif
    rasqal_literal *first_value = NULL;
    rasqal_literal *second_value = NULL;

    int offset1 = map->defined_in_map[i<<1];
    int offset2 = map->defined_in_map[1 + (i<<1)];

    if(offset1 >= 0)
      first_value = first_row->values[offset1];

    if(offset2 >= 0)
      second_value = second_row->values[offset2];

#if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
    RASQAL_DEBUG5("row variable #%d - %s has first row offset #%d  second row offset #%d\n", i, name, offset1, offset2);
#endif

    /* do not test if both are NULL */
    if(!first_value && !second_value)
      continue;

    if(!first_value || !second_value) {
#if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
      RASQAL_DEBUG3("row variable #%d - %s has (one NULL, one value)\n", i,
                    name);
#endif
      /* compatible if one is NULL and the other is not */
      continue;
    }

    if(!rasqal_literal_equals(first_value, second_value)) {
      RASQAL_DEBUG3("row variable #%d - %s has different values\n", i, name);
      /* incompatible if not equal values */
      compatible = 0;
      break;
    } else {
#if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
      RASQAL_DEBUG3("row variable #%d - %s has same values\n", i, name);
#endif
    }
  }

  return compatible;
}
Пример #2
0
/**
 * rasqal_free_variable:
 * @v: #rasqal_variable object
 *
 * Destructor - Destroy a Rasqal variable object.
 *
 **/
void
rasqal_free_variable(rasqal_variable* v)
{
  if(!v)
    return;

#ifdef RASQAL_DEBUG_VARIABLE_USAGE
  v->usage--;
  RASQAL_DEBUG3("Variable %s usage decreased to %d\n", v->name, v->usage);
  if(v->usage)
    return;
#else
  if(--v->usage)
    return;
#endif
  
  if(v->name)
    RASQAL_FREE(char*, v->name);

  if(v->value)
    rasqal_free_literal(v->value);

  if(v->expression)
    rasqal_free_expression(v->expression);

  RASQAL_FREE(rasqal_variable, v);
}
Пример #3
0
/**
 * rasqal_rowsource_reset:
 * @rowsource: rasqal rowsource
 *
 * INTERNAL - Reset a rowsource to regenerate the same set of rows
 *
 * Return value: query or NULL
 **/
int
rasqal_rowsource_reset(rasqal_rowsource* rowsource)
{
  rowsource->finished = 0;
  rowsource->count = 0;

  if(rowsource->handler->reset)
    return rowsource->handler->reset(rowsource, rowsource->user_data);

  if(rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS) {
    RASQAL_DEBUG3("%s rowsource %p resetting to use saved rows\n", 
                  rowsource->handler->name, rowsource);
    rowsource->offset = 0;
  } else {
    RASQAL_DEBUG3("WARNING: %s rowsource %p has no reset and there are no saved rows\n",
                  rowsource->handler->name, rowsource);
  }
  return 0;
}
Пример #4
0
/**
 * rasqal_new_variable_from_variable:
 * @v: #rasqal_variable to copy
 *
 * Copy Constructor - Create a new Rasqal variable from an existing one
 *
 * This adds a new reference to the variable, it does not do a deep copy
 *
 * Return value: a new #rasqal_variable or NULL on failure.
 **/
rasqal_variable*
rasqal_new_variable_from_variable(rasqal_variable* v)
{
  if(!v)
    return NULL;
  
  v->usage++;
  
#ifdef RASQAL_DEBUG_VARIABLE_USAGE
  RASQAL_DEBUG3("Variable %s usage increased to %d\n", v->name, v->usage);
#endif

  return v;
}
Пример #5
0
/**
 * rasqal_rowsource_read_row:
 * @rowsource: rasqal rowsource
 *
 * Read a query result row from the rowsource.
 *
 * If a row is returned, it is owned by the caller.
 *
 * Return value: row or NULL when no more rows are available
 **/
rasqal_row*
rasqal_rowsource_read_row(rasqal_rowsource *rowsource)
{
    rasqal_row* row = NULL;

    if(rowsource->finished)
        return NULL;

    if(rasqal_rowsource_ensure_variables(rowsource))
        return NULL;

    if(rowsource->handler->read_row)
        row = rowsource->handler->read_row(rowsource, rowsource->user_data);
    else {
        if(!rowsource->rows_sequence) {
            rowsource->rows_sequence = rasqal_rowsource_read_all_rows(rowsource);
            rowsource->offset = 0;
        }

        if(rowsource->rows_sequence)
            /* remove and return row from sequence at offset */
            row = (rasqal_row*)raptor_sequence_delete_at(rowsource->rows_sequence,
                    rowsource->offset++);
    }

    if(!row)
        rowsource->finished = 1;
    else {
        rowsource->count++;

        /* Generate a group around all rows if there are no groups returned */
        if(rowsource->generate_group && row->group_id < 0)
            row->group_id = 0;
    }

#ifdef RASQAL_DEBUG
    RASQAL_DEBUG3("%s rowsource %p read row:  ", rowsource->handler->name,
                  rowsource);
    if(row)
        rasqal_row_print(row, stderr);
    else
        fputs("NONE", stderr);
    fputs("\n", stderr);
#endif

    return row;
}
Пример #6
0
/*
 * rasqal_world_register_query_result_format_factory:
 * @world: rasqal world
 * @register_factory: pointer to function to call to register the factory
 * 
 * INTERNAL - Register a query result format via a factory.
 *
 * All strings set in the @factory method are shared with the
 * #rasqal_query_result_format_factory
 *
 * Return value: new factory object or NULL on failure
 **/
rasqal_query_results_format_factory*
rasqal_world_register_query_results_format_factory(rasqal_world* world,
                                                   int (*register_factory)(rasqal_query_results_format_factory*))
{
  rasqal_query_results_format_factory *factory = NULL;
  
  factory = RASQAL_CALLOC(rasqal_query_results_format_factory*, 1, 
                          sizeof(*factory));
  if(!factory)
    return NULL;

  factory->world = world;

  if(raptor_sequence_push(world->query_results_formats, factory))
    return NULL; /* on error, factory is already freed by the sequence */
  
  /* Call the factory registration function on the new object */
  if(register_factory(factory))
    /* factory is owned and freed by the query_results_formats sequence */
    return NULL;
  
  factory->desc.flags = 0;
  if(factory->get_rowsource)
    factory->desc.flags |= RASQAL_QUERY_RESULTS_FORMAT_FLAG_READER;
  if(factory->write)
    factory->desc.flags |= RASQAL_QUERY_RESULTS_FORMAT_FLAG_WRITER;

  if(raptor_syntax_description_validate(&factory->desc)) {
    rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, NULL,
                            "Result query result format description failed to validate\n");
    goto tidy;
  }

#if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
  RASQAL_DEBUG3("Registered query result format %s with context size %d\n",
                factory->desc.names[0], factory->context_length);
#endif

  return factory;

  /* Clean up on failure */
  tidy:
  rasqal_free_query_results_format_factory(factory);
  return NULL;
}
Пример #7
0
/*
 * rasqal_query_language_register_factory:
 * @factory: pointer to function to call to register the factory
 * 
 * INTERNAL - Register a query language syntax handled by a query factory
 *
 * Return value: new factory or NULL on failure
 **/
RASQAL_EXTERN_C
rasqal_query_language_factory*
rasqal_query_language_register_factory(rasqal_world *world,
                                       int (*factory) (rasqal_query_language_factory*))
{
  rasqal_query_language_factory *query = NULL;
  
  query = (rasqal_query_language_factory*)RASQAL_CALLOC(rasqal_query_language_factory, 1,
                                                        sizeof(*query));
  if(!query)
    goto tidy;

  query->world = world;
  
  if(raptor_sequence_push(world->query_languages, query))
    return NULL; /* on error, query is already freed by the sequence */
  
  /* Call the query registration function on the new object */
  if(factory(query))
    return NULL; /* query is owned and freed by the query_languages sequence */
  
  if(raptor_syntax_description_validate(&query->desc)) {
    rasqal_log_error_simple(world, RAPTOR_LOG_LEVEL_ERROR, NULL,
                            "Query language format description failed to validate\n");
    goto tidy;
  }

#if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
  RASQAL_DEBUG3("Registered query language %s with context size %d\n",
                query->names[0], query->context_length);
#endif

  return query;

  /* Clean up on failure */
  tidy:
  if(query)
    rasqal_free_query_language_factory(query);

  return NULL;
}
Пример #8
0
/**
 * rasqal_rowsource_ensure_variables:
 * @rowsource: rasqal rowsource
 *
 * INTERNAL - Ensure that the variables in the rowsource are defined
 *
 * Return value: non-0 on failure
 */
int
rasqal_rowsource_ensure_variables(rasqal_rowsource *rowsource)
{
    int rc = 0;

    if(rowsource->updated_variables)
        return 0;

    rowsource->updated_variables++;

    if(rowsource->handler->ensure_variables)
        rc = rowsource->handler->ensure_variables(rowsource, rowsource->user_data);

#ifdef RASQAL_DEBUG
    if(!rc) {
        RASQAL_DEBUG3("%s rowsource %p header: ", rowsource->handler->name,
                      rowsource);
        rasqal_rowsource_print_header(rowsource, stderr);
    }
#endif

    return rc;
}
Пример #9
0
static int
rasqal_rowsource_visitor_set_requirements(rasqal_rowsource* rowsource,
                                          void *user_data)
{
  unsigned int flags = *(unsigned int*)user_data;

  if(rowsource->handler->set_requirements)
    return rowsource->handler->set_requirements(rowsource, rowsource->user_data,
                                                flags);

  if(flags & RASQAL_ROWSOURCE_REQUIRE_RESET) {
    if(!rowsource->handler->reset) {
      /* If there is no reset handler, it is handled by this module and it is needed
       * it is handled by this module
       */
      RASQAL_DEBUG3("setting %s rowsource %p to save rows\n",
                    rowsource->handler->name, rowsource);
      rowsource->flags |= RASQAL_ROWSOURCE_FLAGS_SAVE_ROWS;
      return 1;
    }
  }

  return 0;
}
Пример #10
0
rasqal_rowsource*
rasqal_new_aggregation_rowsource(rasqal_world *world, rasqal_query* query,
                                 rasqal_rowsource* rowsource,
                                 raptor_sequence* exprs_seq,
                                 raptor_sequence* vars_seq)
{
  rasqal_aggregation_rowsource_context* con;
  int flags = 0;
  int size;
  int i;
  
  if(!world || !query || !rowsource || !exprs_seq || !vars_seq)
    goto fail;

  exprs_seq = rasqal_expression_copy_expression_sequence(exprs_seq);
  vars_seq = rasqal_variable_copy_variable_sequence(vars_seq);

  size = raptor_sequence_size(exprs_seq);
  if(size != raptor_sequence_size(vars_seq)) {
    RASQAL_DEBUG3("expressions sequence size %d does not match vars sequence size %d\n", size, raptor_sequence_size(vars_seq));
    goto fail;
  }


  con = (rasqal_aggregation_rowsource_context*)RASQAL_CALLOC(rasqal_aggregation_rowsource_context, 1, sizeof(*con));
  if(!con)
    goto fail;

  con->rowsource = rowsource;

  con->exprs_seq = exprs_seq;
  con->vars_seq = vars_seq;
  
  /* allocate per-expr data */
  con->expr_count = size;
  con->expr_data = (rasqal_agg_expr_data*)RASQAL_CALLOC(rasqal_agg_expr_data, 
                                                        sizeof(rasqal_agg_expr_data),
                                                        size);
  if(!con->expr_data)
    goto fail;

  /* Initialise per-expr data */
  for(i = 0; i < size; i++) {
    rasqal_expression* expr = (rasqal_expression *)raptor_sequence_get_at(exprs_seq, i);
    rasqal_variable* variable = (rasqal_variable*)raptor_sequence_get_at(vars_seq, i);
    rasqal_agg_expr_data* expr_data = &con->expr_data[i];

    expr_data->expr = rasqal_new_expression_from_expression(expr);
    expr_data->variable = variable;

    /* Prepare expression arguments sequence in per-expr data */
    if(expr->args) {
      /* list of #rasqal_expression arguments already in expr
       * #RASQAL_EXPR_FUNCTION and #RASQAL_EXPR_GROUP_CONCAT 
       */
      expr_data->exprs_seq = rasqal_expression_copy_expression_sequence(expr->args);
    } else {
      /* single argument */
      
      expr_data->exprs_seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_expression,
                                               (raptor_data_print_handler)rasqal_expression_print);
      raptor_sequence_push(expr_data->exprs_seq,
                           rasqal_new_expression_from_expression(expr->arg1));
    }
  }
  
  
  return rasqal_new_rowsource_from_handler(world, query,
                                           con,
                                           &rasqal_aggregation_rowsource_handler,
                                           query->vars_table,
                                           flags);

  fail:

  if(rowsource)
    rasqal_free_rowsource(rowsource);
  if(exprs_seq)
    raptor_free_sequence(exprs_seq);
  if(vars_seq)
    raptor_free_sequence(vars_seq);

  return NULL;
}
Пример #11
0
static int
rasqal_builtin_agg_expression_execute_step(void* user_data,
                                           raptor_sequence* literals)
{
  rasqal_builtin_agg_expression_execute* b;
  rasqal_literal* l;
  int i;

  b = (rasqal_builtin_agg_expression_execute*)user_data;

  if(b->error)
    return 1;
  
  if(b->expr->op == RASQAL_EXPR_COUNT) {
    /* COUNT(*) : counts every row (does not care about literals) */
    if(b->expr->arg1->op == RASQAL_EXPR_VARSTAR)
      b->count++;
    /* COUNT(expr list) : counts rows with non-empty sequence of literals */
    else if(raptor_sequence_size(literals) > 0)
      b->count++;
    
    return 0;
  }
    

  /* Other aggregate functions count every row */
  b->count++;

  for(i = 0; (l = (rasqal_literal*)raptor_sequence_get_at(literals, i)); i++) {
    rasqal_literal* result = NULL;

    if(b->expr->op == RASQAL_EXPR_SAMPLE) {
      /* Sample chooses the first literal it sees */
      if(!b->l)
        b->l = rasqal_new_literal_from_literal(l);

      break;
    }

    if(b->expr->op == RASQAL_EXPR_GROUP_CONCAT) {
      const unsigned char* str;
      int error = 0;
      
      str = (const unsigned char*)rasqal_literal_as_string_flags(l, 0, &error);

      if(!error) {
        if(raptor_stringbuffer_length(b->sb))
          raptor_stringbuffer_append_counted_string(b->sb, b->separator, 1, 1);

        raptor_stringbuffer_append_string(b->sb, str, 1); 
      }
      continue;
    }
  
    
    if(!b->l)
      result = rasqal_new_literal_from_literal(l);
    else {
      if(b->expr->op == RASQAL_EXPR_SUM || b->expr->op == RASQAL_EXPR_AVG) {
        result = rasqal_literal_add(b->l, l, &b->error);
      } else if(b->expr->op == RASQAL_EXPR_MIN) {
        int cmp = rasqal_literal_compare(b->l, l, 0, &b->error);
        if(cmp <= 0)
          result = rasqal_new_literal_from_literal(b->l);
        else
          result = rasqal_new_literal_from_literal(l);
      } else if(b->expr->op == RASQAL_EXPR_MAX) {
        int cmp = rasqal_literal_compare(b->l, l, 0, &b->error);
        if(cmp >= 0)
          result = rasqal_new_literal_from_literal(b->l);
        else
          result = rasqal_new_literal_from_literal(l);
      } else {
        RASQAL_FATAL2("Builtin aggregation operation %d is not implemented", 
                      b->expr->op);
      }

      rasqal_free_literal(b->l);

      if(!result)
        b->error = 1;
    }
    
    b->l = result;

#if RASQAL_DEBUG > 1
    RASQAL_DEBUG3("Aggregation step result %s (error=%d)\n", 
                  (result ? (const char*)rasqal_literal_as_string(result) : "(NULL)"),
                  b->error);
#endif
    
    if(b->error)
      break;
  }
  
  return b->error;
}
Пример #12
0
/**
 * rasqal_rowsource_read_row:
 * @rowsource: rasqal rowsource
 *
 * Read a query result row from the rowsource.
 *
 * If a row is returned, it is owned by the caller.
 *
 * Return value: row or NULL when no more rows are available
 **/
rasqal_row*
rasqal_rowsource_read_row(rasqal_rowsource *rowsource)
{
  rasqal_row* row = NULL;
  
  if(!rowsource || rowsource->finished)
    return NULL;

  if(rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS) {
    /* return row from saved rows sequence at offset */
    row = (rasqal_row*)raptor_sequence_get_at(rowsource->rows_sequence,
                                              rowsource->offset++);
#ifdef RASQAL_DEBUG
    RASQAL_DEBUG3("%s rowsource %p returned saved row:  ",
                  rowsource->handler->name, rowsource);
    if(row)
      rasqal_row_print(row, stderr);
    else
      fputs("NONE", stderr);
    fputs("\n", stderr);
#endif      
    if(row)
      row = rasqal_new_row_from_row(row);
    /* row is owned by us */
  } else {
    if(rasqal_rowsource_ensure_variables(rowsource))
      return NULL;

    if(rowsource->handler->read_row) {
      row = rowsource->handler->read_row(rowsource, rowsource->user_data);
      /* row is owned by us */

      if(row && rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVE_ROWS) {
        if(!rowsource->rows_sequence) {
          rowsource->rows_sequence = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
                                                         (raptor_data_print_handler)rasqal_row_print);
          rowsource->offset = 0;
        }
        /* copy to save it away */
        row = rasqal_new_row_from_row(row);
        raptor_sequence_push(rowsource->rows_sequence, row);
      }
    } else {
      if(!rowsource->rows_sequence) {
        raptor_sequence* seq;
        
        seq = rasqal_rowsource_read_all_rows(rowsource);
        if(rowsource->rows_sequence)
          raptor_free_sequence(rowsource->rows_sequence);
        /* rows_sequence now owns all rows */
        rowsource->rows_sequence = seq;

        rowsource->offset = 0;
      }
      
      if(rowsource->rows_sequence) {
        /* return row from sequence at offset */
        row = (rasqal_row*)raptor_sequence_get_at(rowsource->rows_sequence,
                                                  rowsource->offset++);
        if(row)
          row = rasqal_new_row_from_row(row);
        /* row is owned by us */
      }
    }
  }
  
  if(!row) {
    rowsource->finished = 1;
    if(rowsource->flags & RASQAL_ROWSOURCE_FLAGS_SAVE_ROWS)
      rowsource->flags |= RASQAL_ROWSOURCE_FLAGS_SAVED_ROWS;
  } else {
    rowsource->count++;

    /* Generate a group around all rows if there are no groups returned */
    if(rowsource->generate_group && row->group_id < 0)
      row->group_id = 0;
  }

#ifdef RASQAL_DEBUG
  RASQAL_DEBUG3("%s rowsource %p returned row:  ", rowsource->handler->name, 
                rowsource);
  if(row)
    rasqal_row_print(row, stderr);
  else
    fputs("NONE", stderr);
  fputs("\n", stderr);
#endif

  return row;
}
Пример #13
0
static void
rasqal_sparql_xml_sax2_end_element_handler(void *user_data,
                                           raptor_xml_element* xml_element)
{
  rasqal_rowsource_sparql_xml_context* con;
  raptor_qname* name;
  int i;
  rasqal_sparql_xml_read_state state=STATE_unknown;
  
  con=(rasqal_rowsource_sparql_xml_context*)user_data;

  name=raptor_xml_element_get_name(xml_element);

  for(i=STATE_first; i <= STATE_last; i++) {
    if(!strcmp((const char*)raptor_qname_get_local_name(name),
               sparql_xml_element_names[i])) {
      state=(rasqal_sparql_xml_read_state)i;
      con->state=state;
    }
  }

  if(state == STATE_unknown) {
    fprintf(stderr, "UNKNOWN element %s\n", raptor_qname_get_local_name(name));
    con->failed++;
  }

  con->depth--;
#ifdef TRACE_XML
  if(con->trace) {
    pad(stderr, con->depth);
    fprintf(stderr, "End Element %s (%d)\n", raptor_qname_get_local_name(name),
            con->state);
  }
#endif

  switch(con->state) {
    case STATE_head:
      /* Only now is the full number of variables known */
      con->variables_count = rasqal_variables_table_get_named_variables_count(con->vars_table);
      con->rowsource->size = con->variables_count;
      break;
      
    case STATE_literal:
      if(1) {
        rasqal_literal* l;
        unsigned char* lvalue;
        raptor_uri* datatype_uri=NULL;
        char* language_str=NULL;

        lvalue=(unsigned char*)RASQAL_MALLOC(cstring, con->value_len+1);
        memcpy(lvalue, con->value, con->value_len + 1);
        if(con->datatype)
          datatype_uri = raptor_new_uri(con->world->raptor_world_ptr, (const unsigned char*)con->datatype);
        if(con->language) {
          size_t language_len = strlen(con->language);
          language_str=(char*)RASQAL_MALLOC(cstring, language_len + 1);
          memcpy(language_str, con->language, language_len + 1);
        }
        l = rasqal_new_string_literal_node(con->world, lvalue, language_str,
                                           datatype_uri);
        rasqal_row_set_value_at(con->row, con->result_offset, l);
        rasqal_free_literal(l);
        RASQAL_DEBUG3("Saving row result %d string value at offset %d\n",
                      con->offset, con->result_offset);
      }
      break;
      
    case STATE_bnode:
      if(1) {
        rasqal_literal* l;
        unsigned char* lvalue;
        lvalue=(unsigned char*)RASQAL_MALLOC(cstring, con->value_len+1);
        memcpy(lvalue, con->value, con->value_len + 1);
        l = rasqal_new_simple_literal(con->world, RASQAL_LITERAL_BLANK, lvalue);
        rasqal_row_set_value_at(con->row, con->result_offset, l);
        rasqal_free_literal(l);
        RASQAL_DEBUG3("Saving row result %d bnode value at offset %d\n",
                      con->offset, con->result_offset);
      }
      break;
      
    case STATE_uri:
      if(1) {
        raptor_uri* uri;
        rasqal_literal* l;
        uri = raptor_new_uri(con->world->raptor_world_ptr, (const unsigned char*)con->value);
        l = rasqal_new_uri_literal(con->world, uri);
        rasqal_row_set_value_at(con->row, con->result_offset, l);
        rasqal_free_literal(l);
        RASQAL_DEBUG3("Saving row result %d uri value at offset %d\n",
                      con->offset, con->result_offset);
      }
      break;
      
    case STATE_result:
      if(con->row) {
        RASQAL_DEBUG2("Saving row result %d\n", con->offset);
        raptor_sequence_push(con->results_sequence, con->row);
      }
      con->row=NULL;
      break;

    case STATE_unknown:
    case STATE_sparql:
    case STATE_variable:
    case STATE_results:
    case STATE_binding:
    default:
      break;
  }

  if(con->value) {
    RASQAL_FREE(cstring, con->value);
    con->value=NULL;
  }
}