1 /* Copyright (C) 2014 InfiniDB, Inc.
2
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public License
5 as published by the Free Software Foundation; version 2 of
6 the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16 MA 02110-1301, USA. */
17
18 /****************************************************************************
19 * $Id: func_inet_aton.cpp 3923 2013-06-19 21:43:06Z bwilkinson $
20 *
21 *
22 ****************************************************************************/
23
24 #include "functor_real.h"
25
26 #include "calpontsystemcatalog.h"
27 #include "functioncolumn.h"
28 #include "joblisttypes.h"
29 #include "rowgroup.h"
30 //#include <iostream> // included when debugging
31
32 namespace funcexp
33 {
34
35 //------------------------------------------------------------------------------
36 // Return input argument type.
37 // See mcs_add in udfsdk.h for explanation of this function.
38 //------------------------------------------------------------------------------
operationType(FunctionParm & fp,execplan::CalpontSystemCatalog::ColType & resultType)39 execplan::CalpontSystemCatalog::ColType Func_inet_aton::operationType(
40 FunctionParm& fp,
41 execplan::CalpontSystemCatalog::ColType& resultType)
42 {
43 return fp[0]->data()->resultType(); // input type
44 }
45
46 //------------------------------------------------------------------------------
47 // Return IP address as a long long int value.
48 // SELECT ... WHERE inet_aton(ipstring) = 11111111 will call getIntVal()
49 //------------------------------------------------------------------------------
getIntVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)50 int64_t Func_inet_aton::getIntVal(rowgroup::Row& row,
51 FunctionParm& fp,
52 bool& isNull,
53 execplan::CalpontSystemCatalog::ColType& op_ct)
54 {
55 // std::cout << "In Func_inet_aton::getIntVal" << std::endl;
56
57 int64_t iValue = joblist::NULL_INT64;
58
59 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
60
61 if (!isNull)
62 {
63 int64_t iVal = convertAton( sValue, isNull );
64
65 if (!isNull)
66 iValue = iVal;
67 }
68
69 return iValue;
70 }
71
72 //------------------------------------------------------------------------------
73 // Return IP address as a double value.
74 // SELECT ... WHERE inet_aton(ipstring) = '11111111' will call getDoubleVal()
75 //------------------------------------------------------------------------------
getDoubleVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)76 double Func_inet_aton::getDoubleVal(rowgroup::Row& row,
77 FunctionParm& fp,
78 bool& isNull,
79 execplan::CalpontSystemCatalog::ColType& op_ct)
80 {
81 // std::cout << "In Func_inet_aton::getDoubleVal" << std::endl;
82
83 double dValue = doubleNullVal();
84
85 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
86
87 if (!isNull)
88 {
89 int64_t iValue = convertAton( sValue, isNull );
90
91 if (!isNull)
92 dValue = iValue;
93 }
94
95 return dValue;
96 }
97
98 //------------------------------------------------------------------------------
99 // Return IP address as a string value.
100 // We are starting with a string value, and we want to return a string value,
101 // so we might be tempted to just return the result from getStrVal(), as-is.
102 // But we still call convertAton() to validate that the IP address we have is
103 // a syntactically valid one.
104 // Don't know if this function will ever be called.
105 //------------------------------------------------------------------------------
getStrVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)106 std::string Func_inet_aton::getStrVal(rowgroup::Row& row,
107 FunctionParm& fp,
108 bool& isNull,
109 execplan::CalpontSystemCatalog::ColType& op_ct)
110 {
111 // std::cout << "In Func_inet_aton::getStrVal" << std::endl;
112
113 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
114
115 if (!isNull)
116 {
117 convertAton( sValue, isNull ); // ignore return value
118 }
119
120 return sValue;
121 }
122
123 //------------------------------------------------------------------------------
124 // Return IP address as a boolean?
125 // getBoolVal() makes no sense for inet_aton() but we will implement anyway.
126 // Don't know if this function will ever be called.
127 //------------------------------------------------------------------------------
getBoolVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)128 bool Func_inet_aton::getBoolVal(rowgroup::Row& row,
129 FunctionParm& fp,
130 bool& isNull,
131 execplan::CalpontSystemCatalog::ColType& op_ct)
132 {
133 bool bValue = false;
134
135 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
136
137 if (!isNull)
138 {
139 int64_t iVal = convertAton( sValue, isNull );
140
141 if ((!isNull) && (iVal != 0))
142 bValue = true;
143 }
144
145 return bValue;
146 }
147
148 //------------------------------------------------------------------------------
149 // Return IP address as a decimal value.
150 // SELECT ... WHERE inet_aton(ipstring) = 11111111. will call getDecimalVal()
151 //------------------------------------------------------------------------------
getDecimalVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)152 execplan::IDB_Decimal Func_inet_aton::getDecimalVal(rowgroup::Row& row,
153 FunctionParm& fp,
154 bool& isNull,
155 execplan::CalpontSystemCatalog::ColType& op_ct)
156 {
157 // std::cout << "In Func_inet_aton::getDecimalVal" << std::endl;
158
159 execplan::IDB_Decimal dValue ( joblist::NULL_INT64, 0, 0 );
160
161 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
162
163 if (!isNull)
164 {
165 int64_t iValue = convertAton( sValue, isNull );
166
167 if (!isNull)
168 return execplan::IDB_Decimal( iValue, 0, 0 );
169 }
170
171 return dValue;
172 }
173
174 //------------------------------------------------------------------------------
175 // Return IP address as a date?
176 // getDateIntVal() makes no sense for inet_aton() but we will implement anyway.
177 // Don't know if this function will ever be called.
178 //------------------------------------------------------------------------------
getDateIntVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)179 int32_t Func_inet_aton::getDateIntVal(rowgroup::Row& row,
180 FunctionParm& fp,
181 bool& isNull,
182 execplan::CalpontSystemCatalog::ColType& op_ct)
183 {
184 int32_t iValue = joblist::DATENULL;
185
186 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
187
188 if (!isNull)
189 {
190 int64_t iVal = convertAton( sValue, isNull );
191
192 if (!isNull)
193 iValue = iVal;
194 }
195
196 return iValue;
197 }
198
199 //------------------------------------------------------------------------------
200 // Return IP address as a date/time?
201 // getDatetimeIntVal() makes no sense for inet_aton() but we will implement
202 // anyway.
203 // Don't know if this function will ever be called.
204 //------------------------------------------------------------------------------
getDatetimeIntVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)205 int64_t Func_inet_aton::getDatetimeIntVal(rowgroup::Row& row,
206 FunctionParm& fp,
207 bool& isNull,
208 execplan::CalpontSystemCatalog::ColType& op_ct)
209 {
210 int64_t iValue = joblist::DATETIMENULL;
211
212 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
213
214 if (!isNull)
215 {
216 int64_t iVal = convertAton( sValue, isNull );
217
218 if (!isNull)
219 iValue = iVal;
220 }
221
222 return iValue;
223 }
224
getTimestampIntVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)225 int64_t Func_inet_aton::getTimestampIntVal(rowgroup::Row& row,
226 FunctionParm& fp,
227 bool& isNull,
228 execplan::CalpontSystemCatalog::ColType& op_ct)
229 {
230 int64_t iValue = joblist::TIMESTAMPNULL;
231
232 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
233
234 if (!isNull)
235 {
236 int64_t iVal = convertAton( sValue, isNull );
237
238 if (!isNull)
239 iValue = iVal;
240 }
241
242 return iValue;
243 }
244
getTimeIntVal(rowgroup::Row & row,FunctionParm & fp,bool & isNull,execplan::CalpontSystemCatalog::ColType & op_ct)245 int64_t Func_inet_aton::getTimeIntVal(rowgroup::Row& row,
246 FunctionParm& fp,
247 bool& isNull,
248 execplan::CalpontSystemCatalog::ColType& op_ct)
249 {
250 int64_t iValue = joblist::TIMENULL;
251
252 const std::string& sValue = fp[0]->data()->getStrVal(row, isNull);
253
254 if (!isNull)
255 {
256 int64_t iVal = convertAton( sValue, isNull );
257
258 if (!isNull)
259 iValue = iVal;
260 }
261
262 return iValue;
263 }
264
265 //------------------------------------------------------------------------------
266 // Convert an ascii IP address string to it's integer equivalent.
267 // isNull is set to true if the IP address string has invalid content.
268 // Source code based on MySQL source (Item_func_inet_aton() in item_func.cc).
269 //------------------------------------------------------------------------------
convertAton(const std::string & ipString,bool & isNull)270 int64_t Func_inet_aton::convertAton(
271 const std::string& ipString,
272 bool& isNull )
273 {
274 char c = '.';
275 int dot_count = 0;
276 unsigned int byte_result = 0;
277 unsigned long long result = 0;
278
279 const char* p = ipString.c_str();
280 const char* end = p + ipString.length();
281
282 // Loop through bytes in the IP address string
283 while (p < end)
284 {
285 c = *p++;
286
287 int digit = (int) (c - '0'); // Assume ascii
288
289 if (digit >= 0 && digit <= 9)
290 {
291 // Add the next digit from the string to byte_result
292 if ((byte_result = byte_result * 10 + digit) > 255)
293 {
294 // Wrong address
295 isNull = true;
296 return 0;
297 }
298 }
299 // Detect end of one portion of the IP address.
300 // Shift current result over 8 bits, and add next byte (byte_result)
301 else if (c == '.')
302 {
303 dot_count++;
304 result = (result << 8) + (unsigned long long) byte_result;
305 byte_result = 0;
306 }
307 // Exit loop if/when we encounter end of string for fixed length column,
308 // that is padded with '\0' at the end.
309 else if (c == '\0')
310 {
311 break;
312 }
313 else
314 {
315 // Invalid character
316 isNull = true;
317 return 0;
318 }
319 }
320
321 if (c != '.') // IP number can't end on '.'
322 {
323 //
324 // Handle short-forms addresses according to standard. Examples:
325 // 127 -> 0.0.0.127
326 // 127.1 -> 127.0.0.1
327 // 127.2.1 -> 127.2.0.1
328 //
329 switch (dot_count)
330 {
331 case 1:
332 result <<= 8; /* Fall through */
333
334 case 2:
335 result <<= 8; /* Fall through */
336 }
337
338 // std::cout << "aton: " <<
339 // (result << 8) + (unsigned long long) byte_result << std::endl;
340
341 return (result << 8) + (unsigned long long) byte_result;
342 }
343
344 // Invalid IP address ended in '.'
345 isNull = true;
346 return 0;
347 }
348
349 }
350