IODA Bundle
TODATable.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 <sstream>
12 
13 #include "eckit/io/FileHandle.h"
14 #include "eckit/utils/StringTools.h"
15 #include "eckit/sql/SQLTableFactory.h"
16 #include "eckit/sql/type/SQLBitfield.h"
17 #include "eckit/utils/Translator.h"
18 #include "eckit/sql/SQLColumn.h"
19 
20 #include "odc/csv/TextReader.h"
22 #include "odc/Reader.h"
23 #include "odc/sql/TODATable.h"
25 
26 using namespace eckit;
27 using namespace eckit::sql;
28 using namespace odc::api;
29 using namespace odc::core;
30 
31 namespace odc {
32 namespace sql {
33 
34 //----------------------------------------------------------------------------------------------------------------------
35 
36 namespace {
37 
38 // Provide a factory such that when a table is specified in a from statement, the SQLParser
39 // can construct an appropriate table!
40 
41 class ODAFactory : public eckit::sql::SQLTableFactoryBase {
42  virtual SQLTable* build(SQLDatabase& owner, const std::string& name, const std::string& location) const override {
43 
44  PathName path(location);
45  if (!path.exists()) return 0;
46 
47  // Check that this is an ODB file
48  FileHandle fh(path, false);
49  fh.openForRead();
50 
51  char buf[5];
52  char oda[5] {'\xff', '\xff', 'O', 'D', 'A'};
53  if (fh.read(buf, 5) != 5 || ::memcmp(buf, oda, 5) != 0) return 0;
54 
55  return new odc::sql::ODATable(owner, location, name);
56  }
57 };
58 
60 
61 }
62 
63 //---------------------------------------------------------------------------------------------------------------------
64 
65 
66 template <typename READER>
67 TODATable<READER>::TODATable(SQLDatabase& owner, const std::string& path, const std::string& name, READER&& oda) :
68  SQLTable(owner, path, name),
69  oda_(std::move(oda)) {
70 
71  populateMetaData();
72 }
73 
74 
75 template <typename READER>
77 
78 template <typename READER>
79 const READER& TODATable<READER>::oda() const {
80  return oda_;
81 }
82 
83 
84 template <typename READER>
86 {
87  auto it = oda_.begin();
88 
89  size_t count = it->columns().size();
90 
91  for(size_t i = 0; i < count; i++)
92  {
93  Column& column (*it->columns()[i]);
94 
95  const std::string name (column.name());
96  bool hasMissing (column.hasMissing());
97  double missing (column.missingValue());
98  BitfieldDef bitfieldDef (column.bitfieldDef());
99 
100  std::string sqlType;
101  size_t typeSizeDoubles = it->dataSizeDoubles(i);
102 
103  switch(column.type()) {
104  case INTEGER: sqlType = "integer"; break;
105  case STRING: sqlType = "string"; break;
106  case REAL: sqlType = "real"; break;
107  case DOUBLE: sqlType = "double"; break;
108  case BITFIELD: {
109  std::string typeSignature = type::SQLBitfield::make("Bitfield", bitfieldDef.first, bitfieldDef.second, "DummyTypeAlias");
110  addColumn(name, i, type::SQLType::lookup(typeSignature), hasMissing, missing, true, bitfieldDef);
111  continue;
112  }
113  default:
114  throw SeriousBug("Unknown type: " + Translator<int, std::string>()(column.type()), Here());
115  }
116 
117  addColumn(name, i, type::SQLType::lookup(sqlType, typeSizeDoubles), hasMissing, missing, column.type() == BITFIELD, bitfieldDef);
118  }
119 }
120 
121 //void TODATable<READER>::updateMetaData(const std::vector<SQLColumn*>& selected)
122 //{
123 // // TODO: Whoah! whoah! whoah!
124 // // n.b. we don't really want to modify the table. We should probabyl deal with this in the iterator...
125 // NOTIMP;
126 //
127 //// MetaData newColumns (it_->columns());
128 //// for(size_t i = 0; i < selected.size(); i++)
129 //// {
130 //// ODAColumn *c = dynamic_cast<ODAColumn *>(selected[i]);
131 //// ASSERT(c);
132 //// if (newColumns.size() <= c->index() || newColumns[c->index()]->name() != c->name())
133 //// {
134 //// Log::warning() << "Column '" << c->fullName() << "': index has changed in new dataset." << endl
135 //// << "Was: " << c->index() << "." << endl;
136 //// bool newIndexFound = false;
137 //// for (size_t j = 0; j < newColumns.size(); ++j)
138 //// {
139 //// Column &other(*newColumns[j]);
140 //// if (other.name() == c->name() || other.name() == c->fullName())
141 //// {
142 //// newIndexFound = true;
143 //// Log::warning() << "New index: " << j << endl;
144 //// c->index(j);
145 //// break;
146 //// }
147 //// }
148 //// if (! newIndexFound)
149 //// {
150 //// // TODO: if user specified MAYBE keyword, then use a constant NULL column.
151 //// //if (maybe_) {
152 //// // Log::warning() << "Column '" << c->name() << "' not found." << endl;
153 //// // selected[i] = new NullColumn(*selected[i]);
154 //// //} else {
155 //// stringstream ss;
156 //// ss << "One of selected columns, '" << c->name() << "', does not exist in new data set.";
157 //// throw UserError(ss.str());
158 //// //}
159 //// }
160 //// }
161 //// //c->value(&data_[i]);
162 //// }
163 //}
164 
165 
166 template <typename READER>
167 bool TODATable<READER>::hasColumn(const std::string& name) const {
168 
169  // If the column is simply in the table, then use it.
170 
171  if (SQLTable::hasColumn(name)) {
172  return true;
173  }
174 
175  // Find columns that also have an (unspecified) section name
176 
177  std::string colName (name + "@");
178  int n = 0;
179 
180  for (const auto& column : columnsByName_) {
181  const std::string& s (column.first);
182  if (StringTools::startsWith(s, colName)) {
183  n++;
184  }
185  }
186 
187  if (n == 1) return true;
188  if (n > 1) {
189  throw UserError(std::string("TODATable:hasColumn(\"") + name + "\"): ambiguous name");
190  }
191 
192  return false;
193 }
194 
195 template <typename READER>
196 const SQLColumn& TODATable<READER>::column(const std::string& name) const {
197 
198  // If the column is simply in the table, then use it.
199 
200  if (SQLTable::hasColumn(name)) {
201  return SQLTable::column(name);
202  }
203 
204  // Find columns that also have an (unspecified) section name
205 
206  const std::string colName (name + "@");
207  SQLColumn* column = 0;
208 
209  for (const auto& col : columnsByName_) {
210  const std::string& s (col.first);
211  if (StringTools::startsWith(s, colName)) {
212  if (column) throw UserError(std::string("TODATable:hasColumn(\"") + name + "\"): ambiguous name");
213  column = col.second;
214  }
215  }
216 
217  if (!column) throw SeriousBug("Requesting column \"" + name + "\": not found", Here());
218 
219  return *column;
220 }
221 
222 template <typename READER>
223 SQLTableIterator* TODATable<READER>::iterator(const std::vector<std::reference_wrapper<const eckit::sql::SQLColumn>>& columns,
224  std::function<void(eckit::sql::SQLTableIterator&)> metadataUpdateCallback) const {
225  return new TODATableIterator<READER>(*this, columns, metadataUpdateCallback);
226 }
227 
228 template <typename READER>
229 void TODATable<READER>::print(std::ostream& s) const {
230  s << "TODATable(" << path_ << ")";
231 }
232 
233 
234 // Explicit instantiation
235 
236 template class TODATable<Reader>;
237 template class TODATable<TextReader>;
238 
239 //----------------------------------------------------------------------------------------------------------------------
240 
241 } // namespace sql
242 } // namespace odc
void oda
static void count(void *counter, const double *data, size_t n)
Definition: UnitTests.cc:531
void bitfieldDef(const eckit::sql::BitfieldDef &b)
Definition: Column.h:85
void hasMissing(bool h)
Delegations to Codec:
Definition: Column.h:71
void missingValue(double v)
Definition: Column.h:80
void name(const std::string name)
Definition: Column.h:57
static api::ColumnType type(const std::string &)
Definition: Column.cc:74
virtual bool hasColumn(const std::string &) const override
Definition: TODATable.cc:167
void populateMetaData()
Definition: TODATable.cc:85
const READER & oda() const
Definition: TODATable.cc:79
virtual const eckit::sql::SQLColumn & column(const std::string &) const override
Definition: TODATable.cc:196
virtual ~TODATable()
Definition: TODATable.cc:76
virtual void print(std::ostream &s) const override
Definition: TODATable.cc:229
virtual eckit::sql::SQLTableIterator * iterator(const std::vector< std::reference_wrapper< const eckit::sql::SQLColumn >> &, std::function< void(eckit::sql::SQLTableIterator &)> metadataUpdateCallback) const override
Definition: TODATable.cc:223
virtual SQLTable * build(SQLDatabase &owner, const std::string &name, const std::string &location) const override
Definition: TODATable.cc:42
@ BITFIELD
Definition: ColumnType.h:27
Definition: ColumnInfo.h:23
Definition: encode.cc:30