IODA Bundle
SQLSelectOutput.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 1996-2012 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #include <limits>
12 #include <algorithm>
13 #include <numeric>
14 
15 #include "eckit/eckit.h"
16 #include "eckit/log/Number.h"
17 
18 #include "eckit/sql/SQLSelect.h"
19 #include "eckit/sql/expression/SQLExpression.h"
20 
22 #include "odc/sql/Types.h"
23 
24 
25 using namespace eckit;
26 using namespace eckit::sql;
27 
28 namespace odc {
29 namespace sql {
30 
31 //----------------------------------------------------------------------------------------------------------------------
32 
33 // TODO: n.b. We can implement an optimised case if the output buffer matches the buffer in the
34 // innards of the select, which just does a memcpy. It will be a bit messy, but this
35 // is probably the place to do it (although it may rather belong in eckit).
36 
37 SQLSelectOutput::SQLSelectOutput(bool manageOwnBuffer) :
38  out_(0),
39  pos_(0),
40  end_(0),
41  bufferElements_(0),
42  count_(0),
43  manageOwnBuffer_(manageOwnBuffer) {}
44 
46 
47 void SQLSelectOutput::resetBuffer(double* out, size_t count) {
48 
49  // The fortran interface doesn't pass in the buffer size, so just assume it is correct
50  // if the size is specified to be zero
51  if (count == 0) count = requiredBufferSize_;
52 
53  ASSERT(!manageOwnBuffer_);
54  out_ = pos_ = out;
55  end_ = out_ + count;
58 }
59 
60 void SQLSelectOutput::print(std::ostream& s) const {
61  s << "SQLSelectOutput";
62 }
63 
64 
67 
68 bool SQLSelectOutput::output(const expression::Expressions& results)
69 {
70  ASSERT(results.size() == columnSizesDoubles_.size());
71  pos_ = out_;
73  results[currentColumn_]->output(*this);
74  }
75  ASSERT(pos_ == end_);
76  count_++;
77  return true;
78 }
79 
80 
82  ASSERT(pos_ >= out_ && pos_ < end_);
83  *pos_++ = x;
84 }
85 
86 // TODO: We can add special missing-value behaviour here --- with user specified missing values!
87 
88 void SQLSelectOutput::outputReal(double x, bool missing) { outputNumber(x); }
89 void SQLSelectOutput::outputDouble(double x, bool missing) { outputNumber(x); }
90 void SQLSelectOutput::outputInt(double x, bool missing) { outputNumber(x); }
91 void SQLSelectOutput::outputUnsignedInt(double x, bool missing) { outputNumber(x); }
92 void SQLSelectOutput::outputBitfield(double x, bool missing) { outputNumber(x); }
93 
94 void SQLSelectOutput::outputString(const char* s, size_t len, bool missing) {
95 
96  ASSERT(pos_ >= out_ && (pos_ + columnSizesDoubles_[currentColumn_]) <= end_);
97 
98  size_t charSize = columnSizesDoubles_[currentColumn_] * sizeof(double);
99  if (len > charSize) {
100  std::ostringstream ss;
101  ss << "String too long for configured output: " << len << " > " << charSize;
102  throw SeriousBug(ss.str(), Here());
103  }
104 
105  if (missing) {
106  len = 0;
107  } else {
108  ::memcpy(reinterpret_cast<char*>(pos_), s, len);
109  }
110 
111  if (len < charSize) {
112  ::memset(&reinterpret_cast<char*>(pos_)[len], 0, charSize-len);
113  }
114 
116 }
117 
118 
119 void SQLSelectOutput::prepare(SQLSelect& sql) {
120  updateTypes(sql);
121 }
122 
123 void SQLSelectOutput::updateTypes(SQLSelect& sql) {
124 
125  size_t offset = 0;
126  expression::Expressions output(sql.output());
127  metaData_.setSize(output.size());
128  offsets_.clear();
129  offsets_.reserve(output.size());
130  columnSizesDoubles_.clear();
131  columnSizesDoubles_.reserve(output.size());
132 
133  // TODO: What happens here if the metadata/columns change during an odb?
134  // --> We need to update this allocation as we go.
135 
136  for (size_t i = 0; i < output.size(); i++) {
137 
138  // Column sizes for output
139 
140  const auto& column(output[i]);
141  size_t colSizeBytes = column->type()->size();
142  ASSERT(colSizeBytes % 8 == 0);
143 
144  columnSizesDoubles_.push_back(colSizeBytes / 8);
145  offsets_.push_back(offset);
146  offset += columnSizesDoubles_.back();
147 
148  // Update the metadata
149 
150  metaData_[i]->name(column->title());
151  metaData_[i]->type<core::SameByteOrder>(sqlToOdbType(*column->type()));
152  metaData_[i]->hasMissing(column->hasMissingValue());
153  metaData_[i]->missingValue(column->missingValue());
154  metaData_[i]->bitfieldDef(column->bitfieldDef());
155  metaData_[i]->dataSizeDoubles(columnSizesDoubles_.back());
156  }
157 
158  requiredBufferSize_ = std::accumulate(columnSizesDoubles_.begin(), columnSizesDoubles_.end(), 0);
159 
160  // Buffer allocation if necessary
161 
162  if (manageOwnBuffer_) {
163  data_.resize(offset);
164  pos_ = out_ = &data_[0];
165  end_ = pos_ + offset;
166  bufferElements_ = offset;
167 
168  // If a buffer is being provided at the time of doing each request, then we need to
169  // test against the buffer size then, not now.
171  }
172 }
173 
174 void SQLSelectOutput::cleanup(SQLSelect& sql) {}
175 
176 unsigned long long SQLSelectOutput::count() { return count_; }
177 
178 //----------------------------------------------------------------------------------------------------------------------
179 
180 } // namespace sql
181 } // namespace odc
static void count(void *counter, const double *data, size_t n)
Definition: UnitTests.cc:531
void setSize(size_t)
Definition: MetaData.cc:64
virtual void outputDouble(double, bool)
virtual void outputString(const char *, size_t, bool)
std::vector< size_t > columnSizesDoubles_
How are writes carried out.
virtual void cleanup(eckit::sql::SQLSelect &)
virtual void outputUnsignedInt(double, bool)
virtual void updateTypes(eckit::sql::SQLSelect &)
virtual unsigned long long count()
virtual void outputInt(double, bool)
virtual void outputReal(double, bool)
virtual void print(std::ostream &) const
double * out_
Where are we writing data to (and how many elements can we write)
void resetBuffer(double *out, size_t count)
std::vector< size_t > offsets_
virtual void outputBitfield(double, bool)
unsigned long long count_
How much output have we done.
std::vector< double > data_
Only used if managing own buffer.
virtual bool output(const eckit::sql::expression::Expressions &)
virtual void prepare(eckit::sql::SQLSelect &)
ColumnType sqlToOdbType(const SQLType &t)
Definition: Types.cc:26
Definition: ColumnInfo.h:23