external_functions.cpp
This file shows some simple examples of external functions.
#include <vector>
#include <iostream>
#include <sstream>
#include <cassert>
#include <zorba/zorba.h>
#include <zorba/external_module.h>
#include <zorba/user_exception.h>
#include <zorba/function.h>
#include <zorba/empty_sequence.h>
#include <zorba/vector_item_sequence.h>
#include <zorba/uri_resolvers.h>
#include <zorba/store_manager.h>
#include <zorba/xquery_exception.h>
#include <zorba/diagnostic_list.h>
#include <zorba/internal/unique_ptr.h>
using namespace zorba;
class MySimpleExternalFunction;
class MyLazySimpleExternalFunction;
class MyErrorReportingExternalFunction;
class MyParametrizedExternalFunction;
class MyExternalModule : public ExternalModule
{
protected:
MySimpleExternalFunction * bar1;
MyLazySimpleExternalFunction * bar2;
MyErrorReportingExternalFunction * bar3;
MyParametrizedExternalFunction * bar4;
public:
MyExternalModule()
:
bar1(0),
bar2(0),
bar3(0),
bar4(0)
{
}
~MyExternalModule();
String getURI() const { return "urn:foo"; }
ExternalFunction* getExternalFunction(const String& aLocalname);
};
bool func_example_0(Zorba* aZorba)
{
try
{
StaticContext_t lContext = aZorba->createStaticContext();
MyExternalModule lModule;
lContext->registerModule(&lModule);
lContext->registerModule(&lModule);
}
catch (ZorbaException const &e)
{
std::cerr << "some exception " << e << std::endl;
return true;
}
return false;
}
class MySimpleExternalFunction : public ContextualExternalFunction
{
protected:
const ExternalModule* theModule;
public:
MySimpleExternalFunction(const ExternalModule* aModule)
:
theModule(aModule)
{
}
String getURI() const { return theModule->getURI(); }
String getLocalName() const { return "bar1"; }
ItemSequence_t evaluate(
const ExternalFunction::Arguments_t& args,
const StaticContext* sctx,
const DynamicContext* dctx) const
{
std::cout << "namespace " << sctx->getNamespaceURIByPrefix("foo") << std::endl
<< "current datetime " << dctx->getCurrentDateTime().getStringValue()
<< std::endl;
ItemVector vec;
for (int i = 0; i < 2; ++i)
{
Iterator_t iter = args[i]->getIterator();
iter->open();
Item item;
while(iter->next(item))
{
vec.push_back(item);
}
iter->close();
}
return ItemSequence_t(new IteratorBackedItemSequence(vec));
}
private:
typedef std::vector<Item> ItemVector;
typedef ItemVector::iterator ItemVectorIte;
class IteratorBackedItemSequence : public ItemSequence
{
class InternalIterator : public Iterator
{
private:
IteratorBackedItemSequence *theItemSequence;
ItemVectorIte theIte;
ItemVectorIte theEnd;
bool is_open;
public:
InternalIterator(IteratorBackedItemSequence *item_sequence) :
theItemSequence(item_sequence),
is_open(false)
{ }
void open()
{
is_open = true;
theIte = theItemSequence->theItems.begin();
theEnd = theItemSequence->theItems.end();
}
void close()
{
is_open = false;
}
bool isOpen() const
{
return is_open;
}
bool next(Item& val)
{
assert(is_open);
if (theIte == theEnd)
{
return false;
}
val = *theIte;
++theIte;
return true;
}
};
private:
ItemVector theItems;
public:
IteratorBackedItemSequence(ItemVector& vec)
:
theItems(vec)
{
}
Iterator_t getIterator () {return new InternalIterator(this);}
};
};
bool func_example_1(Zorba* aZorba)
{
StaticContext_t sctx = aZorba->createStaticContext();
MyExternalModule module;
sctx->registerModule(&module);
std::ostringstream queryText;
queryText << "declare namespace foo=\"urn:foo\";" << std::endl
<< "declare function foo:bar1($a1, $a2) external;" << std::endl
<< "foo:bar1((1,2,3), (4,5,6))" << std::endl;
XQuery_t query = aZorba->compileQuery(queryText.str(), sctx);
std::cout << query << std::endl;
return true;
}
class MyLazySimpleExternalFunction : public NonContextualExternalFunction
{
protected:
const ExternalModule* theModule;
public:
MyLazySimpleExternalFunction(const ExternalModule* aModule)
:
theModule(aModule)
{
}
String getURI() const { return theModule->getURI(); }
String getLocalName() const { return "bar2"; }
ItemSequence_t evaluate(const Arguments_t& args) const
{
return ItemSequence_t(new LazyConcatItemSequence(args));
}
private:
class LazyConcatItemSequence : public ItemSequence
{
class InternalIterator : public Iterator
{
private:
LazyConcatItemSequence *theItemSequence;
size_t theCurrentArg;
Iterator_t args_iter;
bool is_open;
public:
InternalIterator(LazyConcatItemSequence *item_sequence) : theItemSequence(item_sequence), theCurrentArg(0), is_open(false)
{
}
virtual void open()
{
is_open = true;
theCurrentArg = 0;
if(theCurrentArg < theItemSequence->theArgs.size())
{
args_iter = theItemSequence->theArgs[theCurrentArg]->getIterator();
args_iter->open();
}
}
virtual void close()
{
if(theCurrentArg < theItemSequence->theArgs.size())
{
args_iter->close();
}
is_open = false;
}
virtual bool isOpen() const
{
return is_open;
}
bool next(Item& result)
{
assert(is_open);
if(theCurrentArg == theItemSequence->theArgs.size())
return false;
while(theCurrentArg < 2 && !args_iter->next(result))
{
args_iter->close();
++theCurrentArg;
if(theCurrentArg == theItemSequence->theArgs.size())
return false;
args_iter = theItemSequence->theArgs[theCurrentArg]->getIterator();
args_iter->open();
}
return !result.isNull();
}
};
private:
Arguments_t theArgs;
public:
LazyConcatItemSequence(const ExternalFunction::Arguments_t& args)
:
theArgs(args)
{
}
Iterator_t getIterator() {return new InternalIterator(this);}
};
};
bool func_example_2_1(Zorba* aZorba)
{
StaticContext_t sctx = aZorba->createStaticContext();
MyExternalModule module;
sctx->registerModule(&module);
std::ostringstream queryText;
queryText << "declare namespace foo=\"urn:foo\";" << std::endl
<< "declare function foo:bar2($a1, $a2) external;" << std::endl
<< "foo:bar2((1,2,3), (4,5,6))" << std::endl;
XQuery_t query = aZorba->compileQuery(queryText.str(), sctx);
std::cout << query << std::endl;
return true;
}
bool func_example_2_2(Zorba* aZorba)
{
StaticContext_t lContext = aZorba->createStaticContext();
MyExternalModule lModule;
lContext->registerModule(&lModule);
std::ostringstream lText;
lText << "declare namespace foo=\"urn:foo\";" << std::endl
<< "declare function foo:bar2($a1, $a2) external;" << std::endl
<< "let $s1 := (1,2,3)" << std::endl
<< "let $s2 := (4,5,6)" << std::endl
<< "for $x in 1 to 6 return (foo:bar2($s1, $s2)[7-$x])" << std::endl;
XQuery_t lQuery = aZorba->compileQuery(lText.str(), lContext);
std::cout << lQuery << std::endl;
return true;
}
class MyErrorReportingExternalFunction : public NonContextualExternalFunction
{
protected:
const ExternalModule* theModule;
public:
MyErrorReportingExternalFunction(const ExternalModule* aModule)
:
theModule(aModule)
{
}
String getURI() const { return theModule->getURI(); }
String getLocalName() const { return "bar3"; }
ItemSequence_t evaluate(const ExternalFunction::Arguments_t& args) const
{
return ItemSequence_t(new LazyErrorReportingItemSequence(args));
}
private:
class LazyErrorReportingItemSequence : public ItemSequence
{
class InternalIterator : public Iterator
{
private:
LazyErrorReportingItemSequence *theItemSequence;
bool is_open;
bool theIsEmpty;
Iterator_t arg0_iter;
public:
InternalIterator(LazyErrorReportingItemSequence *item_sequence) : theItemSequence(item_sequence), is_open(false), theIsEmpty(true)
{
}
virtual void open()
{
is_open = true;
arg0_iter = theItemSequence->theArgs[0]->getIterator();
arg0_iter->open();
}
virtual void close()
{
if(is_open)
arg0_iter->close();
is_open = false;
}
virtual bool isOpen() const
{
return is_open;
}
bool next(Item& result)
{
assert(is_open);
bool done = !arg0_iter->next(result);
if (done && theIsEmpty)
{
throw USER_EXCEPTION(
err::XPTY0004,
"argument must not be the empty sequence"
);
}
theIsEmpty = false;
return !done;
}
};
private:
ExternalFunction::Arguments_t theArgs;
public:
LazyErrorReportingItemSequence(const ExternalFunction::Arguments_t& args)
:
theArgs(args)
{
}
Iterator_t getIterator() {return new InternalIterator(this);}
};
};
bool func_example_3_1(Zorba* aZorba)
{
StaticContext_t sctx = aZorba->createStaticContext();
MyExternalModule module;
sctx->registerModule(&module);
std::ostringstream queryText;
queryText << "declare namespace foo=\"urn:foo\";" << std::endl
<< "declare function foo:bar3($a1) external;" << std::endl
<< "let $s1 := ()" << std::endl
<< "for $x in 1 to 6 return (foo:bar3($s1))" << std::endl;
XQuery_t query = aZorba->compileQuery(queryText.str(), sctx);
try
{
std::cout << query << std::endl;
}
catch (ZorbaException const& ex)
{
std::cerr << ex << std::endl;
return ex.diagnostic().kind() == diagnostic::XQUERY_TYPE;
}
return false;
}
class MyParametrizedExternalFunction : public ContextualExternalFunction
{
protected:
const ExternalModule* theModule;
public:
MyParametrizedExternalFunction(const ExternalModule* aModule)
:
theModule(aModule)
{
}
String getURI() const { return theModule->getURI(); }
String getLocalName() const { return "bar4"; }
ItemSequence_t evaluate(
const ExternalFunction::Arguments_t& args,
const StaticContext* sctx,
const DynamicContext* dctx) const
{
void* lParam;
std::string lParamName("myparam");
if (!dctx->getExternalFunctionParam(lParamName, lParam))
{
assert(false);
}
std::cout << "the function param: " << *static_cast<std::string*>(lParam)
<< std::endl;
return ItemSequence_t(new EmptySequence());
}
};
bool func_example_4_1(Zorba* aZorba)
{
StaticContext_t sctx = aZorba->createStaticContext();
MyExternalModule module;
sctx->registerModule(&module);
std::ostringstream queryText;
queryText << "declare namespace foo=\"urn:foo\";" << std::endl
<< "declare function foo:bar4() external;" << std::endl
<< "for $x in 1 to 6 return (foo:bar4())" << std::endl;
XQuery_t query = aZorba->compileQuery(queryText.str(), sctx);
DynamicContext* lDynContext = query->getDynamicContext();
std::string lFunctionParam("foo:bar");
lDynContext->addExternalFunctionParam("myparam", &lFunctionParam);
try
{
std::cout << query << std::endl;
}
catch (ZorbaException const &ex)
{
std::cerr << ex << std::endl;
return ex.diagnostic().kind() == diagnostic::XQUERY_STATIC;
}
return true;
}
MyExternalModule::~MyExternalModule()
{
delete bar1;
delete bar2;
delete bar3;
delete bar4;
}
ExternalFunction* MyExternalModule::getExternalFunction(const String& aLocalname)
{
if (aLocalname == "bar1")
{
if (!bar1)
{
bar1 = new MySimpleExternalFunction(this);
}
return bar1;
}
else if (aLocalname == "bar2")
{
if (!bar2)
{
bar2 = new MyLazySimpleExternalFunction(this);
}
return bar2;
}
else if (aLocalname == "bar3")
{
if (!bar3)
{
bar3 = new MyErrorReportingExternalFunction(this);
}
return bar3;
}
else if (aLocalname == "bar4")
{
if (!bar3)
{
bar4 = new MyParametrizedExternalFunction(this);
}
return bar4;
}
return 0;
}
static void
releaseStream(std::istream* aStream)
{
delete aStream;
}
class MyModuleURLResolver : public URLResolver
{
public:
~MyModuleURLResolver() {}
virtual Resource* resolveURL(
const String& aUrl,
EntityData const* aEntityData)
{
if (aEntityData->getKind() == EntityData::MODULE &&
aUrl == "http://zorba.io/mymodule")
{
std::unique_ptr<std::istream> lQuery
(new std::istringstream
("module namespace lm = 'http://zorba.io/mymodule'; "
"declare function lm:foo() { 'foo' }; "
"declare function lm:ext() external;"));
return StreamResource::create(lQuery.release(), &releaseStream);
}
else {
return NULL;
}
}
};
class MyModuleExternalFunction;
class MyModuleExternal : public ExternalModule
{
protected:
Zorba * theZorba;
MyModuleExternalFunction * theExtFunc;
public:
MyModuleExternal(Zorba* aZorba) : theZorba(aZorba), theExtFunc(NULL) {}
~MyModuleExternal() {}
ItemFactory* getItemFactory() const { return theZorba->getItemFactory(); }
String getURI() const
{
return "http://zorba.io/mymodule";
}
void setExternalFunction(MyModuleExternalFunction* f)
{
theExtFunc = f;
}
ExternalFunction* getExternalFunction(const String& aLocalname)
{
if (aLocalname == "ext")
{
return reinterpret_cast<ExternalFunction*>(theExtFunc);
}
return NULL;
}
};
class MyModuleExternalFunction : public NonContextualExternalFunction
{
protected:
MyModuleExternal * theModule;
std::vector<Item> theItems;
public:
MyModuleExternalFunction(MyModuleExternal* aModule)
:
theModule(aModule)
{
Item item = aModule->getItemFactory()->createString("ext");
theItems.push_back(item);
theModule->setExternalFunction(this);
}
String getURI() const
{
return theModule->getURI();
}
String getLocalName() const
{
return "ext";
}
ItemSequence_t evaluate(const ExternalFunction::Arguments_t& args) const
{
return ItemSequence_t(new VectorItemSequence(theItems));
}
};
bool func_example_5(Zorba* aZorba)
{
StaticContext_t sctx = aZorba->createStaticContext();
MyModuleURLResolver moduleResolver;
sctx->registerURLResolver(&moduleResolver);
MyModuleExternal lExternalModule(aZorba);
sctx->registerModule(&lExternalModule);
MyModuleExternalFunction lExtFunc(&lExternalModule);
std::ostringstream queryText;
queryText << "import module namespace lm=\"http://zorba.io/mymodule\";"
<< "concat(lm:foo(), lm:ext())" << std::endl;
try
{
XQuery_t query = aZorba->compileQuery(queryText.str(), sctx);
std::cout << query << std::endl;
}
catch (ZorbaException const &ex)
{
std::cerr << ex << std::endl;
return false;
}
return true;
}
int external_functions(int argc, char* argv[])
{
void* lStore = zorba::StoreManager::getStore();
Zorba* lZorba = Zorba::getInstance(lStore);
bool res = false;
std::cout << std::endl << "executing simple external function test 0" << std::endl;
res = func_example_0(lZorba);
if (!res) return 1;
std::cout << std::endl;
std::cout << std::endl << "executing simple external function test 1.1" << std::endl;
res = func_example_1(lZorba);
if (!res) return 1;
std::cout << std::endl;
std::cout << std::endl << "executing simple external function test 2.1" << std::endl;
res = func_example_2_1(lZorba);
if (!res) return 1;
std::cout << std::endl;
std::cout << std::endl << "executing simple external function test 2.2" << std::endl;
res = func_example_2_2(lZorba);
if (!res) return 1;
std::cout << std::endl;
std::cout << std::endl << "executing simple external function test 3.1" << std::endl;
res = func_example_3_1(lZorba);
if (!res) return 1;
std::cout << std::endl;
std::cout << std::endl << "executing simple external function test 4.1" << std::endl;
res = func_example_4_1(lZorba);
if (!res) return 1;
std::cout << std::endl;
std::cout << std::endl << "executing simple external function test 5" << std::endl;
res = func_example_5(lZorba);
if (!res) return 1;
std::cout << std::endl;
lZorba->shutdown();
zorba::StoreManager::shutdownStore(lStore);
return 0;
}