Files
secondo/UserInterfaces/SecondoPL.cpp
2026-01-23 17:03:45 +08:00

1374 lines
32 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
\vspace{1cm}
\centerline{\LARGE \bf SecondoPL}
\begin{center}
\footnotesize
\tableofcontents
\end{center}
1 Overview
This is the source code of a PROLOG shell which has
support for calling Secondo from PROLOG.
2 Includes and defines
*/
#include <string.h>
#include <iostream>
#include <list>
#include "stdlib.h"
#include "SWI-Prolog.h"
#include "SecondoPL.h"
// NVK ADDED
#ifdef SECONDO_USE_MEMORY_ALLOCATION
#include "MemoryOptimization.h"
//#include "QueryProcessor.h"
#endif
// NVK ADDED END
#include "NestedList.h"
#include "SecondoInterface.h"
#if !defined(SECONDO_CLIENT_SERVER) && !defined(REPLAY)
#include "SecondoInterfaceTTY.h"
#elif defined(SECONDO_CLIENT_SERVER)
#include "SecondoInterfaceCS.h"
#elif defined(REPLAY)
#include "SecondoInterfaceREPLAY.h"
#else
#include "SecondoInterfaceCS.h"
#endif
#include "Profiles.h"
#include "LogMsg.h"
#include "License.h"
#include "TTYParameter.h"
#include "NList.h"
#include "../OptParser/OptimizerChecker.h"
#ifdef SECONDO_USE_ENTROPY
#include "../Optimizer/Entropy/entropy.h"
#endif
using namespace std;
SecondoInterface* si = 0;
NestedList* plnl = 0;
int lastErrorCode = 0;
string lastErrorMessage = "";
/*
3 Function handle\_exit
This function is registered as exit handler in the main function.
*/
void handle_exit(void) {
/* PROLOG interpreter has terminated, shutdown Secondo */
if(si != 0)
{
try {
si->Terminate();
delete si;
si = 0;
}
catch (SecondoException &e)
{
cerr << e.msg() << endl;
}
};
}
/*
3 Function ListExprToTerm
Converts a Secondo list expression to a PROLOG term.
*/
term_t
ListExprToTerm(ListExpr expr, NestedList* nl)
{
ListExpr current;
int length;
int i;
std::list<ListExpr> listElements;
std::list<ListExpr>::iterator iter;
long intValue;
double realValue;
bool boolValue;
string stringValue;
string stringRepr;
TextScan scan;
term_t elem;
term_t result = PL_new_term_ref();
if(nl->IsAtom(expr))
{
switch(nl->AtomType(expr))
{
case IntType:
intValue = nl->IntValue(expr);
if(!PL_put_integer(result, intValue)){
assert(false);
}
break;
case RealType:
realValue = nl->RealValue(expr);
if(!PL_put_float(result, realValue)){
assert(false);
}
break;
case BoolType:
boolValue = nl->BoolValue(expr);
PL_put_atom_chars(result, boolValue ? "true" : "false");
break;
case StringType:
stringValue = nl->StringValue(expr);
stringRepr = string("\"") + stringValue + '\"';
PL_put_atom_chars(result, stringRepr.c_str());
break;
case SymbolType:
stringValue = nl->SymbolValue(expr);
PL_put_atom_chars(result, stringValue.c_str());
break;
case TextType:
scan = nl->CreateTextScan(expr);
nl->GetText(scan, nl->TextLength(expr) + 2, stringValue);
nl->DestroyTextScan(scan);
PL_put_atom_chars(result, stringValue.c_str());
break;
default:
/* this should not happen */
assert(false);
}
}
else
{
PL_put_nil(result);
current = expr;
length = nl->ListLength(current);
for(i = 0; i < length; i++)
{
listElements.push_front(nl->First(current));
current = nl->Rest(current);
}
for(iter = listElements.begin(); iter != listElements.end(); iter++)
{
elem = ListExprToTerm(*iter, nl);
if(!PL_cons_list(result, elem, result)){
assert(false);
}
}
}
return result;
}
/*
4 Function AtomToListExpr
Converts a PROLOG atom (represented as a string) to
a ListExpr.
*/
ListExpr
AtomToListExpr(NestedList* nl, char* str, bool& error)
{
ListExpr result;
string atomStr;
error = false;
if(strcmp(str, "true") == 0)
{
result = nl->BoolAtom(true);
}
else if(strcmp(str, "false") == 0)
{
result = nl->BoolAtom(false);
}
else if(str[0] == '\"')
{
str++;
atomStr = str;
if(atomStr.size() > 0 && atomStr[atomStr.size() - 1] == '\"')
{
atomStr.erase(atomStr.size() - 1);
result = nl->StringAtom(atomStr);
}
else
{
error = true;
result = nl->TheEmptyList();
}
}
else
{
result = nl->SymbolAtom(string(str));
}
return result;
}
/*
4 Function TermToListExpr
Converts a PROLOG term to a ListExpr.
*/
ListExpr
TermToListExpr(term_t t, NestedList* nl, bool& error)
{
long intValue;
double realValue;
char* charValue;
char* strValue;
size_t len;
term_t head;
term_t list;
std::list<ListExpr> elementList;
std::list<ListExpr>::iterator iter;
ListExpr result;
error = false;
switch(PL_term_type(t))
{
case PL_VARIABLE:
error = true;
result = nl->TheEmptyList();
break;
case PL_INTEGER:
if(!PL_get_long(t, &intValue)){
cerr << "PL_get_long failed" << endl;
}
result = nl->IntAtom(intValue);
break;
case PL_FLOAT:
if(!PL_get_float(t, &realValue)){
cerr << "PL_get_float failed" << endl;
}
result = nl->RealAtom(realValue);
break;
case PL_ATOM:
if(!PL_get_atom_chars(t, &charValue)){
cerr << "PL_get_atom failed" << endl;
}
result = AtomToListExpr(nl, charValue, error);
break;
case PL_STRING:
if(!PL_get_string_chars(t, &charValue, &len)){
cerr << "PL_get_string failed" << endl;
}
strValue = new char[len + 1];
strValue[len] = 0;
memcpy(strValue, charValue, len);
result = AtomToListExpr(nl, strValue, error);
delete[] strValue;
break;
case PL_TERM:
if(PL_is_list(t))
{
result = nl->TheEmptyList();
head = PL_new_term_ref();
list = PL_copy_term_ref(t);
while(PL_get_list(list, head, list))
{
elementList.push_front(TermToListExpr(head, nl, error));
if(error)
break;
}
if(!error)
{
for(iter = elementList.begin(); iter != elementList.end(); iter++)
{
result = nl->Cons(*iter, result);
}
}
else
{
result = nl->TheEmptyList();
}
}
else
{
error = true;
result = nl->TheEmptyList();
}
break;
default:
assert(false); /* should not happen */
}
return result;
}
// some code below can only be translated
// when the Optimizaton-Library (OPT++) is
// present
#ifdef SECONDO_USE_ENTROPY
/*
4 Function FloatListToVector
Converts a PROLOG list of float numbers to a Vector of float numbers (double).
*/
void
FloatListToVector(term_t t, std::vector<double>& v, bool& error)
{
error = 1;
if( PL_is_list(t) )
{
term_t head = PL_new_term_ref();
term_t list = PL_copy_term_ref(t);
v.clear();
while( PL_get_list(list, head, list) )
{
double d;
if ( PL_get_float(head, &d) )
v.push_back(d);
else
return;
}
error = 0;
}
}
/*
4 Function FloatListPairToVectorPair
Converts a PROLOG list of (integer,float) pair to a vector of (int,float) pair.
*/
void
FloatListPairToVectorPair( term_t t,
ProbabilityPairVec& v,
bool& error )
{
error = 1;
if( PL_is_list(t) )
{
// Outer list
term_t o_head = PL_new_term_ref();
term_t o_list = PL_copy_term_ref(t);
v.clear();
while( PL_get_list(o_list, o_head, o_list) )
{
ProbabilityPair p;
term_t i_head = PL_new_term_ref();
term_t i_list = PL_copy_term_ref(o_head);
PL_get_list(i_list, i_head, i_list);
if ( PL_get_integer(i_head, &p.first) )
if ( PL_get_list(i_list, i_head, i_list)
&& PL_get_float(i_head, &p.second) )
v.push_back(p);
else
return;
else
return;
}
error = 0;
}
}
/*
4 Function FloatVectorToList
Converts a Vector of float numbers to a PROLOG list of float numbers (double).
*/
void
FloatVectorToList(ProbabilityVec& v,term_t& t, bool& error)
{
term_t list = PL_copy_term_ref(t);
term_t head = PL_new_term_ref();
ProbabilityVec::iterator iter;
error = 1;
for( iter = v.begin(); iter != v.end(); iter++ )
{
if ( !PL_unify_list(list, head, list) || !PL_unify_float(head, *iter) )
return;
}
error = !PL_unify_nil(list);
}
/*
4 Function FloatVectorPairToListPair
Converts a vector of (int,float) numbers to a PROLOG list of (integer,float).
*/
void
FloatVectorPairToListPair( ProbabilityPairVec& v,
term_t& t, bool& error )
{
// Outer list
term_t o_list = PL_copy_term_ref(t);
term_t o_head = PL_new_term_ref();
ProbabilityPairVec::iterator iter;
error = 1;
for( iter = v.begin(); iter != v.end(); iter++ )
{
if ( !PL_unify_list(o_list, o_head, o_list) ) return;
term_t i_list = PL_copy_term_ref(o_head);
term_t i_head = PL_new_term_ref();
if ( !PL_unify_list(i_list, i_head, i_list) ) return;
if ( !PL_unify_integer(i_head, iter->first) ) return;
if ( !PL_unify_list(i_list, i_head, i_list) ) return;
if ( !PL_unify_float(i_head, iter->second) ) return;
if ( !PL_unify_nil(i_list) ) return;
}
error = !PL_unify_nil(o_list);
}
#endif
/*
4 Function pl\_print\_term\_le
Converts a PROLOG term to a ListExpr and then prints
that ListExpr using the routines from NestedList.
*/
static foreign_t
pl_print_term_le(term_t term)
{
bool error;
TermToListExpr(term, plnl, error);
if(error)
{
PL_fail;
}
else
{
// for debugging
// plnl->WriteListExpr(listLE);
PL_succeed;
}
}
/*
4 Function pl\_get\_error\_info
Get error code (an integer) and error message (a string)
of the last issued Secondo command.
*/
static foreign_t
pl_get_error_info(term_t errorCode, term_t errorMessage)
{
int unify1 = PL_unify_integer(errorCode, lastErrorCode);
string msg = SecondoInterface::GetErrorMessage(lastErrorCode) + "\n"
+ lastErrorMessage;
if( (unify1 != 0) && PL_unify_atom_chars( errorMessage, msg.c_str()) != 0)
{
PL_succeed;
}
else
{
PL_fail;
}
}
/*
4 Function pl\_call\_secondo
Call Secondo. The first argument must either be an atom
representing a query in text format or it must be
a PROLOG list. The result is a PROLOG nested list
which is unified with the second argument. The command level is
set to executable. If something goes wrong, the predicate fails and
error information can be obtained via predicate secondo\_error\_info.
*/
static foreign_t
pl_call_secondo(term_t command, term_t result)
{
bool error = false;
char* commandCStr;
string commandStr;
int commandLevel;
ListExpr commandLE = plnl->TheEmptyList();
ListExpr resultList = plnl->TheEmptyList();
int errorPos;
if(PL_get_atom_chars(command, &commandCStr))
{
error = false;
commandStr = commandCStr;
/* executable command in text syntax */
commandLevel = 1;
}
else
{
commandLE = TermToListExpr(command, plnl, error);
/* executable command in nested list syntax */
commandLevel = 0;
if (error)
{
cerr << "SecondoPL: TermToListExpr() failed." << endl;
PL_fail;
}
}
lastErrorCode = 0;
si->Secondo(commandStr,
commandLE,
commandLevel,
false,
false,
resultList,
lastErrorCode,
errorPos,
lastErrorMessage);
// reset NestedList pointer for the NList interface
NList::setNLRef(plnl);
if(lastErrorCode != 0)
{
PL_fail;
}
else
{
if(PL_unify(result, ListExprToTerm(resultList, plnl)) != 0)
{
plnl->initializeListMemory();
PL_succeed;
}
else
{
cerr << "SecondoPL: Predicate secondo/2 failed, but error code was 0."
<< endl;
plnl->WriteListExpr(resultList);
}
}
PL_fail;
}
static foreign_t getOperatorIndexes(
term_t nameP, // input: name of operator
term_t argList, // input: argumentlist
term_t resList, // output: resultlist
term_t algId, // output: algebra id
term_t opId, // output: operator id
term_t funId){ // output: value mapping id
// convert operator name into a c++ string
char* nameC;
if(!PL_get_atom_chars(nameP, &nameC)){ // name not given
cout << "cannot convert name" << endl;
PL_fail;
}
// convert argument list from prolog to C++
bool error = false;
ListExpr argListC = TermToListExpr(argList, si->GetNestedList(), error);
if(error){
cout << "cannot convert arglist" << endl;
PL_fail;
}
int algIdC;
int opIdC;
int funIdC;
ListExpr resListC;
// ask System for correct values
bool ok = si->getOperatorIndexes(nameC, argListC, resListC,
algIdC, opIdC, funIdC,si->GetNestedList());
if(!ok){
//cout << "OPerator not available for arguments" << endl;
PL_fail;
}
// convert results back to prolog terms
if(!PL_unify(resList, ListExprToTerm(resListC, si->GetNestedList()))){
cerr << "PL_unify failed" << endl;
}
if(!PL_unify_integer(algId,algIdC)){
cerr << "PL_unify_interger failed" << endl;
}
if(!PL_unify_integer(opId,opIdC)){
cerr << "PL_unify_integer failed" << endl;
}
if(!PL_unify_integer(funId,funIdC)){
cerr << "PL_unify_integer failed" << endl;
}
// todo: error handling in conversion
PL_succeed;
}
/*
~readIntList~
if ~t~ is a list consisting of size integer values, these integer
values are written into the buffer res which must have enough space
for these integers. If this is successful, true is returns,
false otherwise.
*/
static bool readIntList(term_t t, int* res,size_t size){
if(!PL_is_list(t)){
return false;
}
term_t head = PL_new_term_ref();
term_t list = PL_copy_term_ref(t);
size_t pos = 0;
while(PL_get_list(list,head,list )){
if(pos>size){
cerr << "list has more than " << size << " elements" << endl;
return false;;
}
if(!PL_get_integer(head, &res[pos])){
cerr << "element " << pos << " is not an integer" << endl;
return false;;
}
pos++;
}
if(pos<size){
cerr << "list has less than " << size << " elements" << endl;
return false;
}
return true;
}
/*
~getCosts~
The next functions return costs for a specified operator when number of tuples
and size of a single tuple is given. If the operator does not provide a
cost estimation function or the getCost function is not implemented,
the return value is false.
The arguments of this functions are:
( [ algId, opId, funId ] ,
[ noTuples, sizeOfTuple, noAttributes ],
selectivity, memoryMB, costs )
Where costs is a return parameter. The first arguments are coded in a list
because prolog supports only 10 arguments for foreign functions. For this
functions this limits will be sufficient, but for versions using two input
streams not. For compability with other functions, we also here use lists
of integer values.
*/
static foreign_t getCosts5(
term_t VM_descr,
term_t stream1_descr,
term_t selectivity,
term_t memoryMB,
term_t costs) {
// convert arguments to C
int memoryMBC;
double selectivityC;
size_t costsC = 0;
int VM_descrC[3];
int stream1_descrC[3];
if(!readIntList(VM_descr,VM_descrC,3)){
cerr << " invalid [algid, opid, vmid] list " << endl;
PL_fail;
}
if(!readIntList(stream1_descr,stream1_descrC,3)){
cerr << "invalid stream description" << endl;
cerr << "must be [noTuples, sizeOfTuple, noAttributes] " << endl;
PL_fail;
}
if(!PL_get_float(selectivity,&selectivityC)){
cerr << "selectivity is not a float" << endl;
PL_fail;
}
if(!PL_get_integer(memoryMB, &memoryMBC)){
cerr << "memoryMB is not an integer" << endl;
PL_fail;
}
if(!si->getCosts( (size_t) VM_descrC[0],
(size_t) VM_descrC[1],
(size_t) VM_descrC[2],
(size_t) stream1_descrC[0],
(size_t) stream1_descrC[1],
(size_t) stream1_descrC[2],
selectivityC,
(size_t) memoryMBC, costsC)){
PL_fail;
} else {
int intCosts = (int) costsC;
if(!PL_unify_integer(costs,intCosts)){
cerr << "PL_unify_integer failed" << endl;
}
PL_succeed;
}
}
static foreign_t getCosts6(
term_t VM_descr,
term_t stream1_descr,
term_t stream2_descr,
term_t selectivity,
term_t memoryMB,
term_t costs) {
int memoryMBC;
double selectivityC;
size_t costsC = 0;
int VM_descrC[3];
int stream1_descrC[3];
int stream2_descrC[3];
if(!readIntList(VM_descr,VM_descrC,3)){
cerr << " invalid [algid, opid, vmid] list " << endl;
PL_fail;
}
if(!readIntList(stream1_descr,stream1_descrC,3)){
cerr << "invalid stream1 description" << endl;
cerr << "must be [noTuples, sizeOfTuple, noAttributes] " << endl;
PL_fail;
}
if(!readIntList(stream2_descr,stream2_descrC,3)){
cerr << "invalid stream2 description" << endl;
cerr << "must be [noTuples, sizeOfTuple, noAttributes] " << endl;
PL_fail;
}
if(!PL_get_float(selectivity,&selectivityC)){
cerr << "selectivity is not a float" << endl;
PL_fail;
}
if(!PL_get_integer(memoryMB, &memoryMBC)){
cerr << "memory is not an integer" << endl;
PL_fail;
}
if(!si->getCosts(
(size_t) VM_descrC[0], (size_t) VM_descrC[1], (size_t) VM_descrC[2],
(size_t) stream1_descrC[0],
(size_t) stream1_descrC[1],
(size_t) stream1_descrC[2],
(size_t) stream2_descrC[0],
(size_t) stream2_descrC[1],
(size_t) stream2_descrC[2],
selectivityC, (size_t) memoryMBC, costsC)){
PL_fail;
} else {
int intCosts = (int) costsC;
if(!PL_unify_integer(costs,intCosts)){
cerr << "PL_unify_integer failed" << endl;
}
PL_succeed;
}
}
/*
~getLinearParams~
Retrieves the parameters for estimating the cost function of an operator
in a linear way.
*/
static foreign_t getLinearParams6(
term_t VM_descr,
term_t stream1_descr,
term_t selectivity,
term_t sufficientMemory,
term_t timeAtSuffMemory,
term_t timeAt16MB) {
int VM_descrC[3];
if(!readIntList(VM_descr,VM_descrC,3)){
cerr << "invalid [algId, opId, funId] list" << endl;
PL_fail;
}
int stream1_descrC[3];
if(!readIntList(stream1_descr,stream1_descrC,3)){
cerr << "invalid [noTuples, sizeOfTuples, noAttribute] list" << endl;
PL_fail;
}
double selectivityC;
if(!PL_get_float(selectivity, &selectivityC)){
cerr << "selectivity is not a float" << endl;
PL_fail;
}
double sufficientMemoryC = 0;
double timeAtSuffMemoryC = 0;
double timeAt16MBC = 0;
if(!si->getLinearParams(
VM_descrC[0], VM_descrC[1], VM_descrC[2],
stream1_descrC[0], stream1_descrC[1], stream1_descrC[2],
selectivity, sufficientMemoryC,timeAtSuffMemoryC,timeAt16MBC)){
PL_fail;
} else {
if(
!PL_unify_float(sufficientMemory,sufficientMemoryC)
|| !PL_unify_float(timeAtSuffMemory, timeAtSuffMemoryC)
|| !PL_unify_float(timeAt16MB, timeAt16MBC)){
cerr << "PL_unify_float failed" << endl;
}
PL_succeed;
}
}
static foreign_t getLinearParams7(
term_t VM_descr,
term_t stream1_descr,
term_t stream2_descr,
term_t selectivity,
term_t sufficientMemory,
term_t timeAtSuffMemory,
term_t timeAt16MB) {
int VM_descrC[3];
if(!readIntList(VM_descr, VM_descrC, 3)){
cerr << "invalid [algId, opId, funId] list" << endl;
PL_fail;
}
int stream1_descrC[3];
if(!readIntList(stream1_descr, stream1_descrC,3)){
cerr << "invalid [noTuples1, tupleSize1, noAttributes1 ] list" << endl;
PL_fail;
}
int stream2_descrC[3];
if(!readIntList(stream2_descr, stream2_descrC,3)){
cerr << "invalid [noTuples2, tupleSize2, noAttributes2 ] list" << endl;
PL_fail;
}
double selectivityC;
if(!PL_get_float(selectivity, &selectivityC)){
cerr << "selectivity is not a float" << endl;
PL_fail;
}
double sufficientMemoryC = 0;
double timeAtSuffMemoryC = 0;
double timeAt16MBC = 0;
if(!si->getLinearParams(
VM_descrC[0], VM_descrC[1], VM_descrC[2],
stream1_descrC[0], stream1_descrC[1], stream1_descrC[2],
stream2_descrC[0], stream2_descrC[1], stream2_descrC[2],
selectivityC, sufficientMemoryC,timeAtSuffMemoryC,timeAt16MBC)){
PL_fail;
} else {
if( !PL_unify_float(sufficientMemory,sufficientMemoryC)
|| !PL_unify_float(timeAtSuffMemory, timeAtSuffMemoryC)
|| !PL_unify_float(timeAt16MB, timeAt16MBC)){
cerr << "PL_unify_floar failed" << endl;
}
PL_succeed;
}
}
/*
~getFunction~
Returns an approximation of the cost function of a specified value mapping as
a parametrized function.
dlist will be a list containing 7 double values
(sufficientMemory, timeAtSuffMemory, timeAt16MB, a,b,c,d)
*/
static foreign_t getFunction5(
term_t VM_descr,
term_t stream1_descr,
term_t selectivity,
term_t funType,
term_t dlist) {
int VM_descrC[3];
if(!readIntList(VM_descr, VM_descrC, 3)){
cerr << "invalid [algId, opId, funId] list" << endl;
PL_fail;
}
int stream1_descrC[3];
if(!readIntList(stream1_descr, stream1_descrC,3)){
cerr << "invalid [noTuples1, noTuples1, noAttributes1 ] list" << endl;
PL_fail;
}
double selectivityC;
if(!PL_get_float(selectivity, &selectivityC)){
cerr << "selectivity is not a float" << endl;
PL_fail;
}
int funTypeC = -1;
double sufficientMemoryC = 0;
double timeAtSuffMemoryC = 0;
double timeAt16MBC = 0;
double aC,bC,cC,dC;
aC = bC = cC = dC = 0;
if(!si->getFunction(
VM_descrC[0], VM_descrC[1], VM_descrC[2],
stream1_descrC[0], stream1_descrC[1], stream1_descrC[2],
selectivityC,
funTypeC, sufficientMemoryC,timeAtSuffMemoryC,timeAt16MBC,
aC,bC,cC,dC)){
PL_fail;
} else {
if(!PL_unify_integer(funType,funTypeC)){
cerr << "PL_unify_integer failed" << endl;
}
NestedList* nl = si->GetNestedList();
ListExpr clist = nl->OneElemList(nl->RealAtom(sufficientMemoryC));
ListExpr last = clist;
last = nl->Append(last, nl->RealAtom(timeAtSuffMemoryC));
last = nl->Append(last, nl->RealAtom(timeAt16MBC));
last = nl->Append(last, nl->RealAtom(aC));
last = nl->Append(last, nl->RealAtom(bC));
last = nl->Append(last, nl->RealAtom(cC));
last = nl->Append(last, nl->RealAtom(dC));
if(!PL_unify(dlist, ListExprToTerm(clist, nl))){
cerr << "PL_unify failed" << endl;
}
PL_succeed;
}
}
static foreign_t getFunction6(
term_t VM_descr,
term_t stream1_descr,
term_t stream2_descr,
term_t selectivity,
term_t funType,
term_t dlist ){
int VM_descrC[3];
if(!readIntList(VM_descr,VM_descrC,3)){
cerr << "invalid [algId, opId, funId] list" << endl;
PL_fail;
}
int stream1_descrC[3];
if(!readIntList(stream1_descr, stream1_descrC, 3)){
cerr << "invalid [noTuples1, noTuples1, noAttributes1] list" << endl;
PL_fail;
}
int stream2_descrC[3];
if(!readIntList(stream2_descr, stream2_descrC, 3)){
cerr << "invalid [noTuples2, noTuples2, noAttributes2] list" << endl;
PL_fail;
}
double selectivityC;
if(!PL_get_float(selectivity, &selectivityC)){
cerr << "selectivity is not a float" << endl;
PL_fail;
}
int funTypeC = -1;
double sufficientMemoryC = 0;
double timeAtSuffMemoryC = 0;
double timeAt16MBC = 0;
double aC,bC,cC,dC;
aC = bC = cC = dC = 0;
if(!si->getFunction(
VM_descrC[0], VM_descrC[1], VM_descrC[2],
stream1_descrC[0], stream1_descrC[1], stream1_descrC[2],
stream2_descrC[0], stream2_descrC[1], stream2_descrC[2],
selectivity,
funTypeC, sufficientMemoryC,timeAtSuffMemoryC,timeAt16MBC,
aC,bC,cC,dC)){
PL_fail;
} else {
if(!PL_unify_integer(funType,funTypeC)){
cerr << "PL_unify_integer failed" << endl;
}
NestedList* nl = si->GetNestedList();
ListExpr clist = nl->OneElemList(nl->RealAtom(sufficientMemoryC));
ListExpr last = clist;
last = nl->Append(last, nl->RealAtom(timeAtSuffMemoryC));
last = nl->Append(last, nl->RealAtom(timeAt16MBC));
last = nl->Append(last, nl->RealAtom(aC));
last = nl->Append(last, nl->RealAtom(bC));
last = nl->Append(last, nl->RealAtom(cC));
last = nl->Append(last, nl->RealAtom(dC));
if(!PL_unify(dlist, ListExprToTerm(clist, nl))){
cerr << "PL_unify failed" << endl;
}
PL_succeed;
}
}
/*
This functions check a sql construct (given as an atom)
to be valid using an external parser. On succeed, the
function will fail. Otherwise, the function succeeds and
returns the error message using the second argument.
*/
static foreign_t
pl_check_syntax(term_t command, term_t result)
{
char* commandstr = 0;
int ok1 = PL_get_chars(command,&commandstr, CVT_ALL);
if(!ok1){
if(!PL_unify_atom_chars(result,"cannot create command")){
cerr << "Cannot return result, please use an "
<< "Variable as the second argument" << endl;
}
PL_succeed;
}
char* errorMessage = 0;
bool ok = checkOptimizerQuery(commandstr, errorMessage);
if(ok){
if(errorMessage){
free(errorMessage);
}
PL_fail;
} else {
if(errorMessage){
if(!PL_unify_atom_chars(result,errorMessage)){
cerr << "cannot return the error message, may be "
<< " the second arguemnt is not a variable" << endl;
cerr << "errorMessage = " << errorMessage << endl;
}
free(errorMessage);
} else {
if(!PL_unify_atom_chars(result,"No error Message available")){
cerr << "cannot return the error message, may be "
<< " the second arguemnt is not a variable" << endl;
cerr << "Internal error, no success, but no error message" << endl;
}
}
PL_succeed;
}
}
/*
Transfers an option the the sql checker parser. Fails, if the option is unknown
or one of the arguments could not be evaluated.
*/
static foreign_t
pl_set_sql_check_option(term_t optionName, term_t enable)
{
char* optionNameStr = 0;
// get the option name
if(! PL_get_chars(optionName,&optionNameStr, CVT_ALL)){
PL_fail;
}
// try to get the boolean parameter
int enableBool;
if(!PL_get_bool(enable,&enableBool)){
PL_fail;
}
bool ok = setSqlParserOption(optionNameStr, enableBool);
if(ok){
PL_succeed;
} else {
PL_fail;
}
}
/*
4 Function pl\_maximize\_entropy
Function to compute the remaining conditional probabilities.
Syntax:
----
maximize_entropy( [[1, p1] [2, p2] ... ], [[3, cp1], [5, cp2] ...], R )
----
pi, cpi are floating point values.
*/
#ifdef SECONDO_USE_ENTROPY
static foreign_t
pl_maximize_entropy(term_t predicates, term_t probabilities, term_t result)
{
// Type checking.
if( !PL_is_list(predicates) || !PL_is_list(probabilities) )
PL_fail;
else
{
//ProbabilityVec vectorPredicates;
ProbabilityPairVec vectorPredicates, vectorProbabilities, vectorResult;
bool error1=false, error2=false;
//FloatListToVector(predicates, vectorPredicates, error1);
FloatListPairToVectorPair(predicates, vectorPredicates, error1);
FloatListPairToVectorPair(probabilities, vectorProbabilities, error2);
if( error1 || error2 )
PL_fail;
else
{
bool error=false;
try
{
maximize_entropy( vectorPredicates,
vectorProbabilities,
vectorResult );
FloatVectorPairToListPair(vectorResult, result, error);
}
catch(...)
{
PL_fail;
}
if( error )
PL_fail;
}
PL_succeed;
}
}
#endif
/*
NVK ADDED MA
Forwards the GlobalMemory property to the prolog environment.
This should be improved by someone who is more familiar with secondo's kernel.
The code in comments won't work, as soon as i include the QueryProcessor.h, secondo won't compile successfully anymore.
Note that GetGlobalMemory function needs to be implemented fist within QueryProcessor.cpp and QueryProcessor.h.
*/
/*
static foreign_t pl_global_memory(term_t value) {
string sbd = getenv("SECONDO_BUILD_DIR");
int globalMem = 512; // Unit: MiB
if(sbd.length()>0) {
globalMem = SmiProfile::GetParameter("QueryProcessor", "GlobalMemory", 512,
sbd + "/bin/SecondoConfig.ini");
}
else
PL_fail;
int unify1 = PL_unify_integer(value, globalMem);
if(unify1 != 0) {
PL_succeed;
}
else {
PL_fail;
}
}
*/
// NVK ADDED MA END
#if PLVERSION>60000
#define PL_FUNCTION_T pl_function_t
#else
#define PL_FUNCTION_T void*
#endif
PL_extension predicates[] =
{
{ "secondo", 2, (PL_FUNCTION_T)pl_call_secondo, 0 },
{ "secondo_error_info", 2, (PL_FUNCTION_T)pl_get_error_info, 0 },
{ "secondo_print_le", 1, (PL_FUNCTION_T)pl_print_term_le, 0 },
{ "check_syntax",2, (PL_FUNCTION_T)pl_check_syntax,0},
{ "set_sql_check_option",2,(PL_FUNCTION_T)pl_set_sql_check_option,0},
{ "getOpIndexes",6,(PL_FUNCTION_T)getOperatorIndexes,0},
{ "getCosts",5,(PL_FUNCTION_T)getCosts5,0},
{ "getCosts",6,(PL_FUNCTION_T)getCosts6,0},
{ "getLinearCostFun",6,(PL_FUNCTION_T)getLinearParams6,0},
{ "getLinearCostFun",7,(PL_FUNCTION_T)getLinearParams7,0},
{ "getCostFun",5,(PL_FUNCTION_T)getFunction5,0},
{ "getCostFun",6,(PL_FUNCTION_T)getFunction6,0},
#ifdef SECONDO_USE_ENTROPY
{ "maximize_entropy", 3, (PL_FUNCTION_T)pl_maximize_entropy, 0 },
#endif
// NVK ADDED MA
#ifdef SECONDO_USE_MEMORY_ALLOCATION
{ "secondo_global_memory", 1, (PL_FUNCTION_T)pl_global_memory, 0 },
{ "memoryOptimization", 6, (PL_FUNCTION_T)pl_memoryOptimization, 0 },
#endif
// NVK ADDED MA END
{ 0, 0, 0, 0 } /* terminating line */
};
/*
8 Function StartSecondoC
Starts Secondo. Assumes that the argument is the name of the
configuration file. Return true iff successful.
*/
bool
StartSecondoC(TTYParameter& tp)
{
if ( !tp.CheckConfiguration() ) {
return false;
}
//tp.Print(cout);
#if !defined(SECONDO_CLIENT_SERVER) && !defined(REPLAY)
si = new SecondoInterfaceTTY();
#elif defined(SECONDO_CLIENT_SERVER)
si = new SecondoInterfaceCS(false,0,true);
#elif defined(REPLAY)
si = new SecondoInterfaceREPLAY();
#else
si = new SecondoInterfaceCS(false,0,true);
#endif
string errorMsg("");
if(si->Initialize(tp.user, tp.pswd, tp.host, tp.port, tp.parmFile, tp.home,
errorMsg))
{
plnl = si->GetNestedList();
NList::setNLRef(plnl);
return true;
}
else
{
delete si;
si = 0;
cout
<< "Error while starting Secondo with config file "
<< tp.parmFile << "." << endl
<< errorMsg << endl;
return false;
}
}
/*
9. registerSecondo
This function registers the secondo predicate at the prolog engine.
*/
int registerSecondo(){
//cout << "register secondo" << endl;
TTYParameter tp(0,0);
atexit(handle_exit);
if( !StartSecondoC(tp) )
{
return -1;
}
/* Start PROLOG interpreter with our extensions. */
PL_register_extensions(predicates);
return 0;
}