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