libdap  Updated for version 3.20.6
libdap4 is an implementation of OPeNDAP's DAP protocol.
ConstraintEvaluator.cc
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2002,2003 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 #include "config.h"
26 
27 //#define DODS_DEBUG
28 
29 #include "ServerFunctionsList.h"
30 #include "ConstraintEvaluator.h"
31 #include "Clause.h"
32 #include "DataDDS.h"
33 
34 #include "ce_parser.h"
35 #include "debug.h"
36 #include "parser.h"
37 #include "expr.h"
38 
39 struct yy_buffer_state;
40 
41 int ce_exprparse(libdap::ce_parser_arg *arg);
42 
43 // Glue routines declared in expr.lex
44 void ce_expr_switch_to_buffer(void *new_buffer);
45 void ce_expr_delete_buffer(void * buffer);
46 void *ce_expr_string(const char *yy_str);
47 
48 namespace libdap {
49 
50 ConstraintEvaluator::ConstraintEvaluator()
51 {
52  // Functions are now held in BES modules. jhrg 1/30/13
53 
54  // modules load functions to this list; this class searches the list
55  // instead of having it's own copy. This is very similar to the BES'
56  // various List classes, but this one is part of libdap and not the
57  // BES. The List class is a singleton, so each function module can
58  // register it's functions to the list object.
59  d_functions_list = ServerFunctionsList::TheList();
60 }
61 
62 ConstraintEvaluator::~ConstraintEvaluator()
63 {
64  // delete all the constants created by the parser for CE evaluation
65  for (Constants_iter j = constants.begin(); j != constants.end(); j++) {
66  BaseType *btp = *j;
67  delete btp;
68  btp = 0;
69  }
70 
71  for (Clause_iter k = expr.begin(); k != expr.end(); k++) {
72  Clause *cp = *k;
73  delete cp;
74  cp = 0;
75  }
76 }
77 
79 ConstraintEvaluator::Clause_iter ConstraintEvaluator::clause_begin()
80 {
81  return expr.begin();
82 }
83 
86 ConstraintEvaluator::Clause_iter ConstraintEvaluator::clause_end()
87 {
88  return expr.end();
89 }
90 
93 bool ConstraintEvaluator::clause_value(Clause_iter &iter, DDS &dds/*, const string &***/)
94 {
95  if (expr.empty())
96  throw InternalErr(__FILE__, __LINE__, "There are no CE clauses for *this* DDS object.");
97 
98  return (*iter)->value(dds);
99 }
100 
113 void ConstraintEvaluator::append_clause(int op, rvalue *arg1, rvalue_list *arg2)
114 {
115  Clause *clause = new Clause(op, arg1, arg2);
116 
117  expr.push_back(clause);
118 }
119 
129 void ConstraintEvaluator::append_clause(bool_func func, rvalue_list *args)
130 {
131  Clause *clause = new Clause(func, args);
132 
133  expr.push_back(clause);
134 }
135 
145 void ConstraintEvaluator::append_clause(btp_func func, rvalue_list *args)
146 {
147  Clause *clause = new Clause(func, args);
148 
149  expr.push_back(clause);
150 }
151 
160 {
161  constants.push_back(btp);
162 }
163 
165 bool ConstraintEvaluator::find_function(const string &name, bool_func *f) const
166 {
167  return d_functions_list->find_function(name, f);
168 }
169 
171 bool ConstraintEvaluator::find_function(const string &name, btp_func *f) const
172 {
173  return d_functions_list->find_function(name, f);
174 }
175 
177 bool ConstraintEvaluator::find_function(const string &name, proj_func *f) const
178 {
179  return d_functions_list->find_function(name, f);
180 }
182 
192 {
193  if (expr.empty())
194  return false;
195 
196  Clause *cp = expr[0];
197  return cp->value_clause();
198 }
199 
203 BaseType *
205 {
206  if (expr.size() != 1)
207  throw InternalErr(__FILE__, __LINE__, "The length of the list of CE clauses is not 1.");
208 
209  Clause *cp = expr[0];
210  BaseType *result;
211  if (cp->value(dds, &result))
212  return result;
213  else
214  return NULL;
215 }
216 
227 {
228  if (expr.empty())
229  return false;
230 
231  for (unsigned int i = 0; i < expr.size(); ++i) {
232  Clause *cp = expr[i];
233  if (!cp->value_clause())
234  return false;
235  }
236 
237  return true;
238 }
239 
255 DDS *
257 {
258  if (expr.empty())
259  throw InternalErr(__FILE__, __LINE__, "The constraint expression is empty.");
260 
261  DDS *fdds = new DDS(dds.get_factory(), "function_result_" + dds.get_dataset_name());
262  for (unsigned int i = 0; i < expr.size(); ++i) {
263  Clause *cp = expr[i];
264  BaseType *result;
265  if (cp->value(dds, &result)) {
266  // This is correct: The function must allocate the memory for the result
267  // variable. 11/30/12 jhrg
268  fdds->add_var_nocopy(result);
269  }
270  else {
271  delete fdds;
272  throw Error(internal_error, "A function was called but failed to return a value.");
273  }
274  }
275 
276  return fdds;
277 }
278 
284 DataDDS *
286 {
287  if (expr.empty())
288  throw InternalErr(__FILE__, __LINE__, "The constraint expression is empty.");
289 
290  DataDDS *fdds = new DataDDS(dds.get_factory(), "function_result_" + dds.get_dataset_name(), dds.get_version(),
291  dds.get_protocol());
292 
293  for (unsigned int i = 0; i < expr.size(); ++i) {
294  Clause *cp = expr[i];
295  BaseType *result;
296  if (cp->value(dds, &result)) {
297  fdds->add_var_nocopy(result);
298  }
299  else {
300  delete fdds;
301  throw Error(internal_error, "A function was called but failed to return a value.");
302  }
303  }
304 
305  return fdds;
306 }
307 
310 {
311  if (expr.empty())
312  return false;
313 
314  bool boolean = true;
315  for (Clause_iter i = expr.begin(); i != expr.end(); i++) {
316  boolean = boolean && (*i)->boolean_clause();
317  }
318 
319  return boolean;
320 }
321 
329 bool ConstraintEvaluator::eval_selection(DDS &dds, const string &)
330 {
331  if (expr.empty()) {
332  DBG(cerr << "No selection recorded" << endl);
333  return true;
334  }
335 
336  DBG(cerr << "Eval selection" << endl);
337 
338  // A CE is made up of zero or more clauses, each of which has a boolean
339  // value. The value of the CE is the logical AND of the clause
340  // values. See ConstraintEvaluator::clause::value(...) for information on logical ORs in
341  // CEs.
342  bool result = true;
343  for (Clause_iter i = expr.begin(); i != expr.end() && result; i++) {
344  // A selection expression *must* contain only boolean clauses!
345  if (!((*i)->boolean_clause()))
346  throw InternalErr(__FILE__, __LINE__, "A selection expression must contain only boolean clauses.");
347  result = result && (*i)->value(dds);
348  }
349 
350  return result;
351 }
352 
363 void ConstraintEvaluator::parse_constraint(const string &constraint, DDS &dds)
364 {
365  void *buffer = ce_expr_string(constraint.c_str());
366 
367  ce_expr_switch_to_buffer(buffer);
368 
369  ce_parser_arg arg(this, &dds);
370 
371  // For all errors, exprparse will throw Error.
372  try {
373  ce_exprparse(&arg);
374  ce_expr_delete_buffer(buffer);
375  }
376  catch (...) {
377  // Make sure to remove the buffer when there's an error
378  ce_expr_delete_buffer(buffer);
379  throw;
380  }
381 }
382 
383 } // namespace libdap
bool boolean_expression()
Does the current constraint expression return a boolean value?
bool find_function(const std::string &name, bool_func *f) const
Find a Boolean function with a given name in the function list.
virtual bool find_function(const std::string &name, bool_func *f) const
Find a boolean function with a given name in the function list.
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:613
string get_dataset_name() const
Definition: DDS.cc:356
BaseType * eval_function(DDS &dds, const std::string &dataset)
Evaluate a function-valued constraint expression.
top level DAP object to house generic methods
Definition: AISConnect.cc:30
A class for software fault reporting.
Definition: InternalErr.h:64
bool value(DDS &dds)
Evaluate a clause which returns a boolean value This method must only be evaluated for clauses with r...
Definition: Clause.cc:156
DDS * eval_function_clauses(DDS &dds)
Evaluate a function-valued constraint expression that contains several function calls.
void parse_constraint(const std::string &constraint, DDS &dds)
Parse the constraint expression given the current DDS.
bool functional_expression()
Does the current constraint expression return a BaseType pointer? This method does not evaluate the c...
string get_version() const
Get the server version string, unparsed.
Definition: DataDDS.h:109
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
void append_constant(BaseType *btp)
bool clause_value(Clause_iter &i, DDS &dds)
bool eval_selection(DDS &dds, const std::string &dataset)
Evaluate a boolean-valued constraint expression. This is main method for the evaluator and is called ...
Holds a fragment of a constraint expression.
Definition: Clause.h:90
bool function_clauses()
Does the current constraint expression contain function clauses.
A class for error processing.
Definition: Error.h:92
BaseTypeFactory * get_factory() const
Definition: DDS.h:242
bool value_clause()
Return true if the clause returns a value in a BaseType pointer.
Definition: Clause.cc:138
Holds a DAP2 DDS.
Definition: DataDDS.h:77
void append_clause(int op, rvalue *arg1, rvalue_list *arg2)
Add a clause to a constraint expression.