MCPcopy Create free account
hub / github.com/apache/impala / GetJsonObjectImpl

Method GetJsonObjectImpl

be/src/exprs/string-functions.cc:307–408  ·  view source on GitHub ↗

TODO(IMPALA-7610): parse the JSON path and cache it so we don't need to parse it everytime

Source from the content-addressed store, hash-verified

305/// TODO(IMPALA-7610): parse the JSON path and cache it so we don't need to parse it
306/// everytime
307StringVal StringFunctions::GetJsonObjectImpl(FunctionContext* ctx,
308 const StringVal& json_str, const StringVal& path_str) {
309 if (UNLIKELY(json_str.is_null || json_str.len == 0)) return StringVal::null();
310 if (UNLIKELY(path_str.is_null || path_str.len == 0)) {
311 ctx->SetError("Empty json path");
312 return StringVal::null();
313 }
314 int beg = 0;
315 // Strip off preceding whitespace.
316 while (beg < path_str.len && path_str.ptr[beg] == ' ') beg++;
317 if (UNLIKELY(beg == path_str.len || path_str.ptr[beg] != '$')) {
318 // Here we use '$$' to escape '$' in Substitute
319 string msg = Substitute("Failed to parse json path '$0': Should start with '$$'",
320 AnyValUtil::ToString(path_str));
321 ctx->SetError(msg.c_str());
322 return StringVal::null();
323 }
324
325 JsonUdfAllocator allocator(ctx);
326 JsonUdfDocument document(&allocator);
327 if (!ParseStringVal(ctx, json_str, &document)) return StringVal::null();
328
329 // BFS to extract selected values. We use array of RapidJson instead of std::vector to
330 // track its memory.
331 JsonUdfValue queue(kArrayType);
332 RETURN_NULL_IF_OOM(queue.Reserve(INITIAL_QUEUE_CAPACITY, allocator));
333 RETURN_NULL_IF_OOM(queue.PushBack(document, allocator));
334 const uint8_t* path = path_str.ptr;
335 const uint8_t* path_end = path + path_str.len;
336 for (int i = beg + 1; i < path_str.len;) {
337 // Each round we extract new items into the queue. Old items will be removed.
338 switch (path[i]) {
339 case '$': {
340 string msg = Substitute("Failed to parse json path '$0':"
341 " $$ should only be placed at start", AnyValUtil::ToString(path_str));
342 ctx->SetError(msg.c_str());
343 return StringVal::null();
344 }
345 case '.': {
346 // Hive does not skip the heading and trailing whitespaces since it simply splits
347 // the json path by '.'. We should keep the same behavior with MySQL. See
348 // JSON_EXTRACT in MySQL(5.7+).
349 for (++i; i < path_str.len && path[i] == ' '; ++i); // skip whitespaces
350 if (i == path_str.len) {
351 string msg = Substitute("Failed to parse json path '$0': Found a trailing '.'",
352 AnyValUtil::ToString(path_str));
353 ctx->SetError(msg.c_str());
354 return StringVal::null();
355 }
356 if (path[i] == '*') {
357 i = ProcessWildcardKey(ctx, path_str, ++i, &queue, &allocator);
358 if (i < 0) return StringVal::null();
359 break;
360 }
361 const uint8_t* start = path + i;
362 const uint8_t* end = FindEndOfIdentifier(start, path_end);
363 // Set error if looking for an empty key
364 if (end == nullptr) {

Callers

nothing calls this directly

Calls 12

SubstituteFunction · 0.85
ParseStringValFunction · 0.85
ProcessWildcardKeyFunction · 0.85
FindEndOfIdentifierFunction · 0.85
SelectByKeyFunction · 0.85
ProcessWildcardIndexFunction · 0.85
ProcessNumberIndexFunction · 0.85
PushBackMethod · 0.80
ToStringValFunction · 0.70
ToStringFunction · 0.50
SetErrorMethod · 0.45
ReserveMethod · 0.45

Tested by

no test coverage detected