bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
TabularSequence.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) 2015 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#include <algorithm>
28#include <string>
29#include <sstream>
30
31//#define DODS_DEBUG
32
33#include <libdap/BaseType.h>
34#include <libdap/Byte.h>
35#include <libdap/Int16.h>
36#include <libdap/Int32.h>
37#include <libdap/UInt16.h>
38#include <libdap/UInt32.h>
39#include <libdap/Float32.h>
40#include <libdap/Float64.h>
41#include <libdap/Str.h>
42#include <libdap/Url.h>
43
44#include <libdap/DDS.h>
45#include <libdap/ConstraintEvaluator.h>
46#include <libdap/Marshaller.h>
47#include <libdap/UnMarshaller.h>
48#include <libdap/debug.h>
49
50#include "BESIndent.h"
51#include "TabularSequence.h"
52
53using namespace std;
54using namespace libdap;
55
56namespace functions {
57
58// static constants and functions copied from the parent class. These
59// should never have been static... hindsight
60
61static const unsigned char end_of_sequence = 0xA5; // binary pattern 1010 0101
62static const unsigned char start_of_instance = 0x5A; // binary pattern 0101 1010
63
64static void
65write_end_of_sequence(Marshaller &m)
66{
67 m.put_opaque( (char *)&end_of_sequence, 1 ) ;
68}
69
70static void
71write_start_of_instance(Marshaller &m)
72{
73 m.put_opaque( (char *)&start_of_instance, 1 ) ;
74}
75
76void TabularSequence::load_prototypes_with_values(BaseTypeRow &btr, bool safe)
77{
78 // For each of the prototype variables in the Sequence, load it
79 // with a values from the BaseType* vector. The order should match.
80 // Test the type, but assume if that matches, the value is correct
81 // for the variable.
82 Vars_iter i = d_vars.begin(), e = d_vars.end();
83 for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
84
85 if (safe && (i == e || ((*i)->type() != (*vi)->var()->type())))
86 throw InternalErr(__FILE__, __LINE__, "Expected number and types to match when loading values for selection expression evaluation.");
87
88 // Ugly... but faster than the generic code that allocates storage for each scalar?
89 switch ((*i)->type()) {
90 case dods_byte_c:
91 static_cast<Byte*>(*i++)->set_value(static_cast<Byte*>(*vi)->value());
92 break;
93 case dods_int16_c:
94 static_cast<Int16*>(*i++)->set_value(static_cast<Int16*>((*vi))->value());
95 break;
96 case dods_int32_c:
97 static_cast<Int32*>(*i++)->set_value(static_cast<Int32*>((*vi))->value());
98 break;
99 case dods_uint16_c:
100 static_cast<UInt16*>(*i++)->set_value(static_cast<UInt16*>((*vi))->value());
101 break;
102 case dods_uint32_c:
103 static_cast<UInt32*>(*i++)->set_value(static_cast<UInt32*>((*vi))->value());
104 break;
105 case dods_float32_c:
106 static_cast<Float32*>(*i++)->set_value(static_cast<Float32*>((*vi))->value());
107 break;
108 case dods_float64_c:
109 static_cast<Float64*>(*i++)->set_value(static_cast<Float64*>((*vi))->value());
110 break;
111 case dods_str_c:
112 static_cast<Str*>(*i++)->set_value(static_cast<Str*>((*vi))->value());
113 break;
114 case dods_url_c:
115 static_cast<Url*>(*i++)->set_value(static_cast<Url*>((*vi))->value());
116 break;
117 default:
118 throw InternalErr(__FILE__, __LINE__, "Expected a scalar type when loading values for selection expression evaluation.");
119 }
120 }
121}
122
123// Public member functions
124
141bool
142TabularSequence::serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval /* true */)
143{
144 DBG(cerr << "Entering TabularSequence::serialize for " << name() << endl);
145
146 SequenceValues &values = value_ref();
147 //ce_eval = true; Commented out here and changed in BESDapResponseBuilder. jhrg 3/10/15
148
149 for (SequenceValues::iterator i = values.begin(), e = values.end(); i != e; ++i) {
150
151 BaseTypeRow &btr = **i;
152
153 // Transfer values of the current row into the Seq's prototypes so the CE
154 // evaluator will find the values.
155#if 1
156 load_prototypes_with_values(btr, false);
157#else
158 int j = 0;
159 for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
160 void *val = 0;
161 (*vi)->buf2val(&val);
162 d_vars.at(j++)->val2buf(val);
163 }
164#endif
165 DBG(cerr << __func__ << ": Sequence element: " << hex << *btr.begin() << dec << endl);
166 // Evaluate the CE against this row; continue (skipping this row) if it fails
167 if (ce_eval && !eval.eval_selection(dds, dataset()))
168 continue;
169
170 // Write out this row of values
171 write_start_of_instance(m);
172
173 // In this loop serialize will signal an error with an exception.
174 for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
175 if ((*vi)->send_p()) {
176 (*vi)->serialize(eval, dds, m, false);
177 }
178 }
179 }
180
181 write_end_of_sequence(m);
182
183 return true; // Signal errors with exceptions.
184}
185
195void TabularSequence::intern_data(ConstraintEvaluator &eval, DDS &dds)
196{
197 DBG(cerr << "Entering TabularSequence::intern_data" << endl);
198
199 // TODO Special case when there are no selection clauses
200 // TODO Use a destructive copy to move values from 'values' to
201 // result? Or pop values - find a way to not copy all the values
202 // after doing some profiling to see if this code can be meaningfully
203 // optimized
204 SequenceValues result; // These values satisfy the CE
205 SequenceValues &values = value_ref();
206
207 for (SequenceValues::iterator i = values.begin(), e = values.end(); i != e; ++i) {
208
209 BaseTypeRow &btr = **i;
210
211 // Transfer values of the current row into the Seq's prototypes so the CE
212 // evaluator will find the values.
213 load_prototypes_with_values(btr, false /* safe */);
214#if 0
215 int j = 0;
216 for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
217 // TODO check this for efficiency - is the switch-based version (load_prototypes_with_values) faster?
218 void *val = 0;
219 (*vi)->buf2val(&val);
220 d_vars.at(j++)->val2buf(val);
221 }
222#endif
223 // Evaluate the CE against this row; continue (skipping this row) if it fails
224 if (!eval.eval_selection(dds, dataset()))
225 continue;
226
227 BaseTypeRow *result_row = new BaseTypeRow();
228 for (BaseTypeRow::iterator vi = btr.begin(), ve = btr.end(); vi != ve; ++vi) {
229 if ((*vi)->send_p()) {
230 result_row->push_back(*vi);
231 }
232 }
233
234 result.push_back(result_row);
235 }
236
237 set_value(result);
238
239 DBG(cerr << "Leaving TabularSequence::intern_data" << endl);
240}
241
250void
251TabularSequence::dump(ostream &strm) const
252{
253 strm << BESIndent::LMarg << "TabularSequence::dump - (" << (void *)this << ")" << endl ;
254 BESIndent::Indent() ;
255 Sequence::dump(strm) ;
256 BESIndent::UnIndent() ;
257}
258
259} // namespace functions
260
virtual void dump(ostream &strm) const
dumps information about this object
virtual void intern_data(libdap::ConstraintEvaluator &eval, libdap::DDS &dds)
virtual bool serialize(libdap::ConstraintEvaluator &eval, libdap::DDS &dds, libdap::Marshaller &m, bool ce_eval=true)