Skip to content

Commit

Permalink
[#463] Migrate JSON, deque, ART & value types(round 2)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jubilee101 committed Oct 25, 2024
1 parent 8801878 commit 2ed11c8
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 28 deletions.
2 changes: 2 additions & 0 deletions doc/manual/98-acknowledgement.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Henrique de Carvalho <[email protected]>
Yihe Lu <[email protected]>
Eugenio Gigante <[email protected]>
Mohanad Khaled <[email protected]>
Haoran Zhang <[email protected]>
```

## Committers
Expand Down Expand Up @@ -50,3 +51,4 @@ the project on [Twitter][twitter] as well.
## License

[BSD-3-Clause][license]

11 changes: 10 additions & 1 deletion src/include/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@ pgagroal_json_put(struct json* item, char* key, uintptr_t val, enum value_type t
uintptr_t
pgagroal_json_get(struct json* item, char* tag);

/**
* Check if the json item contains the given key
* @param item The json item
* @param key The key
* @return True if the key exists, otherwise false
*/
bool
pgagroal_json_contains_key(struct json* item, char* key);

/**
* Append an entry into the json array
* If the entry is put into an empty json object, it will be treated as json array,
Expand Down Expand Up @@ -192,4 +201,4 @@ pgagroal_json_destroy(struct json* object);
}
#endif

#endif
#endif
1 change: 1 addition & 0 deletions src/include/pgagroal.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ extern "C" {
#define INDENT_PER_LEVEL 2
#define FORMAT_JSON 0
#define FORMAT_TEXT 1
#define FORMAT_JSON_COMPACT 2
#define BULLET_POINT "- "

#define likely(x) __builtin_expect (!!(x), 1)
Expand Down
8 changes: 8 additions & 0 deletions src/include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,14 @@ pgagroal_indent(char* str, char* tag, int indent);
bool
pgagroal_compare_string(const char* str1, const char* str2);

/**
* Escape a string
* @param str The original string
* @return The escaped string
*/
char*
pgagroal_escape_string(char* str);

#ifdef DEBUG

/**
Expand Down
3 changes: 1 addition & 2 deletions src/include/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


#ifndef PGAGROAL_VALUE_H
#define PGAGROAL_VALUE_H

Expand Down Expand Up @@ -59,7 +58,7 @@ enum value_type {
ValueDeque,
ValueART,
ValueRef,
ValueVerifyEntry,
ValueMem,
};

/**
Expand Down
75 changes: 72 additions & 3 deletions src/libpgagroal/art.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
*/

#include <art.h>
#include <json.h>
#include <utils.h>

#include <stdbool.h>
Expand Down Expand Up @@ -292,9 +293,15 @@ art_to_json_string_cb(void* param, const unsigned char* key, uint32_t key_len, s
static int
art_to_text_string_cb(void* param, const unsigned char* key, uint32_t key_len, struct value* value);

static int
art_to_compact_json_string_cb(void* param, const unsigned char* key, uint32_t key_len, struct value* value);

static char*
to_json_string(struct art* t, char* tag, int indent);

static char*
to_compact_json_string(struct art* t, char* tag, int indent);

static char*
to_text_string(struct art* t, char* tag, int indent);

Expand Down Expand Up @@ -382,6 +389,10 @@ pgagroal_art_to_string(struct art* t, int32_t format, char* tag, int indent)
{
return to_text_string(t, tag, indent);
}
else if (format == FORMAT_JSON_COMPACT)
{
return to_compact_json_string(t, tag, indent);
}
return NULL;
}

Expand Down Expand Up @@ -1459,10 +1470,13 @@ art_to_json_string_cb(void* param, const unsigned char* key, uint32_t key_len, s
struct to_string_param* p = (struct to_string_param*) param;
char* str = NULL;
char* tag = NULL;
char* translated_key = NULL;
p->cnt++;
bool has_next = p->cnt < p->t->size;
tag = pgagroal_append_char(tag, '"');
tag = pgagroal_append(tag, (char*)key);
translated_key = pgagroal_escape_string((char*)key);
tag = pgagroal_append(tag, translated_key);
free(translated_key);
tag = pgagroal_append_char(tag, '"');
tag = pgagroal_append(tag, ": ");
str = pgagroal_value_to_string(value, FORMAT_JSON, tag, p->indent);
Expand All @@ -1474,6 +1488,30 @@ art_to_json_string_cb(void* param, const unsigned char* key, uint32_t key_len, s
return 0;
}

static int
art_to_compact_json_string_cb(void* param, const unsigned char* key, uint32_t key_len, struct value* value)
{
struct to_string_param* p = (struct to_string_param*) param;
char* str = NULL;
char* tag = NULL;
char* translated_key = NULL;
p->cnt++;
bool has_next = p->cnt < p->t->size;
tag = pgagroal_append_char(tag, '"');
translated_key = pgagroal_escape_string((char*)key);
tag = pgagroal_append(tag, (char*)translated_key);
free(translated_key);
tag = pgagroal_append_char(tag, '"');
tag = pgagroal_append(tag, ":");
str = pgagroal_value_to_string(value, FORMAT_JSON_COMPACT, tag, p->indent);
free(tag);
p->str = pgagroal_append(p->str, str);
p->str = pgagroal_append(p->str, has_next ? "," : "");

free(str);
return 0;
}

static int
art_to_text_string_cb(void* param, const unsigned char* key, uint32_t key_len, struct value* value)
{
Expand All @@ -1484,15 +1522,23 @@ art_to_text_string_cb(void* param, const unsigned char* key, uint32_t key_len, s
bool has_next = p->cnt < p->t->size;
tag = pgagroal_append(tag, (char*)key);
tag = pgagroal_append(tag, ": ");
if (value->type == ValueJSON)
if (value->type == ValueJSON && ((struct json*) value->data)->type != JSONUnknown)
{
tag = pgagroal_append(tag, "\n");
}
if (pgagroal_compare_string(p->tag, BULLET_POINT))
{
if (p->cnt == 1)
{
str = pgagroal_value_to_string(value, FORMAT_TEXT, tag, 0);
if (value->type != ValueJSON || ((struct json*) value->data)->type == JSONUnknown)
{
str = pgagroal_value_to_string(value, FORMAT_TEXT, tag, 0);
}
else
{
p->str = pgagroal_indent(p->str, tag, 0);
str = pgagroal_value_to_string(value, FORMAT_TEXT, NULL, p->indent + INDENT_PER_LEVEL);
}
}
else
{
Expand Down Expand Up @@ -1535,6 +1581,29 @@ to_json_string(struct art* t, char* tag, int indent)
return ret;
}

static char*
to_compact_json_string(struct art* t, char* tag, int indent)
{
char* ret = NULL;
ret = pgagroal_indent(ret, tag, indent);
if (t == NULL || t->size == 0)
{
ret = pgagroal_append(ret, "{}");
return ret;
}
ret = pgagroal_append(ret, "{");
struct to_string_param param = {
.indent = indent,
.str = ret,
.t = t,
.cnt = 0,
};
art_iterate(t, art_to_compact_json_string_cb, &param);
ret = param.str;
ret = pgagroal_append(ret, "}");
return ret;
}

static char*
to_text_string(struct art* t, char* tag, int indent)
{
Expand Down
43 changes: 43 additions & 0 deletions src/libpgagroal/deque.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ deque_find(struct deque* deque, char* tag);
static char*
to_json_string(struct deque* deque, char* tag, int indent);

static char*
to_compact_json_string(struct deque* deque, char* tag, int indent);

static char*
to_text_string(struct deque* deque, char* tag, int indent);

Expand Down Expand Up @@ -229,6 +232,10 @@ pgagroal_deque_to_string(struct deque* deque, int32_t format, char* tag, int ind
{
return to_text_string(deque, tag, indent);
}
else if (format == FORMAT_JSON_COMPACT)
{
return to_compact_json_string(deque, tag, indent);
}
return NULL;
}

Expand Down Expand Up @@ -462,6 +469,42 @@ to_json_string(struct deque* deque, char* tag, int indent)
return ret;
}

static char*
to_compact_json_string(struct deque* deque, char* tag, int indent)
{
char* ret = NULL;
ret = pgagroal_indent(ret, tag, indent);
struct deque_node* cur = NULL;
if (deque == NULL || pgagroal_deque_empty(deque))
{
ret = pgagroal_append(ret, "[]");
return ret;
}
deque_read_lock(deque);
ret = pgagroal_append(ret, "[");
cur = deque_next(deque, deque->start);
while (cur != NULL)
{
bool has_next = cur->next != deque->end;
char* str = NULL;
char* t = NULL;
if (cur->tag != NULL)
{
t = pgagroal_append(t, cur->tag);
t = pgagroal_append(t, ":");
}
str = pgagroal_value_to_string(cur->data, FORMAT_JSON_COMPACT, t, indent);
free(t);
ret = pgagroal_append(ret, str);
ret = pgagroal_append(ret, has_next ? "," : "");
free(str);
cur = deque_next(deque, cur);
}
ret = pgagroal_append(ret, "]");
deque_unlock(deque);
return ret;
}

static char*
to_text_string(struct deque* deque, char* tag, int indent)
{
Expand Down
71 changes: 67 additions & 4 deletions src/libpgagroal/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ static int parse_string(char* str, uint64_t* index, struct json** obj);
static int json_add(struct json* obj, char* key, uintptr_t val, enum value_type type);
static int fill_value(char* str, char* key, uint64_t* index, struct json* o);
static bool value_start(char ch);
static int handle_escape_char(char* str, uint64_t* index, uint64_t len, char* ch);

int
pgagroal_json_append(struct json* array, uintptr_t entry, enum value_type type)
Expand Down Expand Up @@ -117,10 +118,7 @@ pgagroal_json_to_string(struct json* object, int32_t format, char* tag, int inde
if (object == NULL || (object->type == JSONUnknown || object->elements == NULL))
{
str = pgagroal_indent(str, tag, indent);
if (format == FORMAT_JSON)
{
str = pgagroal_append(str, "{}");
}
str = pgagroal_append(str, "{}");
return str;
}
if (object->type != JSONArray)
Expand Down Expand Up @@ -163,6 +161,16 @@ pgagroal_json_get(struct json* item, char* tag)
return pgagroal_art_search(item->elements, (unsigned char*)tag, strlen(tag) + 1);
}

bool
pgagroal_json_contains_key(struct json* item, char* key)
{
if (item == NULL || item->type != JSONItem || key == NULL || strlen(key) == 0)
{
return false;
}
return pgagroal_art_contains_key(item->elements, (unsigned char*)key, strlen(key) + 1);
}

int
pgagroal_json_iterator_create(struct json* object, struct json_iterator** iter)
{
Expand Down Expand Up @@ -325,6 +333,18 @@ parse_string(char* str, uint64_t* index, struct json** obj)
// The key
while (idx < len && str[idx] != '"')
{
char ec_ch;
// handle escape character
if (str[idx] == '\\')
{
if (handle_escape_char(str, &idx, len, &ec_ch))
{
goto error;
}
key = pgagroal_append_char(key, ec_ch);
continue;
}

key = pgagroal_append_char(key, str[idx++]);
}
if (idx == len || key == NULL)
Expand Down Expand Up @@ -443,6 +463,17 @@ fill_value(char* str, char* key, uint64_t* index, struct json* o)
idx++;
while (idx < len && str[idx] != '"')
{
char ec_ch;
if (str[idx] == '\\')
{
if (handle_escape_char(str, &idx, len, &ec_ch))
{
goto error;
}
val = pgagroal_append_char(val, ec_ch);
continue;
}

val = pgagroal_append_char(val, str[idx++]);
}
if (idx == len)
Expand Down Expand Up @@ -549,6 +580,38 @@ fill_value(char* str, char* key, uint64_t* index, struct json* o)
return 1;
}

static int
handle_escape_char(char* str, uint64_t* index, uint64_t len, char* ch)
{
uint64_t idx = *index;
idx++;
if (idx == len) // security check
{
return 1;
}
// Check the next character after checking '\' character
switch (str[idx])
{
case '\"':
case '\\':
*ch = str[idx];
break;
case 'n':
*ch = '\n';
break;
case 't':
*ch = '\t';
break;
case 'r':
*ch = '\r';
break;
default:
return 1;
}
*index = idx + 1;
return 0;
}

static bool
type_allowed(enum value_type type)
{
Expand Down
Loading

0 comments on commit 2ed11c8

Please sign in to comment.