mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	 dfcbb30a92
			
		
	
	
	dfcbb30a92
	
	
	
		
			
			This patch can be viewed as combination of two parts: 1) Enabling '-' in the path so that the parser does not give out a warning. 2) Setting the negative index to a correct value and returning the appropriate value. 1) To enable using the negative index in the path: To make the parser not return warning when negative index is used in path '-' needs to be allowed in json path characters. P_NEG is added to enable this and is made recognizable by setting the 45th index of json_path_chr_map[] to P_NEG (instead of previous P_ETC) because 45 corresponds to '-' in unicode. When the path is being parsed and '-' is encountered, the parser should recognize it as parsing '-' sign, so a new json state PS_NEG is required. When the state is PS_NEG, it means that a negative integer is going to be parsed so set is_negative_index of current step to 1 and n_item is set accordingly when integer is encountered after '-'. Next proceed with parsing rest of the path and get the correct path. Next thing is parsing the json and returning correct value. 2) Setting the negative index to a correct value and returning the value: While parsing json if we encounter array and the path step for the array is a negative index (n_item < 0), then we can count the number of elements in the array and set n_item to correct corresponding value. This is done in json_skip_array_and_count.
		
			
				
	
	
		
			186 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright (c) 2016, MariaDB Corp. All rights reserved.
 | |
| 
 | |
|    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 St, Fifth Floor, Boston, MA  02110-1301  USA */
 | |
| 
 | |
| #include "my_config.h"
 | |
| #include "config.h"
 | |
| #include <tap.h>
 | |
| #include <my_global.h>
 | |
| #include <my_sys.h>
 | |
| #include <json_lib.h>
 | |
| 
 | |
| /* The character set used for JSON all over this test. */
 | |
| static CHARSET_INFO *ci;
 | |
| 
 | |
| #define s_e(j) j, j + strlen((const char *) j)
 | |
| 
 | |
| 
 | |
| struct st_parse_result
 | |
| {
 | |
|   int n_keys;
 | |
|   int n_values;
 | |
|   int n_arrays;
 | |
|   int n_objects;
 | |
|   int n_steps;
 | |
|   int error;
 | |
|   uchar keyname_csum;
 | |
| };
 | |
| 
 | |
| 
 | |
| static void parse_json(const uchar *j, struct st_parse_result *result)
 | |
| {
 | |
|   json_engine_t je;
 | |
| 
 | |
|   bzero(result, sizeof(*result));
 | |
| 
 | |
|   if (json_scan_start(&je, ci, s_e(j)))
 | |
|     return;
 | |
| 
 | |
|   do
 | |
|   {
 | |
|     result->n_steps++;
 | |
|     switch (je.state)
 | |
|     {
 | |
|     case JST_KEY:
 | |
|       result->n_keys++;
 | |
|       while (json_read_keyname_chr(&je) == 0)
 | |
|       {
 | |
|         result->keyname_csum^= je.s.c_next;
 | |
|       }
 | |
|       if (je.s.error)
 | |
|         return;
 | |
|       break;
 | |
|     case JST_VALUE:
 | |
|       result->n_values++;
 | |
|       break;
 | |
|     case JST_OBJ_START:
 | |
|       result->n_objects++;
 | |
|       break;
 | |
|     case JST_ARRAY_START:
 | |
|       result->n_arrays++;
 | |
|       break;
 | |
|     default:
 | |
|       break;
 | |
|     };
 | |
|   } while (json_scan_next(&je) == 0);
 | |
| 
 | |
|   result->error= je.s.error;
 | |
| }
 | |
| 
 | |
| 
 | |
| static const uchar *js0= (const uchar *) "123";
 | |
| static const uchar *js1= (const uchar *) "[123, \"text\"]";
 | |
| static const uchar *js2= (const uchar *) "{\"key1\":123, \"key2\":\"text\"}";
 | |
| static const uchar *js3= (const uchar *) "{\"key1\":{\"ikey1\":321},"
 | |
|                                           "\"key2\":[\"text\", 321]}";
 | |
| 
 | |
| /*
 | |
|   Test json_lib functions to parse JSON.
 | |
| */
 | |
| static void
 | |
| test_json_parsing()
 | |
| {
 | |
|   struct st_parse_result r;
 | |
|   parse_json(js0, &r);
 | |
|   ok(r.n_steps == 1 && r.n_values == 1, "simple value");
 | |
|   parse_json(js1, &r);
 | |
|   ok(r.n_steps == 5 && r.n_values == 3 && r.n_arrays == 1, "array");
 | |
|   parse_json(js2, &r);
 | |
|   ok(r.n_steps == 5 && r.n_keys == 2 && r.n_objects == 1 && r.keyname_csum == 3,
 | |
|      "object");
 | |
|   parse_json(js3, &r);
 | |
|   ok(r.n_steps == 12 && r.n_keys == 3 && r.n_objects == 2 &&
 | |
|      r.n_arrays == 1 && r.keyname_csum == 44,
 | |
|      "complex json");
 | |
| }
 | |
| 
 | |
| 
 | |
| static const uchar *p0= (const uchar *) "$.key1[12].*[*]";
 | |
| /*
 | |
|   Test json_lib functions to parse JSON path.
 | |
| */
 | |
| static void
 | |
| test_path_parsing()
 | |
| {
 | |
|   json_path_t p;
 | |
|   if (json_path_setup(&p, ci, s_e(p0)))
 | |
|     return;
 | |
|   ok(p.last_step - p.steps == 4 && 
 | |
|      p.steps[0].type == JSON_PATH_ARRAY_WILD &&
 | |
|      p.steps[1].type == JSON_PATH_KEY &&
 | |
|      p.steps[2].type == JSON_PATH_ARRAY && p.steps[2].n_item == 12 &&
 | |
|      p.steps[3].type == JSON_PATH_KEY_WILD &&
 | |
|      p.steps[4].type == JSON_PATH_ARRAY_WILD,
 | |
|      "path");
 | |
| }
 | |
| 
 | |
| 
 | |
| static const uchar *fj0=(const uchar *) "[{\"k0\":123, \"k1\":123, \"k1\":123},"
 | |
|                                         " {\"k3\":321, \"k4\":\"text\"},"
 | |
|                                         " {\"k1\":[\"text\"], \"k2\":123}]";
 | |
| static const uchar *fp0= (const uchar *) "$[*].k1";
 | |
| /*
 | |
|   Test json_lib functions to search through JSON.
 | |
| */
 | |
| static void
 | |
| test_search()
 | |
| {
 | |
|   json_engine_t je;
 | |
|   json_path_t p;
 | |
|   json_path_step_t *cur_step;
 | |
|   int n_matches, scal_values;
 | |
|   int array_counters[JSON_DEPTH_LIMIT];
 | |
| 
 | |
|   if (json_scan_start(&je, ci, s_e(fj0)) ||
 | |
|       json_path_setup(&p, ci, s_e(fp0)))
 | |
|     return;
 | |
| 
 | |
|   cur_step= p.steps;
 | |
|   n_matches= scal_values= 0;
 | |
|   while (json_find_path(&je, &p, &cur_step, array_counters) == 0)
 | |
|   {
 | |
|     n_matches++;
 | |
|     if (json_read_value(&je))
 | |
|       return;
 | |
|     if (json_value_scalar(&je))
 | |
|     {
 | |
|       scal_values++;
 | |
|       if (json_scan_next(&je))
 | |
|         return;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       if (json_skip_level(&je) || json_scan_next(&je))
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   ok(n_matches == 3, "search");
 | |
| }
 | |
| 
 | |
| 
 | |
| int main()
 | |
| {
 | |
|   ci= &my_charset_utf8mb3_general_ci;
 | |
| 
 | |
|   plan(6);
 | |
|   diag("Testing json_lib functions.");
 | |
| 
 | |
|   test_json_parsing();
 | |
|   test_path_parsing();
 | |
|   test_search();
 | |
| 
 | |
|   return exit_status();
 | |
| }
 |