You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-10-31 18:30:33 +03:00 
			
		
		
		
	This patch is the columnstore-part of the task. Columnstore wanted to have previous 32 depth, so this patch aims at keeping the compatibility.
		
			
				
	
	
		
			244 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <type_traits>
 | |
| #include "functor_json.h"
 | |
| #include "functioncolumn.h"
 | |
| #include "rowgroup.h"
 | |
| #include "treenode.h"
 | |
| using namespace execplan;
 | |
| using namespace rowgroup;
 | |
| 
 | |
| #include "dataconvert.h"
 | |
| 
 | |
| #include "jsonhelpers.h"
 | |
| using namespace funcexp::helpers;
 | |
| 
 | |
| namespace funcexp
 | |
| {
 | |
| int Func_json_extract::doExtract(Row& row, FunctionParm& fp, json_value_types* type, std::string& retJS,
 | |
|                                  bool compareWhole = true)
 | |
| {
 | |
|   bool isNull = false;
 | |
|   const auto js = fp[0]->data()->getStrVal(row, isNull);
 | |
|   if (isNull)
 | |
|     return 1;
 | |
|   const char* rawJS = js.str();
 | |
|   const uchar* value;
 | |
|   bool notFirstVal = false;
 | |
|   size_t valLen;
 | |
|   bool mayMulVal;
 | |
|   int wildcards;
 | |
|   bool isMatch;
 | |
| #if MYSQL_VERSION_ID >= 100900
 | |
|   int arrayCounter[JSON_DEPTH_LIMIT];
 | |
|   bool hasNegPath = false;
 | |
| #endif
 | |
|   const size_t argSize = fp.size();
 | |
|   std::string tmp;
 | |
| 
 | |
|   for (size_t i = 1; i < argSize; i++)
 | |
|   {
 | |
|     JSONPath& path = paths[i - 1];
 | |
|     path.p.types_used = JSON_PATH_KEY_NULL;
 | |
|     if (!path.parsed && parseJSPath(path, row, fp[i]))
 | |
|       return 1;
 | |
| 
 | |
| #if MYSQL_VERSION_ID >= 100900
 | |
|     hasNegPath |= path.p.types_used & JSON_PATH_NEGATIVE_INDEX;
 | |
| #endif
 | |
|   }
 | |
| 
 | |
| #if MYSQL_VERSION_ID >= 100900
 | |
|   wildcards = (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD | JSON_PATH_ARRAY_RANGE);
 | |
| #else
 | |
|   wildcards = (JSON_PATH_WILD | JSON_PATH_DOUBLE_WILD);
 | |
| #endif
 | |
|   mayMulVal = argSize > 2 || (paths[0].p.types_used & wildcards);
 | |
| 
 | |
|   *type = mayMulVal ? JSON_VALUE_ARRAY : JSON_VALUE_NULL;
 | |
| 
 | |
|   if (compareWhole)
 | |
|   {
 | |
|     retJS.clear();
 | |
|     if (mayMulVal)
 | |
|       retJS.append("[");
 | |
|   }
 | |
| 
 | |
|   json_get_path_start(&jsEg, getCharset(fp[0]), (const uchar*)rawJS, (const uchar*)rawJS + js.length(), &p);
 | |
| 
 | |
|   while (json_get_path_next(&jsEg, &p) == 0)
 | |
|   {
 | |
| #if MYSQL_VERSION_ID >= 100900
 | |
| #if MYSQL_VERSION_ID >= 120200
 | |
|     json_path_step_t *last_step= reinterpret_cast<json_path_step_t*>(mem_root_dynamic_array_get_val(&p.steps, p.last_step_idx));
 | |
|     if (hasNegPath && jsEg.value_type == JSON_VALUE_ARRAY &&
 | |
|         json_skip_array_and_count(&jsEg, arrayCounter + (last_step - reinterpret_cast<json_path_step_t*>(p.steps.buffer))))
 | |
| #else
 | |
|    if (hasNegPath && jsEg.value_type == JSON_VALUE_ARRAY &&
 | |
|         json_skip_array_and_count(&jsEg, arrayCounter + (p.last_step - p.steps)))
 | |
| #endif
 | |
|       return 1;
 | |
| #endif
 | |
| 
 | |
| #if MYSQL_VERSION_ID >= 100900
 | |
|     isMatch = matchJSPath(paths, &p, jsEg.value_type, arrayCounter, false);
 | |
| #else
 | |
|     isMatch = matchJSPath(paths, &p, jsEg.value_type, nullptr, false);
 | |
| #endif
 | |
|     if (!isMatch)
 | |
|       continue;
 | |
| 
 | |
|     value = jsEg.value_begin;
 | |
|     if (*type == JSON_VALUE_NULL)
 | |
|       *type = jsEg.value_type;
 | |
| 
 | |
|     /* we only care about the first found value */
 | |
|     if (!compareWhole)
 | |
|     {
 | |
|       retJS = js.safeString("");
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|     if (json_value_scalar(&jsEg))
 | |
|       valLen = jsEg.value_end - value;
 | |
|     else
 | |
|     {
 | |
|       if (mayMulVal)
 | |
|         savJSEg = jsEg;
 | |
|       if (json_skip_level(&jsEg))
 | |
|         return 1;
 | |
|       valLen = jsEg.s.c_str - value;
 | |
|       if (mayMulVal)
 | |
|         jsEg = savJSEg;
 | |
|     }
 | |
| 
 | |
|     if (notFirstVal)
 | |
|       retJS.append(", ");
 | |
|     retJS.append((const char*)value, valLen);
 | |
| 
 | |
|     notFirstVal = true;
 | |
| 
 | |
|     if (!mayMulVal)
 | |
|     {
 | |
|       /* Loop to the end of the JSON just to make sure it's valid. */
 | |
|       while (json_get_path_next(&jsEg, &p) == 0)
 | |
|       {
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (unlikely(jsEg.s.error))
 | |
|     return 1;
 | |
| 
 | |
|   if (!notFirstVal)
 | |
|     /* Nothing was found. */
 | |
|     return 1;
 | |
| 
 | |
|   if (mayMulVal)
 | |
|     retJS.append("]");
 | |
| 
 | |
|   utils::NullString retJS_ns(retJS);
 | |
|   initJSEngine(jsEg, getCharset(fp[0]), retJS_ns);
 | |
|   if (doFormat(&jsEg, tmp, Func_json_format::LOOSE))
 | |
|     return 1;
 | |
| 
 | |
|   retJS.clear();
 | |
|   retJS.swap(tmp);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| CalpontSystemCatalog::ColType Func_json_extract::operationType(FunctionParm& fp,
 | |
|                                                                CalpontSystemCatalog::ColType& /*resultType*/)
 | |
| {
 | |
|   return fp[0]->data()->resultType();
 | |
| }
 | |
| 
 | |
| std::string Func_json_extract::getStrVal(Row& row, FunctionParm& fp, bool& isNull,
 | |
|                                          CalpontSystemCatalog::ColType& /*type*/)
 | |
| {
 | |
|   std::string retJS;
 | |
|   json_value_types valType;
 | |
|   if (doExtract(row, fp, &valType, retJS) == 0)
 | |
|     return retJS;
 | |
| 
 | |
|   isNull = true;
 | |
|   return "";
 | |
| }
 | |
| 
 | |
| int64_t Func_json_extract::getIntVal(rowgroup::Row& row, FunctionParm& fp, bool& /*isNull*/,
 | |
|                                      execplan::CalpontSystemCatalog::ColType& /*type*/)
 | |
| {
 | |
|   std::string retJS;
 | |
|   json_value_types valType;
 | |
|   int64_t ret = 0;
 | |
|   if (doExtract(row, fp, &valType, retJS, false) == 0)
 | |
|   {
 | |
|     switch (valType)
 | |
|     {
 | |
|       case JSON_VALUE_NUMBER:
 | |
|       case JSON_VALUE_STRING:
 | |
|       {
 | |
|         char* end;
 | |
|         int err;
 | |
|         ret = getCharset(fp[0])->strntoll(retJS.data(), retJS.size(), 10, &end, &err);
 | |
|         break;
 | |
|       }
 | |
|       case JSON_VALUE_TRUE: ret = 1; break;
 | |
|       default: break;
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| double Func_json_extract::getDoubleVal(rowgroup::Row& row, FunctionParm& fp, bool& /*isNull*/,
 | |
|                                        execplan::CalpontSystemCatalog::ColType& /*type*/)
 | |
| {
 | |
|   std::string retJS;
 | |
|   json_value_types valType;
 | |
|   double ret = 0.0;
 | |
|   if (doExtract(row, fp, &valType, retJS, false) == 0)
 | |
|   {
 | |
|     switch (valType)
 | |
|     {
 | |
|       case JSON_VALUE_NUMBER:
 | |
|       case JSON_VALUE_STRING:
 | |
|       {
 | |
|         char* end;
 | |
|         int err;
 | |
|         ret = getCharset(fp[0])->strntod(retJS.data(), retJS.size(), &end, &err);
 | |
|         break;
 | |
|       }
 | |
|       case JSON_VALUE_TRUE: ret = 1.0; break;
 | |
|       default: break;
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| execplan::IDB_Decimal Func_json_extract::getDecimalVal(rowgroup::Row& row, FunctionParm& fp, bool& isNull,
 | |
|                                                        execplan::CalpontSystemCatalog::ColType& /*type*/)
 | |
| {
 | |
|   json_value_types valType;
 | |
|   std::string retJS;
 | |
| 
 | |
|   if (doExtract(row, fp, &valType, retJS, false) == 0)
 | |
|   {
 | |
|     switch (valType)
 | |
|     {
 | |
|       case JSON_VALUE_STRING:
 | |
|       case JSON_VALUE_NUMBER: return fp[0]->data()->getDecimalVal(row, isNull);
 | |
|       case JSON_VALUE_TRUE: return IDB_Decimal(1, 0, 1);
 | |
|       case JSON_VALUE_OBJECT:
 | |
|       case JSON_VALUE_ARRAY:
 | |
|       case JSON_VALUE_FALSE:
 | |
|       case JSON_VALUE_NULL:
 | |
|       case JSON_VALUE_UNINITIALIZED: break;
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   return IDB_Decimal(0, 0, 1);
 | |
| }
 | |
| }  // namespace funcexp
 |