/*
Copyright ( c ) 2025 , MariaDB
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1335
USA */
#ifndef SQL_JSON_LIB
#define SQL_JSON_LIB
#include "json_lib.h"
#include "sql_string.h"
#include "mysqld.h" /* system_charset_info */
/*
A syntax sugar interface to json_string_t
*/
class Json_string
{
json_string_t str;
public :
explicit Json_string(const char *name)
{
json_string_set_str(&str, (const uchar *) name,
(const uchar *) name + strlen(name));
json_string_set_cs(&str, system_charset_info);
}
json_string_t *get() { return &str; }
};
/*
This [ partially ] saves the JSON parser state and then can rollback the parser
to it .
The goal of this is to be able to make multiple json_key_matches ( ) calls :
Json_saved_parser_state save ( je ) ;
if ( json_key_matches ( je , KEY_NAME_1 ) ) {
. . .
return ;
}
save . restore_to ( je ) ;
if ( json_key_matches ( je , KEY_NAME_2 ) ) {
. . .
}
This allows one to parse JSON objects where [ optional ] members come in any
order .
*/
class Json_saved_parser_state
{
const uchar *c_str;
my_wc_t c_next;
int state;
public :
explicit Json_saved_parser_state(const json_engine_t *je)
: c_str(je->s.c_str), c_next(je->s.c_next), state(je->state)
{
}
void restore_to(json_engine_t *je)
{
je->s.c_str= c_str;
je->s.c_next= c_next;
je->state= state;
}
};
/*
@ brief
Un - escape a JSON string and save it into * out .
*/
bool json_unescape_to_string(const char *val, int val_len, String *out);
/*
@ brief
Escape and quote a JSON string and save it into * out .
*/
int json_escape_to_string(const String *str, String *out);
namespace json_reader
{
class Read_value;
};
/*
Description of a JSON object member that is to be read by json_read_object ( ) .
Intended usage :
char * var1 ;
int var2 ;
Read_named_member memb [ ] = {
{ " member1 " , Read_string ( thd - > mem_root , & var1 ) , false } ,
{ " member2 " , Read_double ( & var2 ) , false } ,
{ NULL , Read_double ( NULL ) , true }
} ;
json_read_object ( je , memb , err ) ;
*/
class Read_named_member
{
public :
const char *name; /* JSON object name */
/*
Reader object holding the datatype and place for the value .
It ' s an lvalue reference so we can have both inherited classes
and refer to unnamed objects on the stack .
*/
json_reader::Read_value &&value;
const bool is_optional; /* Can this member be omitted in JSON? */
bool value_assigned= false ; /* Filled and checked by json_read_object() */
};
/* Read an object from JSON according to description in *members */
int json_read_object(json_engine_t *je, Read_named_member *members,
String *err_buf);
namespace json_reader
{ /* Things to use with Read_named_member */
bool read_string(MEM_ROOT *mem_root, json_engine_t *je, const char *read_elem_key,
String *err_buf, char *&value);
bool read_double(json_engine_t *je, const char *read_elem_key, String *err_buf,
double &value);
bool read_ha_rows_and_check_limit(json_engine_t *je, const char *read_elem_key,
String *err_buf, ha_rows &value,
ha_rows LIMIT_VAL,
const char *limit_val_type,
bool unescape_required);
/*
Interface to read a value with value_name from Json ,
while in the process of parsing the Json document
*/
class Read_value
{
public :
virtual bool read_value(json_engine_t *je, const char *value_name,
String *err_buf)= 0 ;
virtual ~Read_value() {};
};
class Read_string : public Read_value
{
char **ptr;
MEM_ROOT *mem_root; /* The string will be allocated on thd->mem_root */
public :
Read_string(MEM_ROOT *mem_root_arg, char **ptr_arg) :
ptr(ptr_arg), mem_root(mem_root_arg)
{}
bool read_value(json_engine_t *je, const char *value_name,
String *err_buf) override
{
return read_string(mem_root, je, value_name, err_buf, *ptr);
}
};
class Read_double : public Read_value
{
double *ptr;
public :
Read_double(double *ptr_arg) : ptr(ptr_arg) {}
bool read_value(json_engine_t *je, const char *value_name,
String *err_buf) override
{
return read_double(je, value_name, err_buf, *ptr);
}
};
template <typename T, ha_rows MAX_VALUE>
class Read_non_neg_integer : public Read_value
{
T *ptr;
public :
Read_non_neg_integer(T *ptr_arg) : ptr(ptr_arg) {}
bool read_value(json_engine_t *je, const char *value_name,
String *err_buf) override
{
ha_rows temp_val;
const char *type= "" ;
switch (MAX_VALUE)
{
case 1 :
type= "boolean" ;
break ;
case UINT_MAX:
type= "unsigned int" ;
break ;
case LONGLONG_MAX:
type= "longlong" ;
break ;
case ULONGLONG_MAX:
type= "unsigned longlong" ;
break ;
default :
err_buf->append(STRING_WITH_LEN("wrong MAX_VALUE provided i.e.: " ));
err_buf->q_append_int64(MAX_VALUE);
return 1 ;
}
if (read_ha_rows_and_check_limit(je, value_name, err_buf, temp_val,
MAX_VALUE, type, false ))
{
return 1 ;
}
switch (MAX_VALUE)
{
case 1 :
*ptr= temp_val == 1 ;
break ;
case UINT_MAX:
case LONGLONG_MAX:
case ULONGLONG_MAX:
*ptr= (T) temp_val;
default :;
}
return 0 ;
}
};
/*
Read a JSON object into a value of type T .
Object construction is done in reader_func , which is expected to
constcut object T and invoke json_read_object ( ) for it .
*/
template <class T>
class Read_object : public Read_value
{
MEM_ROOT *mem_root;
T **ptr;
using reader_func_t= T* (*) (MEM_ROOT *mem_root,
json_engine_t *je,
String *err_buf);
reader_func_t reader_func;
public :
Read_object(MEM_ROOT *mem_arg, T **ptr_arg, reader_func_t reader_arg) :
mem_root(mem_arg), ptr(ptr_arg), reader_func(reader_arg) {}
bool read_value(json_engine_t *je, const char *value_name,
String *err_buf) override
{
*ptr = reader_func(mem_root, je, err_buf);
/* NULL return value means an error */
return (*ptr == NULL);
}
};
/*
Extends the Read_value interface to read an array of elements .
This class will just start reading the JSON array .
Reading of array members is done by descendant classes in read_container ( ) .
*/
class Read_array : public Read_value
{
int read_array_start(json_engine_t *je, const char *value_name,
String *err_buf)
{
if (json_scan_next(je) || je->state != JST_ARRAY_START)
{
err_buf->append(STRING_WITH_LEN("error reading " ));
err_buf->append(value_name, strlen(value_name));
err_buf->append(STRING_WITH_LEN(" value" ));
return 1 ;
}
return 0 ;
}
// here rc == -1 means we've caught array_end...
int after_read(int rc) { return rc > 0 ; }
public :
bool read_value(json_engine_t *je, const char *value_name,
String *err_buf) override
{
int rc= read_array_start(je, value_name, err_buf);
if (rc <= 0 )
rc= read_container(je, value_name, err_buf);
return after_read(rc);
}
virtual int read_container(json_engine_t *je, const char *name,
String *err_buf)= 0 ;
};
class Read_array_of_strings : public Read_array
{
MEM_ROOT *mem_root;
List<char > *strings;
public :
Read_array_of_strings(MEM_ROOT *mem_root_arg, List<char > *ranges_arg)
: mem_root(mem_root_arg), strings(ranges_arg)
{}
int read_container(json_engine_t *je, const char *name, String *err_buf)
override
{
if (json_scan_next(je))
return 1 ;
while (je->state != JST_ARRAY_END)
{
char *value;
if (read_string(mem_root, je, name, err_buf, value))
return 1 ;
strings->push_back(value, mem_root);
if (json_scan_next(je))
return 1 ;
}
return 0 ;
}
};
/*
Parse a JSON array of objects info a List < T > .
The constructor accepts reader_func argument which reads one JSON object
into an object of type T .
*/
template <class T>
class Read_object_array : public Read_array
{
MEM_ROOT *mem_root;
List<T> *list_ctx;
/*
A function to read individual array element . It ' s an object of type T .
*/
using reader_func_t= T* (*) (MEM_ROOT *mem_root,
json_engine_t *je,
String *err_buf);
reader_func_t reader_func;
public :
Read_object_array(MEM_ROOT *mem_root_arg, List<T> *list_arg, reader_func_t reader_arg)
: mem_root(mem_root_arg), list_ctx(list_arg), reader_func(reader_arg)
{}
int read_container(json_engine_t *je, const char *name, String *err_buf)
override
{
DBUG_ASSERT(je->state == JST_ARRAY_START);
int rc= json_scan_next(je);
while (1 )
{
if (je->state == JST_ARRAY_END)
return -1 ; // End of array
/* We get JST_VALUE state before each element. Check and consume it */
if (je->state != JST_VALUE)
return 1 ; // Error
if (json_scan_next(je))
return 1 ;
/* Read the element */
T *elem= reader_func(mem_root, je, err_buf);
if (!elem)
return 1 ; // Error
if (list_ctx->push_back(elem, mem_root))
return 1 ;
/* Consume JST_OBJ_END that is left after reading an object */
if (je->state == JST_OBJ_END && json_scan_next(je))
return 1 ; // Error
}
return rc;
}
};
}; /* namespace json_reader */
#endif
Messung V0.5 in Prozent C=93 H=98 G=95
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland