cexternal_functions.c

This file demonstrates how to write an external function.

/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zorba/zorbac.h>
#include <simplestore/simplestorec.h>

// user define data struct
// created in my_ext_fct_init
// passed to my_ext_fct_next
// released in my_ext_fct_release
typedef struct
{
  XQC_Item        item;
  XQC_ItemFactory factory;
  XQC_Sequence    seq;
  int             i;
} my_ext_data;

// callback function called once when initializing the external function
// The user_data parameter can be created in this function and is available
// during the execution.
// The global_user_data parameter can be supplied as a parameter to the
// XQC_StaticContext::register_external_function function
void
my_ext_fct_init(void** user_data, void* global_user_data)
{
  XQC_Implementation impl = (XQC_Implementation) global_user_data;
  my_ext_data* data;

  *user_data = malloc(sizeof(my_ext_data));

  data = (my_ext_data*)(*user_data);
  data->i = 0;

  impl->item_factory(impl, &(data->factory));  
  impl->create_item(impl, &(data->item));
}

// callback function called for each invocation of the external function in the query
XQUERY_ERROR
my_ext_fct_next(XQC_Sequence args, // arguments
                int argc, // number of arguments two this function
                XQC_Item_Ref result,
                void* user_data,
                void* global_user_data)
{
  my_ext_data* data = (my_ext_data*)(user_data);

  // concat the input sequence
  while ( data->i < argc ) {
    if ( args[data->i].next(&(args[data->i]), data->item) != API0025_END_OF_SEQUENCE ) {
      *result = data->item;
      return XQ_NO_ERROR;
    }
    ++(data->i);
  }

  return API0025_END_OF_SEQUENCE;
  

}

// called after the execution of the query has finished
// cleanup of the user_data should be done here
void
my_ext_fct_release(void* user_data,
                   void* global_user_data)
{
  my_ext_data* data = (my_ext_data*)(user_data);
  data->item->free(data->item);
  data->factory->free(data->factory);
  free(user_data);
}

/**
 * register an external function in the static context and execute a query with it
 */
int
external_function_example_1(XQC_Implementation impl)
{
  XQC_Query          lXQuery;
  XQC_StaticContext  lContext;

  impl->create_context(impl, &lContext);

  lContext->register_external_function(lContext, "urn:foo", "bar", 
                                       my_ext_fct_init, 
                                       my_ext_fct_next, 
                                       my_ext_fct_release,
                                       impl);

  impl->prepare(impl, "declare namespace foo=\"urn:foo\"; declare function foo:bar($x, $y, $z) external; foo:bar((1, 2, 3), 1, 2)", lContext, 0, &lXQuery);

  // execute it and print the result on standard out
  lXQuery->execute(lXQuery, stdout);

  // release resources
  lXQuery->free(lXQuery);
  lContext->free(lContext);

  return 1;
}

int
cexternal_functions(int argc, char** argv)
{
  int res = 0; 
  XQC_Implementation impl;

  void* store = create_simple_store();

  if ( zorba_implementation(&impl, store) != XQ_NO_ERROR)
      return 1;

  printf("executing C example 1\n");
  res = external_function_example_1(impl);
  if (!res) { impl->free(impl); return 1; };
  printf("\n");

  impl->free(impl);
  shutdown_simple_store(store);

  return 0;
}