IODA Bundle
MDSetTool.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 "odc/tools/MDSetTool.h"
12 
13 #include "eckit/filesystem/PathName.h"
14 #include "eckit/log/Log.h"
15 #include "eckit/utils/StringTools.h"
16 #include "eckit/utils/Tokenizer.h"
17 #include "eckit/sql/SQLTypedefs.h"
18 
19 #include "odc/core/Header.h"
20 #include "odc/core/MetaData.h"
21 #include "odc/core/TablesReader.h"
22 #include "odc/ODBAPISettings.h"
23 
24 using namespace eckit;
25 using namespace std;
26 typedef eckit::StringTools S;
27 using namespace odc::core;
28 
29 namespace odc {
30 namespace tool {
31 
32 void MDSetTool::help(std::ostream &o) {
33  o << "Creates a new file resetting types or values (constants only) of columns.";
34 }
35 
36 
37 void MDSetTool::usage(const std::string& name, std::ostream &o) {
38  o << name << " <update-list> <input.odb> <output.odb>" << endl << endl
39 
40  << "\t<update-list> is a comma separated list of expressions of the form:" << endl
41  << "\t <column-name> : <type> = <value>" << endl << endl
42  << "\t<type> can be one of: integer, real, double, string. If ommited, the existing type of the column will not be changed." << endl
43  << "\tBoth type and value are optional; at least one of the two should be present. For example:" << endl
44  << "\t odb mdset \"expver=' 0008'\" input.odb patched.odb " << endl;
45 }
46 
47 MDSetTool::MDSetTool (int argc, char *parameters[]) : Tool(argc, parameters) { }
48 
50 {
51  if (parameters().size() != 4)
52  {
53  Log::error() << "Usage: ";
55  Log::error() << std::endl;
56  return;
57  }
58 
59  PathName inFile = parameters(2), outFile = parameters(3);
60  std::unique_ptr<DataHandle> outHandle(ODBAPISettings::instance().writeToFile(outFile));
61 
62  std::vector<std::string> columns, types, values;
63  std::vector<eckit::sql::BitfieldDef> bitfieldDefs;
64  parseUpdateList(parameters(1), columns, types, values, bitfieldDefs);
65 
66  odc::core::TablesReader reader(inFile);
67 
68  for (auto it = reader.begin(), end = reader.end(); it != end; ++it) {
69 
70  const MetaData& md (it->columns());
71  for (size_t i = 0; i < columns.size(); ++i)
72  {
73  Column& c (*md[md.columnIndex(columns[i])]);
74  Log::info() << "" << columns[i] << ": " << c << endl;
75 
76  if (types[i].size() && types[i] != "NONE") c.type(Column::type(types[i]));
77  if (bitfieldDefs[i].first.size()) c.bitfieldDef(bitfieldDefs[i]);
78  if (values[i].size() && values[i] != "NONE")
79  {
80  Codec& codec (c.coder());
81  if (codec.name().find("constant") == std::string::npos)
82  {
83  stringstream ss;
84  ss << "Column '" << columns[i] << "' is not constant (codec: " << codec.name() << ")" << endl;
85  throw UserError(ss.str());
86  }
87  double v (StringTool::translate(values[i]));
88  c.min(v);
89  c.max(v);
90  }
91  }
92 
93  size_t sizeOfEncodedData = it->encodedDataSize();
94  eckit::Buffer encodedData(it->readEncodedData());
95  ASSERT(encodedData.size() == sizeOfEncodedData);
96 
97  // See if the file was created on a different order architecture
98  if (it->byteOrder() == BYTE_ORDER_INDICATOR)
99  {
100  Log::info() << "MDSetTool::run: SAME ORDER " << sizeOfEncodedData << std::endl;
101 
102  auto encodedHeader = core::Header::serializeHeader(sizeOfEncodedData,
103  md.rowsNumber(),
104  it->properties(),
105  md);
106  outHandle->write(encodedHeader.first, encodedHeader.second);
107  }
108  else
109  {
110  Log::info() << "MDSetTool::run: OTHER ORDER " << sizeOfEncodedData << std::endl;
111 
112  auto encodedHeader = core::Header::serializeHeaderOtherByteOrder(
113  sizeOfEncodedData,
114  md.rowsNumber(),
115  it->properties(),
116  md);
117  outHandle->write(encodedHeader.first, encodedHeader.second);
118  }
119  outHandle->write(encodedData.data(), sizeOfEncodedData);
120  }
121 }
122 
123 //
124 //static std::vector<std::string> split(const std::string& delim, const std::string& text);
125 
126 void MDSetTool::parseUpdateList(const std::string& s,
127  std::vector<std::string>& columns,
128  std::vector<std::string>& types,
129  std::vector<std::string>& values,
130  std::vector<eckit::sql::BitfieldDef>& bitfieldDefs)
131 {
132  std::vector<std::string> assignments(S::split(",", s));
133  for (size_t i = 0; i < assignments.size(); ++i)
134  {
135  vector<string> assignment(S::split("=", assignments[i]));
136  string value (assignment.size() == 2 ? assignment[1] : "NONE");
137  vector<string> columnNameAndType(S::split(":", assignment[0]));
138  string type (columnNameAndType.size() == 2 ? columnNameAndType[1] : "NONE");
139  string column (assignment[0]);
140 
141  eckit::sql::BitfieldDef bf;
142  if (type.size() && type[0] == '[' && type[type.size() - 1] == ']')
143  {
144  std::vector<std::string> parts(StringTools::split(";", type.substr(1, type.size() - 2)));
145  for (size_t p = 0; p < parts.size(); ++p)
146  {
147  std::vector<std::string> field (S::split(":", parts[p]));
148  bf.first.push_back(field[0]);
149  bf.second.push_back(atoi(field[1].c_str()));
150  }
151  }
152 
153  Log::info() << "MDSetTool::parseUpdateList: " << column << " : " << type << " = '" << value << "'" << std::endl;
154 
155  columns.push_back(column);
156  types.push_back(type);
157  values.push_back(value);
158  bitfieldDefs.push_back(bf);
159  }
160  ASSERT(columns.size() == types.size());
161  ASSERT(columns.size() == values.size());
162  ASSERT(columns.size() == bitfieldDefs.size());
163 }
164 
165 } // namespace tool
166 } // namespace odc
167 
eckit::StringTools S
Definition: MDSetTool.cc:26
static ODBAPISettings & instance()
static double translate(const std::string &v)
Definition: StringTool.cc:133
const std::string & name() const
Definition: Codec.h:40
static std::pair< eckit::Buffer, size_t > serializeHeader(size_t dataSize, size_t rowsNumber, const Properties &properties, const MetaData &columns)
Definition: Header.cc:204
static std::pair< eckit::Buffer, size_t > serializeHeaderOtherByteOrder(size_t dataSize, size_t rowsNumber, const Properties &properties, const MetaData &columns)
Definition: Header.cc:208
size_t columnIndex(const std::string &) const
Definition: MetaData.cc:95
unsigned long long rowsNumber() const
Definition: MetaData.h:39
const std::vector< std::string > parameters()
void parseUpdateList(const std::string &s, std::vector< std::string > &columns, std::vector< std::string > &types, std::vector< std::string > &values, std::vector< eckit::sql::BitfieldDef > &bitfieldDefs)
Definition: MDSetTool.cc:126
static void usage(const std::string &name, std::ostream &o)
Definition: MDSetTool.cc:37
const int32_t BYTE_ORDER_INDICATOR
Definition: Header.h:40
Definition: ColumnInfo.h:23
Definition: encode.cc:30
subroutine usage()
Definition: odc_ls.f90:59