You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +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
 |