Changeset: 639c163bd823 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/639c163bd823
Added Files:
monetdb5/modules/atoms/pg_jsonpath/jsonpath_exec.c
monetdb5/modules/atoms/pg_jsonpath/yyjson.c
monetdb5/modules/atoms/pg_jsonpath/yyjson.h
Modified Files:
monetdb5/modules/atoms/pg_jsonpath/CMakeLists.txt
Branch: json-extend
Log Message:
import yyjson jsonpath_exec as is
diffs (truncated from 22878 to 300 lines):
diff --git a/monetdb5/modules/atoms/pg_jsonpath/CMakeLists.txt
b/monetdb5/modules/atoms/pg_jsonpath/CMakeLists.txt
--- a/monetdb5/modules/atoms/pg_jsonpath/CMakeLists.txt
+++ b/monetdb5/modules/atoms/pg_jsonpath/CMakeLists.txt
@@ -26,7 +26,10 @@ BISON_TARGET(jsonpath_parser
target_sources(pg_jsonpath
PRIVATE
${FLEX_jsonpath_scanner_OUTPUTS}
- ${BISON_jsonpath_parser_OUTPUT_SOURCE})
+ ${BISON_jsonpath_parser_OUTPUT_SOURCE}
+ yyjson.c # for now just build yyjson directly into pg_jsonpath
+ jsonpath.c
+ jsonpath_exec.c)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jsonpath_scan.l
${CMAKE_CURRENT_BINARY_DIR}/jsonpath_scan.l
@@ -41,7 +44,8 @@ target_link_libraries(pg_jsonpath
monetdb_config_header
bat
sqlinclude
- sqlcommon)
+ sqlcommon
+ mal)
target_include_directories(pg_jsonpath
PRIVATE
diff --git a/monetdb5/modules/atoms/pg_jsonpath/jsonpath_exec.c
b/monetdb5/modules/atoms/pg_jsonpath/jsonpath_exec.c
new file mode 100644
--- /dev/null
+++ b/monetdb5/modules/atoms/pg_jsonpath/jsonpath_exec.c
@@ -0,0 +1,4494 @@
+/*-------------------------------------------------------------------------
+ *
+ * jsonpath_exec.c
+ * Routines for SQL/JSON path execution.
+ *
+ * Jsonpath is executed in the global context stored in JsonPathExecContext,
+ * which is passed to almost every function involved into execution. Entry
+ * point for jsonpath execution is executeJsonPath() function, which
+ * initializes execution context including initial JsonPathItem and JsonbValue,
+ * flags, stack for calculation of @ in filters.
+ *
+ * The result of jsonpath query execution is enum JsonPathExecResult and
+ * if succeeded sequence of JsonbValue, written to JsonValueList *found, which
+ * is passed through the jsonpath items. When found == NULL, we're inside
+ * exists-query and we're interested only in whether result is empty. In this
+ * case execution is stopped once first result item is found, and the only
+ * execution result is JsonPathExecResult. The values of JsonPathExecResult
+ * are following:
+ * - jperOk -- result sequence is not empty
+ * - jperNotFound -- result sequence is empty
+ * - jperError -- error occurred during execution
+ *
+ * Jsonpath is executed recursively (see executeItem()) starting form the
+ * first path item (which in turn might be, for instance, an arithmetic
+ * expression evaluated separately). On each step single JsonbValue obtained
+ * from previous path item is processed. The result of processing is a
+ * sequence of JsonbValue (probably empty), which is passed to the next path
+ * item one by one. When there is no next path item, then JsonbValue is added
+ * to the 'found' list. When found == NULL, then execution functions just
+ * return jperOk (see executeNextItem()).
+ *
+ * Many of jsonpath operations require automatic unwrapping of arrays in lax
+ * mode. So, if input value is array, then corresponding operation is
+ * processed not on array itself, but on all of its members one by one.
+ * executeItemOptUnwrapTarget() function have 'unwrap' argument, which
indicates
+ * whether unwrapping of array is needed. When unwrap == true, each of array
+ * members is passed to executeItemOptUnwrapTarget() again but with unwrap ==
false
+ * in order to avoid subsequent array unwrapping.
+ *
+ * All boolean expressions (predicates) are evaluated by executeBoolItem()
+ * function, which returns tri-state JsonPathBool. When error is occurred
+ * during predicate execution, it returns jpbUnknown. According to standard
+ * predicates can be only inside filters. But we support their usage as
+ * jsonpath expression. This helps us to implement @@ operator. In this case
+ * resulting JsonPathBool is transformed into jsonb bool or null.
+ *
+ * Arithmetic and boolean expression are evaluated recursively from expression
+ * tree top down to the leaves. Therefore, for binary arithmetic expressions
+ * we calculate operands first. Then we check that results are numeric
+ * singleton lists, calculate the result and pass it to the next path item.
+ *
+ * Copyright (c) 2019-2024, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/backend/utils/adt/jsonpath_exec.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "catalog/pg_collation.h"
+#include "catalog/pg_type.h"
+#include "executor/execExpr.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "nodes/miscnodes.h"
+#include "nodes/nodeFuncs.h"
+#include "regex/regex.h"
+#include "utils/builtins.h"
+#include "utils/date.h"
+#include "utils/datetime.h"
+#include "utils/float.h"
+#include "utils/formatting.h"
+#include "utils/json.h"
+#include "utils/jsonpath.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/timestamp.h"
+
+/*
+ * Represents "base object" and it's "id" for .keyvalue() evaluation.
+ */
+typedef struct JsonBaseObjectInfo
+{
+ JsonbContainer *jbc;
+ int id;
+} JsonBaseObjectInfo;
+
+/* Callbacks for executeJsonPath() */
+typedef JsonbValue *(*JsonPathGetVarCallback) (void *vars, char *varName, int
varNameLen,
+
JsonbValue *baseObject, int *baseObjectId);
+typedef int (*JsonPathCountVarsCallback) (void *vars);
+
+/*
+ * Context of jsonpath execution.
+ */
+typedef struct JsonPathExecContext
+{
+ void *vars; /* variables to substitute into
jsonpath */
+ JsonPathGetVarCallback getVar; /* callback to extract a given variable
+ * from
'vars' */
+ JsonbValue *root; /* for $ evaluation */
+ JsonbValue *current; /* for @ evaluation */
+ JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue()
+ *
evaluation */
+ int lastGeneratedObjectId; /* "id" counter for
.keyvalue()
+
* evaluation */
+ int innermostArraySize; /* for LAST array index
evaluation */
+ bool laxMode; /* true for "lax" mode, false
for "strict"
+ * mode */
+ bool ignoreStructuralErrors; /* with "true" structural
errors such
+
* as absence of required json item or
+
* unexpected json item type are
+
* ignored */
+ bool throwErrors; /* with "false" all suppressible errors
are
+ * suppressed */
+ bool useTz;
+} JsonPathExecContext;
+
+/* Context for LIKE_REGEX execution. */
+typedef struct JsonLikeRegexContext
+{
+ text *regex;
+ int cflags;
+} JsonLikeRegexContext;
+
+/* Result of jsonpath predicate evaluation */
+typedef enum JsonPathBool
+{
+ jpbFalse = 0,
+ jpbTrue = 1,
+ jpbUnknown = 2
+} JsonPathBool;
+
+/* Result of jsonpath expression evaluation */
+typedef enum JsonPathExecResult
+{
+ jperOk = 0,
+ jperNotFound = 1,
+ jperError = 2
+} JsonPathExecResult;
+
+#define jperIsError(jper) ((jper) == jperError)
+
+/*
+ * List of jsonb values with shortcut for single-value list.
+ */
+typedef struct JsonValueList
+{
+ JsonbValue *singleton;
+ List *list;
+} JsonValueList;
+
+typedef struct JsonValueListIterator
+{
+ JsonbValue *value;
+ List *list;
+ ListCell *next;
+} JsonValueListIterator;
+
+/* Structures for JSON_TABLE execution */
+
+/*
+ * Struct holding the result of jsonpath evaluation, to be used as source row
+ * for JsonTableGetValue() which in turn computes the values of individual
+ * JSON_TABLE columns.
+ */
+typedef struct JsonTablePlanRowSource
+{
+ Datum value;
+ bool isnull;
+} JsonTablePlanRowSource;
+
+/*
+ * State of evaluation of row pattern derived by applying jsonpath given in
+ * a JsonTablePlan to an input document given in the parent TableFunc.
+ */
+typedef struct JsonTablePlanState
+{
+ /* Original plan */
+ JsonTablePlan *plan;
+
+ /* The following fields are only valid for JsonTablePathScan plans */
+
+ /* jsonpath to evaluate against the input doc to get the row pattern */
+ JsonPath *path;
+
+ /*
+ * Memory context to use when evaluating the row pattern from the
jsonpath
+ */
+ MemoryContext mcxt;
+
+ /* PASSING arguments passed to jsonpath executor */
+ List *args;
+
+ /* List and iterator of jsonpath result values */
+ JsonValueList found;
+ JsonValueListIterator iter;
+
+ /* Currently selected row for JsonTableGetValue() to use */
+ JsonTablePlanRowSource current;
+
+ /* Counter for ORDINAL columns */
+ int ordinal;
+
+ /* Nested plan, if any */
+ struct JsonTablePlanState *nested;
+
+ /* Left sibling, if any */
+ struct JsonTablePlanState *left;
+
+ /* Right sibling, if any */
+ struct JsonTablePlanState *right;
+
+ /* Parent plan, if this is a nested plan */
+ struct JsonTablePlanState *parent;
+} JsonTablePlanState;
+
+/* Random number to identify JsonTableExecContext for sanity checking */
+#define JSON_TABLE_EXEC_CONTEXT_MAGIC 418352867
+
+typedef struct JsonTableExecContext
+{
+ int magic;
+
+ /* State of the plan providing a row evaluated from "root" jsonpath */
+ JsonTablePlanState *rootplanstate;
+
+ /*
+ * Per-column JsonTablePlanStates for all columns including the nested
+ * ones.
+ */
+ JsonTablePlanState **colplanstates;
+} JsonTableExecContext;
+
+/* strict/lax flags is decomposed into four [un]wrap/error flags */
+#define jspStrictAbsenceOfErrors(cxt) (!(cxt)->laxMode)
+#define jspAutoUnwrap(cxt) ((cxt)->laxMode)
+#define jspAutoWrap(cxt) ((cxt)->laxMode)
+#define jspIgnoreStructuralErrors(cxt) ((cxt)->ignoreStructuralErrors)
+#define jspThrowErrors(cxt) ((cxt)->throwErrors)
+
+/* Convenience macro: return or throw error depending on context */
+#define RETURN_ERROR(throw_error) \
+do { \
+ if (jspThrowErrors(cxt)) \
+ throw_error; \
+ else \
+ return jperError; \
+} while (0)
+
+typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
+
JsonbValue *larg,
+
JsonbValue *rarg,
+
void *param);
+typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
+
+static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
+
JsonPathGetVarCallback getVar,
+
JsonPathCountVarsCallback countVars,
+
Jsonb *json, bool throwErrors,
+
JsonValueList *result, bool useTz);
+static JsonPathExecResult executeItem(JsonPathExecContext *cxt,
+
JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
+static JsonPathExecResult executeItemOptUnwrapTarget(JsonPathExecContext *cxt,
+
JsonPathItem *jsp, JsonbValue *jb,
+
JsonValueList *found, bool unwrap);
+static JsonPathExecResult executeItemUnwrapTargetArray(JsonPathExecContext
*cxt,
+
JsonPathItem *jsp, JsonbValue *jb,
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]