bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
BindNameFunction.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) 2013 OPeNDAP, Inc.
7// Authors: 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 <cassert>
30
31#include <sstream>
32#include <vector>
33
34#include <libdap/BaseType.h>
35#include <libdap/Str.h>
36
37#include <libdap/Error.h>
38#include <libdap/DDS.h>
39#include <libdap/DMR.h>
40#include <libdap/D4Group.h>
41#include <libdap/D4RValue.h>
42
43#include <libdap/debug.h>
44#include <libdap/util.h>
45
46#include <BESDebug.h>
47
48#include "BindNameFunction.h"
49
50using namespace libdap;
51
52namespace functions {
53
54string bind_name_info =
55 string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
56 + "<function name=\"make_array\" version=\"1.0\" href=\"http://docs.opendap.org/index.php/Server_Side_Processing_Functions#bind_name\">\n"
57 + "</function>";
58
72void function_bind_name_dap2(int argc, BaseType * argv[], DDS &dds, BaseType **btpp)
73{
74 DBG(cerr << "function_bind_name_dap2() - BEGIN" << endl);
75
76 if (argc == 0) {
77 Str *response = new Str("info");
78 response->set_value(bind_name_info);
79 *btpp = response;
80 return;
81 }
82
83 // Check for two args or more. The first two must be strings.
84 if (argc != 2) throw Error(malformed_expr, "bind_name(name,variable) requires two arguments.");
85
86 DBG(cerr << "function_bind_name_dap2() - Processing argv[0]" << endl);
87
88 string name = extract_string_argument(argv[0]);
89 DBG(cerr << "function_bind_name_dap2() - New name: " << name << endl);
90
91 DBG(cerr << "function_bind_name_dap2() - Processing argv[1]" << endl);
92 BaseType *sourceVar = argv[1];
93 DBG(cerr << "function_bind_name_dap2() - Source variable: " <<
94 sourceVar->type_name() << " " << sourceVar->name() << endl);
95
96 // Don't allow renaming that will introduce namespace collisions.
97 //
98 // Check the DDS to see if a variable with name given as argv[0] already exists. If
99 // so, return an error. This is complicated somewhat because the CE Evaluator will
100 // have already looked and, if the string passed into the function matches a variable,
101 // replaced that string with a BaseType* to the (already existing) variable. If not,
102 // the CE Evaluator will make a DAP String variable with a value that is the string
103 // passed into the function. So, either way argv[0] is a BaseType*. However, if it's
104 // a variable in the dataset, its name() will be found by DDS::var().
105 if (dds.var(/*argv[0]->name()*/name)) throw Error(malformed_expr, "The name '" + name + "' is already in use.");
106
107 // If the variable is the return value of a function, just pass it back. If it is
108 // a variable in the dataset (i.e., present in the DDS), copy it because DDS deletes
109 // all its variables and the function processing code also deletes all it's variables.
110 // NB: Could use reference counting pointers to eliminate this copy... jhrg 6/24/13
111 if (dds.var(sourceVar->name())) {
112 DBG(cerr << "function_bind_name_dap2() - Copying existing variable in DDS: " << sourceVar->name() << endl);
113 *btpp = sourceVar->ptr_duplicate();
114 if (!(*btpp)->read_p()) {
115 (*btpp)->read();
116 (*btpp)->set_read_p(true);
117 }
118 (*btpp)->set_send_p(true);
119 (*btpp)->set_name(name);
120 }
121 else {
122 DBG(cerr << "function_bind_name_dap2 - Using passed variable: " << sourceVar->name() << endl);
123 sourceVar->set_name(name);
124 *btpp = sourceVar;
125 } DBG(cerr << "function_bind_name_dap2() - END" << endl);
126
127 return;
128}
129
130BaseType *function_bind_name_dap4(D4RValueList *args, DMR &dmr)
131{
132 // DAP4 function porting information: in place of 'argc' use 'args.size()'
133 if (args == 0 || args->size() == 0) {
134 Str *response = new Str("info");
135 response->set_value(bind_name_info);
136 // DAP4 function porting: return a BaseType* instead of using the value-result parameter
137 return response;
138 }
139
140 // Check for 2 arguments
141 DBG(cerr << "args->size() = " << args->size() << endl);
142 if (args->size() != 2) throw Error(malformed_expr, "bind_shape(shape,variable) requires two arguments.");
143
144 string name = extract_string_argument(args->get_rvalue(0)->value(dmr));
145
146 DBG(cerr << "function_bind_name_dap4() - New name: " << name << endl);
147
148 BaseType *sourceVar = args->get_rvalue(1)->value(dmr);
149 DBG(cerr << "function_bind_name_dap4() - Source variable: " << sourceVar->type_name() << " " << sourceVar->name() << endl);
150
151 BaseType *resultVar;
152
153 // Don't allow renaming that will introduce namespace collisions.
154 //
155 // Check the DMR to see if a variable with name given as args[0] already exists. If
156 // so, return an error. This is complicated somewhat because the CE Evaluator will
157 // have already looked and, if the string passed into the function matches a variable,
158 // replaced that string with a BaseType* to the (already existing) variable. If not,
159 // the CE Evaluator will make a DAP String variable with a value that is the string
160 // passed into the function. So, either way args[0] is a BaseType*. However, if it's
161 // a variable in the dataset, its name() will be found by DMR::root()->var().
162 if (dmr.root()->var(/*arg0->name()*/name))
163 throw Error(malformed_expr, "The name '" + /*arg0->name()*/name + "' is already in use.");
164
165 // If the variable is the return value of a function, just pass it back. If it is
166 // a variable in the dataset (i.e., present in the DDS), copy it because DDS deletes
167 // all its variables and the function processing code also deletes all it's variables.
168 // NB: Could use reference counting pointers to eliminate this copy... jhrg 6/24/13
169 if (dmr.root()->var(sourceVar->name())) {
170 DBG(cerr << "function_bind_name_dap4() - Copying existing variable in DMR: " << sourceVar->name() << endl);
171 resultVar = sourceVar->ptr_duplicate();
172 if (!resultVar->read_p()) {
173 resultVar->read();
174 resultVar->set_read_p(true);
175 }
176 resultVar->set_send_p(true);
177 resultVar->set_name(name);
178 }
179 else {
180 DBG(cerr << "function_bind_name_dap4 - Using passed variable: " << sourceVar->name() << endl);
181 resultVar = sourceVar;
182 resultVar->set_name(name);
183
184 }
185 return resultVar;
186
187}
188
189} // namesspace functions