/*------------------------------------------------------------------------- * * json.h * Core JSON manipulation routines used by JSON data type support, * along with miscellaneous declarations and includes. * * Copyright (c) 2010, PostgreSQL Global Development Group * Written by Joey Adams . * *------------------------------------------------------------------------- */ #ifndef JSON_H #define JSON_H #include "postgres.h" #include "access/heapam.h" #include "access/htup.h" #include "catalog/namespace.h" #include "catalog/pg_type.h" #include "funcapi.h" #include "libpq/pqformat.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/typcache.h" typedef struct varlena jsontype; #define DatumGetJSONP(X) ((jsontype *) PG_DETOAST_DATUM(X)) #define JSONPGetDatum(X) PointerGetDatum(X) #define PG_GETARG_JSON_P(n) DatumGetJSONP(PG_GETARG_DATUM(n)) #define PG_RETURN_JSON_P(x) PG_RETURN_POINTER(x) void report_corrupt_json(void); /* Keep the order of these enum entries in sync with * enum_type_names[] in json_ops.c . */ typedef enum { JSON_NULL, JSON_STRING, JSON_NUMBER, JSON_BOOL, JSON_OBJECT, JSON_ARRAY, JSON_TYPE_COUNT = JSON_ARRAY + 1, JSON_INVALID } json_type; #define json_type_is_valid(type) ((type) >= 0 && (type) < JSON_TYPE_COUNT) typedef struct JSON JSON; /* * All strings in JSON nodes are UTF-8-encoded, not server encoded. * The reason for this is because we need to encode/decode individual * Unicode codepoints when dealing with escape characters, but there * are no functions for efficiently converting between Unicode code points * and any server encoding. * * As an exception to the rule, if you only use node factory functions and * json_encode without the JSONOPT_ESCAPE_UNICODE option, you may operate * in the server encoding instead. */ struct JSON { json_type type; union { /* JSON_BOOL */ bool v_bool; /* JSON_STRING */ struct { char *str; size_t length; } string; /* * JSON_NUMBER * * Numbers are encoded as strings to avoid unnecessary precision loss. */ char *number; /* JSON_ARRAY or JSON_OBJECT (children) */ struct { JSON *head; JSON *tail; size_t count; } children; } v; JSON *parent; JSON *prev; JSON *next; /* * If node is a member of an object, key will be set. Otherwise, key will * be null. */ char *key; size_t key_length; struct json_orig { /* These only apply if this node is a member of an object. */ struct { const char *start; const char *end; } key_left_space, key, key_right_space; struct { const char *start; const char *end; } left_space, value, right_space; } orig; /* Used by jp_set to indicate we should not visit this node again. */ bool jp_changed; }; /*** Encoding / decoding / validation ***/ bool json_validate(const char *str); bool json_validate_server_encoded(const char *str); JSON *json_decode(const char *str); #define JSONOPT_USE_ORIG 1 #define JSONOPT_ESCAPE_UNICODE 2 #define JSONOPT_NO_TRIM 4 char *json_encode(JSON * node, int options); json_type json_text_type(const char *str, size_t nbytes); /*** Lookup / traversal ***/ #define json_foreach(child, parent) \ for ((child) = json_head(parent); (child) != NULL; (child) = (child)->next) static inline JSON * json_head(JSON * parent) { switch (parent->type) { case JSON_ARRAY: case JSON_OBJECT: return parent->v.children.head; default: return NULL; } } /*** Parent/child manipulation ***/ void json_append(JSON * parent, JSON * child); void json_remove(JSON * node); /*** Node factory functions ***/ JSON *json_mknode(json_type type); JSON *json_mkbool(bool v_bool); JSON *json_mkstring(const char *str, size_t length); JSON *json_mknumber(const char *number, size_t length); static inline JSON * json_mkarray(void) { return json_mknode(JSON_ARRAY); } static inline JSON * json_mkobject(void) { return json_mknode(JSON_OBJECT); } /*** Value get/set functions ***/ void json_touch_value(JSON * node); static inline bool json_get_bool(JSON * node) { Assert(node->type == JSON_BOOL); return node->v.v_bool; } static inline void json_set_bool(JSON * node, bool v_bool) { Assert(node->type == JSON_BOOL); node->v.v_bool = v_bool; json_touch_value(node); } const char *json_get_string(JSON * node, size_t *length_out); void json_set_string(JSON * node, const char *str, size_t length); const char *json_get_number(JSON * node); void json_set_number(JSON * node, const char *number, size_t length); void json_replace_value(JSON * node, JSON * replacement); /*** Miscellaneous utility functions ***/ char *json_decode_string(const char **sp, size_t *length, bool strict); char *json_encode_string(const char *str, size_t length, char quote, bool escape_unicode); #endif