From a2386a4ecf0c7215ee0b4b8f9aed105751797257 Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Sun, 16 Jul 2017 20:04:27 +0300 Subject: [PATCH 01/15] 1.0.1 Version --- META.json | 4 +- Makefile | 25 ++- expected/jsquery.out | 86 ++++++++++ jsquery--1.0.1.sql | 298 +++++++++++++++++++++++++++++++++ jsquery_io.c | 32 ++++ monq.h | 264 +++++++++++++++++++++++++++++ monq_create_query.c | 244 +++++++++++++++++++++++++++ monq_delete_query.c | 192 +++++++++++++++++++++ monq_get_jsquery.c | 388 +++++++++++++++++++++++++++++++++++++++++++ monq_gram.y | 244 +++++++++++++++++++++++++++ monq_scan.l | 96 +++++++++++ sql/jsquery.sql | 20 +++ 12 files changed, 1878 insertions(+), 15 deletions(-) create mode 100644 jsquery--1.0.1.sql create mode 100644 monq.h create mode 100644 monq_create_query.c create mode 100644 monq_delete_query.c create mode 100644 monq_get_jsquery.c create mode 100644 monq_gram.y create mode 100644 monq_scan.l diff --git a/META.json b/META.json index 35ba35f..3121bd1 100644 --- a/META.json +++ b/META.json @@ -2,7 +2,7 @@ "name": "JsQuery", "abstract": "JSON Query Language with GIN indexing support", "description": "JsQuery provides additional functionality for JSONB, such as a simple and effective way to search in nested objects and arrays, and more comparison operators with index support. It does this by implementing a specialized search syntax, the @@ operator, and the jsquery type for search strings.", - "version": "1.0.0", + "version": "1.0.1", "maintainer": [ "Teodor Sigaev ", "Alexander Korotkov ", @@ -42,7 +42,7 @@ }, "generated_by": "Josh Berkus", "meta-spec": { - "version": "1.0.0", + "version": "1.0.1", "url": "http://pgxn.org/meta/spec.txt" }, "tags": [ diff --git a/Makefile b/Makefile index 0892a24..ad1d169 100644 --- a/Makefile +++ b/Makefile @@ -2,38 +2,37 @@ MODULE_big = jsquery OBJS = jsonb_gin_ops.o jsquery_constr.o jsquery_extract.o \ - jsquery_gram.o jsquery_io.o jsquery_op.o jsquery_support.o + jsquery_gram.o jsquery_io.o jsquery_op.o jsquery_support.o \ + monq_gram.o monq_scan.o monq_get_jsquery.o monq_create_query.o monq_delete_query.o EXTENSION = jsquery -DATA = jsquery--1.0.sql -INCLUDES = jsquery.h +DATA = jsquery--1.0.1.sql +INCLUDES = jsquery.h monq.h REGRESS = jsquery # We need a UTF8 database ENCODING = UTF8 EXTRA_CLEAN = y.tab.c y.tab.h \ - jsquery_gram.c jsquery_scan.c jsquery_gram.h + jsquery_gram.c jsquery_scan.c jsquery_gram.h \ + monq_gram.c monq_scan.c monq_gram.h -ifdef USE_PGXS PG_CONFIG ?= pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) -else -subdir = contrib/jsquery -top_builddir = ../.. -include $(top_builddir)/src/Makefile.global -include $(top_srcdir)/contrib/contrib-global.mk -endif jsquery_gram.o: jsquery_scan.c jsquery_gram.c: BISONFLAGS += -d -distprep: jsquery_gram.c jsquery_scan.c +monq_gram.o: monq_scan.c + +monq_gram.c: BISONFLAGS += -d + +distprep: jsquery_gram.c jsquery_scan.c monq_gram.c monq_scan.c maintainer-clean: - rm -f jsquery_gram.c jsquery_scan.c jsquery_gram.h + rm -f jsquery_gram.c jsquery_scan.c jsquery_gram.h monq_gram.c monq_scan.c monq_gram.h install: installincludes diff --git a/expected/jsquery.out b/expected/jsquery.out index 14b2730..a5d4655 100644 --- a/expected/jsquery.out +++ b/expected/jsquery.out @@ -2913,4 +2913,90 @@ select v from test_jsquery where v @@ 'array = [2,3]' order by v; {"array": [2, 3]} (1 row) +---MongoDB query translator tests +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : 1 }'); + ?column? +---------- + t +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $eq : 1 } }'); + ?column? +---------- + t +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $ne : 1 } }'); + ?column? +---------- + f +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $lt : 1 } }'); + ?column? +---------- + f +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $lte : 1 } }'); + ?column? +---------- + t +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $gt : 1 } }'); + ?column? +---------- + f +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $gte : 1 } }'); + ?column? +---------- + t +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $in : [2,3] } }'); + ?column? +---------- + f +(1 row) + +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $nin : [2,3] } }'); + ?column? +---------- + t +(1 row) + +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : false } }'); + ?column? +---------- + f +(1 row) + +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : true } }'); + ?column? +---------- + t +(1 row) + +select parse_mquery('{ is : { $lt: 1 } }')::jsquery; + parse_mquery +-------------- + "is" < 1 +(1 row) + +select v from test_jsquery where v @@ parse_mquery('{ array : { $all: [2,3] } }') order by v; + v +---------------------- + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} +(3 rows) + +select v from test_jsquery where v @@ parse_mquery('{ { $text: { $search: "Flew" } } }'); + v +--- +(0 rows) + RESET enable_seqscan; diff --git a/jsquery--1.0.1.sql b/jsquery--1.0.1.sql new file mode 100644 index 0000000..0141bb4 --- /dev/null +++ b/jsquery--1.0.1.sql @@ -0,0 +1,298 @@ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION jsquery" to load this file. \quit + +CREATE TYPE jsquery; + +CREATE FUNCTION jsquery_in(cstring) + RETURNS jsquery + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE FUNCTION jsquery_out(jsquery) + RETURNS cstring + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE TYPE jsquery ( + INTERNALLENGTH = -1, + INPUT = jsquery_in, + OUTPUT = jsquery_out, + STORAGE = extended +); + +CREATE FUNCTION jsquery_json_exec(jsquery, jsonb) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE FUNCTION json_jsquery_exec(jsonb, jsquery) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR @@ ( + LEFTARG = jsquery, + RIGHTARG = jsonb, + PROCEDURE = jsquery_json_exec, + COMMUTATOR = '@@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +CREATE OPERATOR @@ ( + LEFTARG = jsonb, + RIGHTARG = jsquery, + PROCEDURE = json_jsquery_exec, + COMMUTATOR = '@@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +CREATE FUNCTION jsquery_join_and(jsquery, jsquery) + RETURNS jsquery + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR & ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_join_and, + COMMUTATOR = '&' +); + +CREATE FUNCTION jsquery_join_or(jsquery, jsquery) + RETURNS jsquery + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR | ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_join_or, + COMMUTATOR = '|' +); + +CREATE FUNCTION jsquery_not(jsquery) + RETURNS jsquery + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR ! ( + RIGHTARG = jsquery, + PROCEDURE = jsquery_not +); + +CREATE FUNCTION jsquery_lt(jsquery, jsquery) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE FUNCTION jsquery_le(jsquery, jsquery) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE FUNCTION jsquery_eq(jsquery, jsquery) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE FUNCTION jsquery_ne(jsquery, jsquery) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE FUNCTION jsquery_ge(jsquery, jsquery) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE FUNCTION jsquery_gt(jsquery, jsquery) + RETURNS bool + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR < ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_lt, + COMMUTATOR = '>', + NEGATOR = '>=', + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR <= ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_le, + COMMUTATOR = '>=', + NEGATOR = '>', + RESTRICT = scalarltsel, + JOIN = scalarltjoinsel +); + +CREATE OPERATOR = ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_eq, + COMMUTATOR = '=', + NEGATOR = '<>', + RESTRICT = eqsel, + JOIN = eqjoinsel, + HASHES, + MERGES +); + +CREATE OPERATOR <> ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_eq, + COMMUTATOR = '<>', + NEGATOR = '=', + RESTRICT = neqsel, + JOIN = neqjoinsel +); + +CREATE OPERATOR >= ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_ge, + COMMUTATOR = '<=', + NEGATOR = '<', + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE OPERATOR > ( + LEFTARG = jsquery, + RIGHTARG = jsquery, + PROCEDURE = jsquery_ge, + COMMUTATOR = '<', + NEGATOR = '<=', + RESTRICT = scalargtsel, + JOIN = scalargtjoinsel +); + +CREATE FUNCTION jsquery_cmp(jsquery, jsquery) + RETURNS int4 + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR CLASS jsquery_ops + DEFAULT FOR TYPE jsquery USING btree AS + OPERATOR 1 < , + OPERATOR 2 <= , + OPERATOR 3 = , + OPERATOR 4 >= , + OPERATOR 5 >, + FUNCTION 1 jsquery_cmp(jsquery, jsquery); + +CREATE FUNCTION jsquery_hash(jsquery) + RETURNS int4 + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR CLASS jsquery_ops + DEFAULT FOR TYPE jsquery USING hash AS + OPERATOR 1 =, + FUNCTION 1 jsquery_hash(jsquery); + +CREATE OR REPLACE FUNCTION gin_compare_jsonb_value_path(bytea, bytea) + RETURNS integer + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_compare_partial_jsonb_value_path(bytea, bytea, smallint, internal) + RETURNS integer + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_extract_jsonb_value_path(internal, internal, internal) + RETURNS internal + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_extract_jsonb_query_value_path(anyarray, internal, smallint, internal, internal, internal, internal) + RETURNS internal + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_consistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal, internal) + RETURNS boolean + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_triconsistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal) + RETURNS boolean + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR CLASS jsonb_value_path_ops + FOR TYPE jsonb USING gin AS + OPERATOR 7 @>, + OPERATOR 14 @@ (jsonb, jsquery), + FUNCTION 1 gin_compare_jsonb_value_path(bytea, bytea), + FUNCTION 2 gin_extract_jsonb_value_path(internal, internal, internal), + FUNCTION 3 gin_extract_jsonb_query_value_path(anyarray, internal, smallint, internal, internal, internal, internal), + FUNCTION 4 gin_consistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal, internal), + FUNCTION 5 gin_compare_partial_jsonb_value_path(bytea, bytea, smallint, internal), + FUNCTION 6 gin_triconsistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal), + STORAGE bytea; + +CREATE OR REPLACE FUNCTION gin_compare_jsonb_path_value(bytea, bytea) + RETURNS integer + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_compare_partial_jsonb_path_value(bytea, bytea, smallint, internal) + RETURNS integer + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_extract_jsonb_path_value(internal, internal, internal) + RETURNS internal + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_extract_jsonb_query_path_value(anyarray, internal, smallint, internal, internal, internal, internal) + RETURNS internal + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_consistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal, internal) + RETURNS boolean + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_triconsistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal) + RETURNS boolean + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR CLASS jsonb_path_value_ops + FOR TYPE jsonb USING gin AS + OPERATOR 7 @>, + OPERATOR 14 @@ (jsonb, jsquery), + FUNCTION 1 gin_compare_jsonb_path_value(bytea, bytea), + FUNCTION 2 gin_extract_jsonb_path_value(internal, internal, internal), + FUNCTION 3 gin_extract_jsonb_query_path_value(anyarray, internal, smallint, internal, internal, internal, internal), + FUNCTION 4 gin_consistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal, internal), + FUNCTION 5 gin_compare_partial_jsonb_path_value(bytea, bytea, smallint, internal), + FUNCTION 6 gin_triconsistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal), + STORAGE bytea; + +CREATE OR REPLACE FUNCTION gin_debug_query_value_path(jsquery) + RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_debug_query_path_value(jsquery) + RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION parse_mquery(cstring) + RETURNS jsquery + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; diff --git a/jsquery_io.c b/jsquery_io.c index 8a43e8e..734c8ca 100644 --- a/jsquery_io.c +++ b/jsquery_io.c @@ -19,6 +19,9 @@ #include "utils/json.h" #include "jsquery.h" +#include "monq.h" + +extern MQuery *parsemquery(char *str); PG_MODULE_MAGIC; @@ -168,6 +171,35 @@ jsquery_in(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } +PG_FUNCTION_INFO_V1(parse_mquery); +Datum +parse_mquery(PG_FUNCTION_ARGS) +{ + char *result = getJsquery(parse((char *) PG_GETARG_CSTRING(0))); + int32 len = strlen(result); + JsQueryParseItem *jsquery = parsejsquery(result, len); + JsQuery *res; + StringInfoData buf; + + initStringInfo(&buf); + enlargeStringInfo(&buf, 4 * len /* estimation */); + + appendStringInfoSpaces(&buf, VARHDRSZ); + + if (jsquery != NULL) + { + flattenJsQueryParseItem(&buf, jsquery, false); + + res = (JsQuery*)buf.data; + SET_VARSIZE(res, buf.len); + + PG_RETURN_JSQUERY(res); + } + + PG_RETURN_NULL(); +} + + static void printHint(StringInfo buf, JsQueryHint hint) { diff --git a/monq.h b/monq.h new file mode 100644 index 0000000..8dd7796 --- /dev/null +++ b/monq.h @@ -0,0 +1,264 @@ +#ifndef _MONQ_H_ +#define _MONQ_H_ + +#include "postgres.h" +#include "fmgr.h" +#include "miscadmin.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/jsonb.h" + +typedef enum TypeOfLeafValue +{ + S, + I, + A, + D, + B +} TypeOfLeafValue; + +typedef enum TypeOfOperator +{ + NOP, + MOP, + AOP, + VOP, + EOP +} TypeOfOperator; + +typedef enum ArrayOperatorType +{ + _IN, + _NIN, + _ALL +} ArrayOperatorType; + +typedef enum ExpressionOperatorType +{ + _OR, + _NOR, + _AND +} ExpressionOperatorType; + +typedef enum ValueOperatorType +{ + _LESS, + _EQ, + _NOTEQ, + _LESSEQ, + _GREAT, + _GREATEQ, + _TYPE, + _SIZE, + _EXISTS +} ValueOperatorType; + + +typedef enum TypeOfClause +{ + LEAF, + COMMENT, + TEXT, + WHERE, + EXPRESSION +} TypeOfClause; + +typedef enum TypeOfValue +{ + LF_VALUE, + OP_OBJECT +} TypeOfValue; + +typedef enum TypeOfElemMatchValue +{ + E_EXPRESSION, + E_OP_OBJECT +} TypeOfElemMatchValue; + +typedef enum TypeOfWhereClauseValue +{ + STR +} TypeOfWhereClauseValue; + +typedef struct MArray +{ + List *arrayList; +} MArray; + +typedef struct LeafValue +{ + TypeOfLeafValue type; + union + { + char *str; + char *i; + MArray *ar; + bool b; + char *d; + }; +} LeafValue; + +/* Operators */ +typedef struct ValueOperator +{ + TypeOfOperator type; + + ValueOperatorType value_op; + LeafValue *value; +} ValueOperator; + +typedef struct NotOperator +{ + TypeOfOperator type; + + struct Operator *op; +} NotOperator; + +typedef struct ArrayOperator +{ + TypeOfOperator type; + + ArrayOperatorType array_op; + MArray *ar; +} ArrayOperator; + +typedef struct ModOperator +{ + TypeOfOperator type; + + LeafValue *divisor; + LeafValue *remainder; +} ModOperator; + +typedef struct Operator +{ + TypeOfOperator type; +} Operator; + +typedef struct OperatorObject +{ + List *operatorList; +} OperatorObject; + +typedef struct MValue +{ + TypeOfValue type; + union + { + LeafValue *lv; + OperatorObject *oob; + }; +} MValue; + +typedef struct LeafClause +{ + TypeOfClause type; + + char *key; + MValue *vl; +} LeafClause; + +typedef struct CommentClause +{ + TypeOfClause type; + + char *op; + char *str; +} CommentClause; + +typedef struct WhereClauseValue +{ + TypeOfClause type; + + TypeOfWhereClauseValue val_type; + char *str; +} WhereClauseValue; + +typedef struct WhereClause +{ + TypeOfClause type; + + WhereClauseValue *wcv; +} WhereClause; + +typedef struct TextClause +{ + TypeOfClause type; + + char *search_str; + bool lang_op; + char *lang_str; + bool case_sense; + bool diacr_sense; +} TextClause; + +typedef struct Clause +{ + TypeOfClause type; +} Clause; + +typedef struct Expression +{ + List *clauseList; +} Expression; + +typedef struct ElemMatchOperator +{ + TypeOfOperator type; + + TypeOfElemMatchValue typeOfValue; + + union + { + Expression *expression; + OperatorObject *operatorOpbject; + }; +} ElemMatchOperator; + +typedef struct ExpressionClause +{ + TypeOfClause type; + + ExpressionOperatorType op; + List *expressionList; +} ExpressionClause; + +typedef struct MQuery +{ + Expression *exp; + Datum jsQuery; +} MQuery; + + +extern MArray *createNewArray(List *arrayList); +extern List *addArrayElement(LeafValue * value, List *arrayList); +extern Operator *createNotOperator(Operator *op); +extern Operator *createModOperator(LeafValue *divisor, LeafValue *remainder); +extern Operator *createArrayOperator(ArrayOperatorType op, MArray *ar); +extern Operator *createValueOperator(ValueOperatorType op, LeafValue *value); +extern Operator *createElemMatchOperatorExpression(Expression *expression); +extern Operator *createElemMatchOperatorOpObject(OperatorObject *oob); +extern LeafValue *createStringValue(char *str); +extern LeafValue *createDoubleValue(char* d); +extern LeafValue *createIntegerValue(char* i); +extern LeafValue *createArrayValue(MArray *ar); +extern LeafValue *createBooleanValue(bool b); +extern List *addOperator(Operator *op, List *operatorList); +extern OperatorObject *createOperatorObject(List *operatorList); +extern MValue *createOperatorObjectValue(OperatorObject *oob); +extern MValue *createLeafValueValue(LeafValue *lv); +extern Clause *createLeafClause(char* key, MValue *vl); +extern Clause *createCommentClause(char *op, char *str); +extern WhereClauseValue *stringToWhereClauseValue(char *str); +extern Clause *createWhereClause(WhereClauseValue *wcv); +extern List *addClause(Clause *clause, List *clauseList); +extern Expression *createExpression(List *clauseList); +extern List *addExpression(Expression *exp, List *expressionList); +extern Clause *createExpressionTreeClause(ExpressionOperatorType op, List *expressionList); +extern Clause *createTextClause(char* search_str, bool lang_op, char* lang_str, bool case_sense, bool diacr_sense); +extern MQuery *createQuery(Expression *exp); +extern void deleteMquery(MQuery *qu); +extern char *getJsquery(MQuery *query); +extern MQuery *parse(char *str); + +#endif \ No newline at end of file diff --git a/monq_create_query.c b/monq_create_query.c new file mode 100644 index 0000000..d0a72ee --- /dev/null +++ b/monq_create_query.c @@ -0,0 +1,244 @@ +#include +#include +#include + +#include "monq.h" + + +MArray * +createNewArray(List *arrayList) +{ + MArray *new_ar = (MArray *) palloc(sizeof(MArray)); + new_ar->arrayList = arrayList; + return new_ar; +} + +List * +addArrayElement(LeafValue *value, List *arrayList) +{ + return lappend(arrayList, value); +} + +Operator * +createNotOperator(Operator *op) +{ + NotOperator *new_op = (NotOperator *) palloc(sizeof(NotOperator)); + new_op->type = NOP; + new_op->op = op; + return (Operator *) new_op; +} + +Operator * +createModOperator(LeafValue *divisor, LeafValue *remainder) +{ + ModOperator *new_op = (ModOperator *) palloc(sizeof(ModOperator)); + new_op->type = MOP; + new_op->divisor = divisor; + new_op->remainder = remainder; + return (Operator *) new_op; +} + +Operator * +createArrayOperator(ArrayOperatorType op, MArray *ar) +{ + ArrayOperator *new_op = (ArrayOperator *) palloc(sizeof(ArrayOperator)); + new_op->type = AOP; + new_op->array_op = op; + new_op->ar = ar; + return (Operator*) new_op; +} + +Operator * +createValueOperator(ValueOperatorType op, LeafValue * value) +{ + ValueOperator *new_op = (ValueOperator *) palloc(sizeof(ValueOperator)); + new_op->type = VOP; + new_op->value_op = op; + new_op->value = value; + return (Operator *) new_op; +} + +Operator * +createElemMatchOperatorOpObject(OperatorObject *oob) +{ + ElemMatchOperator *new_op = (ElemMatchOperator *) palloc(sizeof(ElemMatchOperator)); + new_op->type = EOP; + new_op->typeOfValue = E_OP_OBJECT; + new_op->operatorOpbject = oob; + return (Operator *) new_op; +} + +Operator * +createElemMatchOperatorExpression(Expression *expression) +{ + ElemMatchOperator *new_op = (ElemMatchOperator *) palloc(sizeof(ElemMatchOperator)); + new_op->type = EOP; + new_op->typeOfValue = E_EXPRESSION; + new_op->expression = expression; + return (Operator *) new_op; +} + +LeafValue * +createStringValue(char *str) +{ + LeafValue *lv = (LeafValue *) palloc(sizeof(LeafValue)); + lv->type = S; + lv->str = str; + return lv; +} + +LeafValue * +createDoubleValue(char* d) +{ + LeafValue *lv = (LeafValue *) palloc(sizeof(LeafValue)); + lv->type = D; + lv->d = d; + return lv; +} + +LeafValue * +createIntegerValue(char* i) +{ + LeafValue *lv = (LeafValue *) palloc(sizeof(LeafValue)); + lv->type = I; + lv->i = i; + return lv; +} + +LeafValue * +createArrayValue(MArray *ar) +{ + LeafValue *lv = (LeafValue *) palloc(sizeof(LeafValue)); + lv->type = A; + lv->ar = ar; + return lv; +} + +LeafValue * +createBooleanValue(bool b) +{ + LeafValue *lv = (LeafValue *) palloc(sizeof(LeafValue)); + lv->type = B; + lv->b = b; + return lv; +} + +List * +addOperator(Operator *op, List *operatorList) +{ + return lcons(op, operatorList); +} + +OperatorObject * +createOperatorObject(List *operatorList) +{ + OperatorObject *new_oob = (OperatorObject *) palloc(sizeof(OperatorObject)); + new_oob->operatorList = operatorList; + return new_oob; +} + +MValue * +createOperatorObjectValue(OperatorObject *oob) +{ + MValue *vl = (MValue *) palloc(sizeof(MValue)); + vl->type = OP_OBJECT; + vl->oob = oob; + return vl; +} + +MValue * +createLeafValueValue(LeafValue *lv) +{ + MValue *vl = (MValue *) palloc(sizeof(MValue)); + vl->type = LF_VALUE; + vl->lv = lv; + return vl; +} + +Clause * +createLeafClause(char* key, MValue *vl) +{ + LeafClause *new_lc = (LeafClause *) palloc(sizeof(LeafClause)); + new_lc->type = LEAF; + new_lc->key = key; + new_lc->vl = vl; + return ( Clause* ) new_lc; +} + +Clause * +createCommentClause(char *op, char *str) +{ + CommentClause *new_com_cl = (CommentClause *) palloc(sizeof(CommentClause)); + new_com_cl->type = COMMENT; + new_com_cl->op = op; + new_com_cl->str = str; + return ( Clause* ) new_com_cl; +} + +WhereClauseValue * +stringToWhereClauseValue(char *str) +{ + WhereClauseValue *wcv = (WhereClauseValue *) palloc(sizeof(WhereClauseValue)); + wcv->str = str; + return wcv; +} + +Clause * +createWhereClause(WhereClauseValue *wcv) +{ + WhereClause *wc = (WhereClause *) palloc(sizeof(WhereClause)); + wc->type = WHERE; + wc->wcv = wcv; + return (Clause *) wc; +} + +List * +addClause(Clause *clause, List *clauseList) +{ + return lappend(clauseList, clause); +} + +Expression * +createExpression(List *clauseList) +{ + Expression *exp = (Expression *) palloc(sizeof(Expression)); + exp->clauseList = clauseList; + return exp; +} + +List * +addExpression(Expression *exp, List *expressionList) +{ + return lcons(exp, expressionList); +} + +Clause * +createExpressionTreeClause(ExpressionOperatorType opType, List *expressionList) +{ + ExpressionClause *exp_cl = (ExpressionClause *) palloc(sizeof(ExpressionClause)); + exp_cl->type = EXPRESSION; + exp_cl->op = opType; + exp_cl->expressionList = expressionList; + return (Clause *) exp_cl; +} + +Clause * +createTextClause(char *search_str, bool lang_op, char *lang_str, bool case_sense, bool diacr_sense) +{ + TextClause *text_cl = (TextClause *) palloc(sizeof(TextClause)); + text_cl->type = TEXT; + text_cl->search_str = search_str; + text_cl->lang_op = lang_op; + text_cl->lang_str = lang_str; + text_cl->case_sense = case_sense; + text_cl->diacr_sense = diacr_sense; + return (Clause *) text_cl; +} + +MQuery * +createQuery(Expression *exp) +{ + MQuery *qu = (MQuery *) palloc(sizeof(MQuery)); + qu->exp = exp; + return qu; +} \ No newline at end of file diff --git a/monq_delete_query.c b/monq_delete_query.c new file mode 100644 index 0000000..05f1d75 --- /dev/null +++ b/monq_delete_query.c @@ -0,0 +1,192 @@ +#include +#include +#include + +#include "c.h" +#include "postgres.h" +#include "access/gin.h" +#include "utils/numeric.h" + +#include "monq.h" + + +static void deleteValueOperator(ValueOperator *vop); +static void deleteOperator(Operator *op); +static void deleteNotOperator(NotOperator *op); +static void deleteElemMatchOperator(ElemMatchOperator *elemMatchOperator); +static void deleteOperatorObject(OperatorObject *op_object); +static void deleteLeafClauseValue(MValue *val); +static void deleteLeafClause(LeafClause *lc); +static void deleteExpressionClause(ExpressionClause* expClause); +static void deleteTextClause(TextClause *tClause); +static void deleteClause(Clause *cl); +static void deleteExpression(Expression * ex); +static void deleteLeafValue(LeafValue *value); +static void deleteArraySequence(MArray *ar); +static void deleteArrayOperator(ArrayOperator *aop); + + +static void +deleteValueOperator(ValueOperator *vop) +{ + deleteLeafValue(vop->value); + pfree(vop); +} + +static void +deleteOperator(Operator *operator) +{ + switch(operator->type) + { + case NOP : + deleteNotOperator((NotOperator*) operator ); + break; + case AOP : + deleteArrayOperator((ArrayOperator*) operator ); + break; + case VOP : + deleteValueOperator((ValueOperator*) operator ); + break; + case EOP : + deleteElemMatchOperator((ElemMatchOperator*) operator); + break; + case MOP : + break; + } +} + +static void +deleteElemMatchOperator(ElemMatchOperator *elemMatchOperator) +{ + switch(elemMatchOperator->typeOfValue) + { + case E_EXPRESSION: + deleteExpression(elemMatchOperator->expression); + break; + case E_OP_OBJECT: + deleteOperatorObject(elemMatchOperator->operatorOpbject); + break; + } +} + +static void +deleteNotOperator(NotOperator *op) +{ + deleteOperator(op->op); + pfree(op); +} + +static void +deleteOperatorObject(OperatorObject *op_object) +{ + List *operatorList; + ListCell *cell; + + operatorList = op_object->operatorList; + + foreach(cell, operatorList) + deleteOperator((Operator *)lfirst(cell)); + + pfree(op_object->operatorList); + pfree(op_object); +} + +static void +deleteLeafClauseValue(MValue *value) +{ + value->type ? deleteOperatorObject(value->oob) : deleteLeafValue(value->lv); +} + +static void +deleteLeafClause(LeafClause *lc) +{ + deleteLeafClauseValue(lc->vl); + pfree(lc); +} + +static void +deleteExpressionClause(ExpressionClause* expClause) +{ + List *expressionList; + ListCell *cell; + + expressionList = expClause->expressionList; + + foreach(cell, expressionList) + deleteExpression((Expression *)lfirst(cell)); + + pfree(expressionList); + pfree(expClause); +} + +static void +deleteTextClause(TextClause *textClause) +{ + pfree(textClause); +} + +static void +deleteClause(Clause *clause) +{ + switch(clause->type) + { + case LEAF : + deleteLeafClause((LeafClause*) clause); + break; + case TEXT : + deleteTextClause((TextClause*) clause); + break; + case EXPRESSION : + deleteExpressionClause((ExpressionClause*) clause); + break; + default : + break; + } +} + +static void +deleteExpression(Expression * expression) +{ + List *clauseList = expression->clauseList; + ListCell *cell; + + foreach(cell, clauseList) + deleteClause((Clause *)lfirst(cell)); + + pfree(expression); +} + +static void +deleteLeafValue(LeafValue *value) +{ + if(value->type == A) + deleteArraySequence(value->ar); + pfree(value); +} + +static void +deleteArraySequence(MArray *marray) +{ + List *arrayList = marray->arrayList; + ListCell *cell; + + foreach(cell, arrayList) + deleteLeafValue((LeafValue *)lfirst(cell)); + + pfree(arrayList); + pfree(marray); +} + +static void +deleteArrayOperator(ArrayOperator *arrayOperator) +{ + deleteArraySequence(arrayOperator->ar); + pfree(arrayOperator); +} + +void +deleteMquery(MQuery *query) +{ + deleteExpression(query->exp); + pfree(query); +} \ No newline at end of file diff --git a/monq_get_jsquery.c b/monq_get_jsquery.c new file mode 100644 index 0000000..ec40ee5 --- /dev/null +++ b/monq_get_jsquery.c @@ -0,0 +1,388 @@ +#include +#include +#include + +#include "monq.h" + + +static void getExpression(StringInfo strInfo, Expression * expression); +static void getClause(StringInfo strInfo, Clause *clause); +static void getExpressionClause(StringInfo strInfo, ExpressionClause* expClause); +static void getTextClause(StringInfo strInfo, TextClause* textClause); +static void getLeafClause(StringInfo strInfo, LeafClause *leafClause); +static void getLeafClauseValue(StringInfo strInfo, char *key, MValue *value); +static void getLeafValueEq(StringInfo strInfo, char *key, LeafValue *leafValue); +static void getOperatorObject(StringInfo strInfo, char *key, OperatorObject *opObject); +static void getOperator(StringInfo strInfo, char *key, Operator *operator); +static void getNotOperator(StringInfo strInfo, char *key, NotOperator *notOperator); +static void getElemMatchOperator(StringInfo strInfo, char *key, ElemMatchOperator *elemMatchOperator); +static void getArrayOperator(StringInfo strInfo, char *key, ArrayOperator *arOperator); +static void getArraySequence(StringInfo strInfo, MArray *marray); +static void getLeafValue(StringInfo strInfo, LeafValue *value); +static void getValueOperator(StringInfo strInfo, char *key, ValueOperator *valOperator); +static void getValueOperatorType(StringInfo strInfo, ValueOperatorType type); +static void getValueType(StringInfo strInfo, char *type); + +static void +getValueOperatorType(StringInfo strInfo, ValueOperatorType type) +{ + switch(type) + { + case _LESS : + appendStringInfo(strInfo, "<"); + break; + case _EQ : + case _NOTEQ : + appendStringInfo(strInfo, "="); + break; + case _LESSEQ : + appendStringInfo(strInfo, "<="); + break; + case _GREAT : + appendStringInfo(strInfo, ">"); + break; + case _GREATEQ : + appendStringInfo(strInfo, ">="); + break; + case _TYPE : + break; + case _SIZE : + appendStringInfo(strInfo, ".@# ="); + break; + case _EXISTS : + appendStringInfo(strInfo, "= *"); + break; + default : + elog(ERROR,"This value operator is not supported"); + break; + } +} + +/* + * Return type in jsquery format + */ +static void +getValueType(StringInfo strInfo, char *type) +{ + if(strcmp(type,"\"string\"") == 0) appendStringInfo(strInfo, " IS STRING"); + else if( + strcmp(type, "\"double\"") == 0 || + strcmp(type, "\"int\"") == 0 || + strcmp(type, "\"long\"") == 0 || + strcmp(type, "\"decimal\"") == 0 + ) appendStringInfo(strInfo, " IS NUMERIC"); + + else if(strcmp(type, "\"array\"") == 0) appendStringInfo(strInfo, " IS ARRAY"); + else if(strcmp(type, "\"object\"") == 0) appendStringInfo(strInfo, " IS OBJECT"); + else if(strcmp(type, "\"bool\"") == 0) appendStringInfo(strInfo, " IS BOOLEAN"); + else + elog(ERROR, "Jsquery is not supported MongoDB %s value type", type); +} + +static void +getValueOperator(StringInfo strInfo, char *key, ValueOperator *valOperator) +{ + if(valOperator->value_op == _EXISTS) + { + if(valOperator->value->b) + { + appendStringInfo(strInfo, "%s", key); + appendStringInfo(strInfo, " "); + getValueOperatorType(strInfo, valOperator->value_op); + } + else + { + appendStringInfo(strInfo, "NOT (%s ", key); + getValueOperatorType(strInfo, valOperator->value_op); + appendStringInfo(strInfo, ")"); + } + } + else if(valOperator->value_op == _TYPE) + { + appendStringInfo(strInfo, "%s ", key); + getValueType(strInfo, valOperator->value->str); + } + else if(valOperator->value_op == _NOTEQ) + { + appendStringInfo(strInfo, "NOT (%s ", key); + getValueOperatorType(strInfo, valOperator->value_op); + appendStringInfo(strInfo, " "); + getLeafValue(strInfo, valOperator->value); + appendStringInfo(strInfo, ")"); + } + else + { + appendStringInfo(strInfo, "%s ", key); + getValueOperatorType(strInfo, valOperator->value_op); + appendStringInfo(strInfo, " "); + getLeafValue(strInfo, valOperator->value); + } +} + +static void +getElemMatchOperator(StringInfo strInfo, char *key, ElemMatchOperator *elemMatchOperator) +{ + appendStringInfo(strInfo, "%s.#:(", key); + switch(elemMatchOperator->typeOfValue) + { + case E_EXPRESSION: + getExpression(strInfo, elemMatchOperator->expression); + break; + case E_OP_OBJECT: + getOperatorObject(strInfo, "$",elemMatchOperator->operatorOpbject); + break; + } + appendStringInfo(strInfo, ")"); +} + +static void +getOperator(StringInfo strInfo, char *key, Operator *operator) +{ + switch(operator->type) + { + case NOP : + getNotOperator(strInfo, key, (NotOperator*) operator); + break; + case MOP : + elog(ERROR, "MongoDB module operator is not supported by jsquery"); + case AOP : + getArrayOperator(strInfo, key, (ArrayOperator*) operator); + break; + case VOP : + getValueOperator(strInfo, key, (ValueOperator*) operator); + break; + case EOP : + getElemMatchOperator(strInfo, key, (ElemMatchOperator*) operator); + break; + default : + elog(ERROR, "This mongoDB operator is not supported by jsquery"); + } +} + +static void +getNotOperator(StringInfo strInfo, char *key, NotOperator *notOperator) +{ + appendStringInfo(strInfo, "NOT ("); + getOperator(strInfo, key,notOperator->op); + appendStringInfo(strInfo, ")"); +} + +static void +getOperatorObject(StringInfo strInfo, char *key, OperatorObject *opObject) +{ + ListCell *cell; + bool first = true; + + foreach(cell, opObject->operatorList) + { + if(first) + { + appendStringInfo(strInfo, "("); + getOperator(strInfo, key, (Operator *)lfirst(cell)); + appendStringInfo(strInfo, ")"); + first = false; + } + else + { + appendStringInfo(strInfo, " AND ("); + getOperator(strInfo, key, ((Operator *)lfirst(cell))); + appendStringInfo(strInfo, ")"); + } + } +} + +static void +getLeafValueEq(StringInfo strInfo, char *key, LeafValue *leafValue) +{ + appendStringInfo(strInfo, "%s = ", key); + getLeafValue(strInfo, leafValue); +} + +static void +getLeafClauseValue(StringInfo strInfo, char *key, MValue *value) +{ + if(value->type) + getOperatorObject(strInfo, key, value->oob); + else + getLeafValueEq(strInfo, key, value->lv); +} + +static void +getLeafClause(StringInfo strInfo, LeafClause *leafClause) +{ + getLeafClauseValue(strInfo, leafClause->key, leafClause->vl); +} + +static void +getExpressionClause(StringInfo strInfo, ExpressionClause* expClause) +{ + ListCell *cell; + bool first = true; + char *expOperator = NULL; + + switch(expClause->op) + { + case _AND : + expOperator = "AND"; + break; + case _OR : + expOperator = "OR"; + break; + case _NOR : + expOperator = "OR NOT"; + break; + } + + foreach(cell, expClause->expressionList) + { + if(first) + { + if(expClause->op == _NOR) appendStringInfo(strInfo, "NOT "); + + appendStringInfo(strInfo, "("); + getExpression(strInfo, (Expression *)lfirst(cell)); + appendStringInfo(strInfo, ") "); + + first = false; + } + else + { + appendStringInfo(strInfo, "%s (", expOperator); + getExpression(strInfo, (Expression *)lfirst(cell)); + appendStringInfo(strInfo, ") "); + } + } +} + +static void +getTextClause(StringInfo strInfo, TextClause *textClause) +{ + appendStringInfo(strInfo, "* = %s", textClause->search_str); +} + +static void +getClause(StringInfo strInfo, Clause *clause) +{ + switch(clause->type) + { + case LEAF : + getLeafClause(strInfo, (LeafClause*) clause); + break; + case COMMENT : + elog(ERROR, "MongoDB comment clause is not supported by jsquery"); + case TEXT : + getTextClause(strInfo, (TextClause*) clause); + break; + case WHERE : + elog(ERROR, "MongoDB where clause is not supported by jsquery"); + case EXPRESSION : + getExpressionClause(strInfo, (ExpressionClause*) clause); + break; + default: + break; + } +} + +static void +getExpression(StringInfo strInfo, Expression *expression) +{ + ListCell *cell; + bool first = true; + + foreach(cell, expression->clauseList) + { + if (first) + { + getClause(strInfo, (Clause *)lfirst(cell)); + first = false; + } + else + { + appendStringInfo(strInfo, " AND "); + getClause(strInfo, (Clause *)lfirst(cell)); + } + } +} + +static void +getLeafValue(StringInfo strInfo, LeafValue *value) +{ + switch(value->type) + { + case S : + appendStringInfo(strInfo, "%s", value->str); + break; + case I : + appendStringInfo(strInfo, "%s", value->i); + break; + case A : + appendStringInfo(strInfo, "["); + getArraySequence(strInfo, value->ar); + appendStringInfo(strInfo, "]"); + break; + case B : + appendStringInfo(strInfo, "%s", (value->b ? "true" : "false")); + break; + case D : + appendStringInfo(strInfo, "%s", value->d); + break; + default : + break; + } +} + +static void +getArraySequence(StringInfo strInfo, MArray *marray) +{ + ListCell *cell; + bool first = true; + + foreach(cell, marray->arrayList) + { + if(first) + { + getLeafValue(strInfo, (LeafValue *)lfirst(cell)); + first = false; + } + else + { + appendStringInfo(strInfo, ", "); + getLeafValue(strInfo, (LeafValue *)lfirst(cell)); + } + } +} + +static void +getArrayOperator(StringInfo strInfo, char *key, ArrayOperator *arOperator) +{ + switch(arOperator->array_op) + { + case _IN : + appendStringInfo(strInfo, "%s IN (", key); + getArraySequence(strInfo, arOperator->ar); + appendStringInfo(strInfo, ")"); + break; + case _NIN: + appendStringInfo(strInfo, "NOT (%s IN (", key); + getArraySequence(strInfo, arOperator->ar); + appendStringInfo(strInfo, "))"); + break; + case _ALL: + appendStringInfo(strInfo, "%s @> [", key); + getArraySequence(strInfo, arOperator->ar); + appendStringInfo(strInfo, "]"); + break; + default : + break; + } +} + +char * +getJsquery(MQuery *qu) +{ + StringInfoData strInfo; + initStringInfo(&strInfo); + getExpression(&strInfo, qu->exp); + deleteMquery(qu); + return strInfo.data; +} \ No newline at end of file diff --git a/monq_gram.y b/monq_gram.y new file mode 100644 index 0000000..abc0858 --- /dev/null +++ b/monq_gram.y @@ -0,0 +1,244 @@ +%{ + #include + #include + #include + + #include "monq.h" + + MQuery *RET; + + typedef struct yy_buffer_state *YY_BUFFER_STATE; + extern int yylex(); + extern void yyerror(char *s); + extern int yyparse(); + extern YY_BUFFER_STATE yy_scan_string(char * str); + extern void yy_delete_buffer(YY_BUFFER_STATE buffer); + + void + yyerror(char *s) + { + elog(ERROR,"%s",s); + exit(0); + } + + MQuery* + parse(char *str) + { + YY_BUFFER_STATE buffer = yy_scan_string(str); + + yyparse(); + yy_delete_buffer(buffer); + + return RET; + } +%} + +/* Types of query tree nodes and leafs */ +%union +{ + MQuery *mquery; + Expression *exp; + Clause *cl; + MValue *vl; + LeafValue *lv; + List *list; + WhereClauseValue *wcv; + char *strval; + int intval; + double dubval; + MArray *arrval; + bool boolval; + ArrayOperatorType aop_type; + ExpressionOperatorType exop_type; + ValueOperatorType valop_type; + OperatorObject *oob; + Operator *op; + ElemMatchOperator *elemMatchOp; +} + +%type QUERY +%type EXPRESSION +%type CLAUSE TEXT_CLAUSE EXPRESSION_TREE_CLAUSE LEAF_CLAUSE COMMENT_CLAUSE WHERE_CLAUSE +%type VALUE + +%type KEY KEY_STRING +%type OPERATOR +%type OPEARATOR_OBJECT + +%type LSCOPE RSCOPE COMMA + +%type OPERATOR_LIST LEAF_VALUE_LIST EXPRESSION_LIST CLAUSE_LIST + +%type WHERE_CLAUSE_VALUE +%type WHERE_OPERATOR +%token WHERE_OPERATOR + +/* OPERATORS */ + +/* Tree clause */ +%type TREE_OPERATOR OR NOR AND +%token OR NOR AND + +/* Leaf value operator */ +%type EQ LESS GREAT LESSEQ GREATEQ NOTEQ TYPE SIZE EXISTS NOT VALUE_OPERATOR +%token EQ NOTEQ LESS LESSEQ GREAT GREATEQ TYPE SIZE EXISTS NOT + +/* Array operator */ +%type IN NIN ALL ARRAY_OPERATOR +%token IN NIN ALL + +/* Mod operator */ +%type MOD_OPERATOR +%type DIVISOR REMAINDER +%token MOD_OPERATOR + +/* ElemMatch operator */ +%type ELEMMATCH_OPERATOR +%type ELEMMATCH +%token ELEMMATCH + +/* Comment clause */ +%type COMMENT_OPERATOR +%token COMMENT_OPERATOR + +/* Text clause */ +%type DIACRITIC_SENSITIVE_OPERATOR CASE_SENSITIVE_OPERATOR LANGUAGE_OPERATOR SEARCH_OPERATOR TEXT_OPERATOR +%token DIACRITIC_SENSITIVE_OPERATOR CASE_SENSITIVE_OPERATOR LANGUAGE_OPERATOR SEARCH_OPERATOR TEXT_OPERATOR + +/* Type of values */ +%type LEAF_VALUE +%type INT +%type STRING +%type DOUBLE +%type ARRAY +%type BOOLEAN +%token INT STRING DOUBLE BOOLEAN KEY_STRING + +/* Scope types */ +%token LSCOPE RSCOPE COMMA LSQBRACKET RSQBRACKET LRBRACKET RRBRACKET + +%start QUERY + +%% +QUERY : EXPRESSION {$$ = createQuery($1); RET=$$; } + ; + +EXPRESSION : LSCOPE CLAUSE_LIST RSCOPE { $$ = createExpression($2); } + ; + +CLAUSE_LIST : CLAUSE COMMA CLAUSE_LIST { $$ = addClause($1, $3); } + | CLAUSE { $$ = lappend(NULL, $1); } + ; + +CLAUSE : LEAF_CLAUSE + | COMMENT_CLAUSE + | WHERE_CLAUSE + | EXPRESSION_TREE_CLAUSE + | TEXT_CLAUSE + ; + + +/* TEXT CLAUSE SECTION */ + +TEXT_CLAUSE : LSCOPE TEXT_OPERATOR EQ LSCOPE SEARCH_OPERATOR EQ KEY + RSCOPE RSCOPE { $$ = createTextClause($7, false, "", false, false); } + | LSCOPE TEXT_OPERATOR EQ LSCOPE SEARCH_OPERATOR EQ KEY COMMA + LANGUAGE_OPERATOR EQ STRING COMMA + CASE_SENSITIVE_OPERATOR EQ BOOLEAN COMMA + DIACRITIC_SENSITIVE_OPERATOR EQ BOOLEAN RSCOPE RSCOPE { $$ = createTextClause($7, false, $11, $15, $19); } + ; + +/* END OF SECTION */ + +/*WHERE CLAUSE SECTION*/ + +WHERE_CLAUSE : LSCOPE WHERE_OPERATOR EQ WHERE_CLAUSE_VALUE RSCOPE { $$ = createWhereClause($4); } + ; + +WHERE_CLAUSE_VALUE : KEY { $$ = stringToWhereClauseValue($1); } + ; +/* END OF SECTION */ + +/*COMMENT CLAUSE SECTION*/ +COMMENT_CLAUSE : LSCOPE COMMENT_OPERATOR EQ STRING RSCOPE { $$ = createCommentClause($2, $4); } + ; +/* END OF SECTION */ + +/*TREE CLAUSE SECTION*/ + +EXPRESSION_TREE_CLAUSE : TREE_OPERATOR EQ LSQBRACKET EXPRESSION_LIST RSQBRACKET { $$ = createExpressionTreeClause($1, $4); } + | LSCOPE EXPRESSION_TREE_CLAUSE RSCOPE { $$ = $2; } + ; + +EXPRESSION_LIST : EXPRESSION { $$ = lcons($1, NULL); } + | EXPRESSION COMMA EXPRESSION_LIST { $$ = addExpression($1, $3); } + ; + +TREE_OPERATOR : OR | AND | NOR ; + +/* END OF SECTION */ + +/* LEAF CLAUSE SECTION */ +LEAF_CLAUSE : KEY EQ VALUE { $$ = createLeafClause($1, $3); } + ; + +KEY : STRING + | KEY_STRING + ; + +VALUE : LEAF_VALUE { $$ = createLeafValueValue($1); } + | OPEARATOR_OBJECT { $$ = createOperatorObjectValue($1); } + ; + +OPEARATOR_OBJECT : LSCOPE OPERATOR_LIST RSCOPE { $$ = createOperatorObject($2); } + ; + +OPERATOR_LIST : OPERATOR { $$ = lappend(NULL, $1); } + | OPERATOR COMMA OPERATOR_LIST { $$ = addOperator($1, $3); } + ; + +OPERATOR : VALUE_OPERATOR EQ LEAF_VALUE { $$ = createValueOperator($1, $3); } + | ARRAY_OPERATOR EQ ARRAY { $$ = createArrayOperator($1, $3); } + | MOD_OPERATOR EQ LSQBRACKET DIVISOR COMMA REMAINDER RSQBRACKET { $$ = createModOperator($4, $6); } + | NOT EQ LSCOPE OPERATOR RSCOPE { $$ = createNotOperator($4); } + | ELEMMATCH EQ ELEMMATCH_OPERATOR { $$ = $3; } + ; + +VALUE_OPERATOR : EQ | NOTEQ | LESS | LESSEQ | GREAT | GREATEQ | TYPE | SIZE | EXISTS + ; + +ELEMMATCH_OPERATOR : OPEARATOR_OBJECT { $$ = createElemMatchOperatorOpObject($1); } + | EXPRESSION { $$ = createElemMatchOperatorExpression($1); } + ; + +DIVISOR : LEAF_VALUE + ; + +REMAINDER : LEAF_VALUE + ; + +ARRAY : LSQBRACKET LEAF_VALUE_LIST RSQBRACKET {$$ = createNewArray($2); } + ; + +ARRAY_OPERATOR : IN | NIN | ALL + ; + +LEAF_VALUE_LIST : LEAF_VALUE { $$ = lcons($1, NULL); } + | LEAF_VALUE COMMA LEAF_VALUE_LIST { $$ = addArrayElement($1, $3); } + ; + +LEAF_VALUE : INT { $$ = createIntegerValue($1); } + | STRING { $$ = createStringValue($1); } + | KEY_STRING { + StringInfoData strf; + initStringInfo(&strf); + appendStringInfo(&strf, "\"%s\"", $1); + $$ = createStringValue(strf.data); + } + | DOUBLE { $$ = createDoubleValue($1); } + | ARRAY { $$ = createArrayValue($1); } + | BOOLEAN { $$ = createBooleanValue($1); } + ; + +/* END OF SECTION */ +%% \ No newline at end of file diff --git a/monq_scan.l b/monq_scan.l new file mode 100644 index 0000000..6ed1114 --- /dev/null +++ b/monq_scan.l @@ -0,0 +1,96 @@ +%{ + #include + #include + #include "monq_structures.h" + #include "monq_gram.h" + #include + + + extern int yylex(); + +%} + +%option yylineno +%option noyywrap +%option nounput +%option noinput + +%% + +[/][/].*\n ; // comment + +[0-9]+ { yylval.strval=strdup(yytext); return INT; } +[0-9]+\.[0-9]+ { yylval.strval=strdup(yytext); return DOUBLE; } +(true|false|TRUE|FALSE) { yylval.boolval=(strcmp(strdup(yytext),"true")==0); return BOOLEAN; } + +\{ { return LSCOPE; } +\} { return RSCOPE; } +\[ { return LSQBRACKET; } +\] { return RSQBRACKET; } + +\, { return COMMA; } + +\: { yylval.valop_type=_EQ; return EQ; } +\$(eq|EQ) { yylval.valop_type=_EQ; return EQ; } +\$(lt|LT) { yylval.valop_type=_LESS; return LESS; } +\$(lte|LTE) { yylval.valop_type=_LESSEQ; return LESSEQ; } +\$(gt|GT) { yylval.valop_type=_GREAT; return GREAT; } +\$(gte|GTE) { yylval.valop_type=_GREATEQ; return GREATEQ; } +\$(ne|NE) { yylval.valop_type=_NOTEQ; return NOTEQ; } +\$type { yylval.valop_type=_TYPE; return TYPE; } +\$size { yylval.valop_type=_SIZE; return SIZE; } +\$exists { yylval.valop_type=_EXISTS; return EXISTS; } + +\$in { yylval.aop_type=_IN; return IN; } +\$nin { yylval.aop_type=_NIN; return NIN; } +\$all { yylval.aop_type=_ALL; return ALL; } + +\$not { return NOT;} + +\$where { return WHERE_OPERATOR; } + +\$elemMatch { return ELEMMATCH; } + +\$or { yylval.exop_type=_OR; return OR; } +\$nor { yylval.exop_type=_NOR; return NOR; } +\$and { yylval.exop_type=_AND; return AND; } + +\$search { return SEARCH_OPERATOR; } +\$text { return TEXT_OPERATOR; } +\$language { return LANGUAGE_OPERATOR; } +\$caseSensitive { return CASE_SENSITIVE_OPERATOR; } +\$diacriticSensitive { return DIACRITIC_SENSITIVE_OPERATOR; } + +\$comment { return COMMENT_OPERATOR; } + +\$mod { return MOD_OPERATOR; } + +\"\" { yylval.strval=strdup(yytext); return STRING; } + +[0-9a-zA-Z]+ { yylval.strval=strdup(yytext); return KEY_STRING; } + +\"[\.0-9a-zA-Z]*\" { + char *str = strdup(yytext+1); + str[yyleng-2] = '\0'; + yylval.strval = str; + return KEY_STRING; + } + +\"[(\\0)\.\, 0-9a-zA-Z]*\" { yylval.strval=strdup(yytext); return STRING; } + +[ \t\r\n] ; // whitespace + + +%% + +/*MQuery* +parsemquery(const char *str, int len) +{ + YY_BUFFER_STATE buffer = yy_scan_string(str); + + yyparse(); + yy_delete_buffer(buffer); + + return RET; +} +*/ diff --git a/sql/jsquery.sql b/sql/jsquery.sql index f4f461c..117dbe8 100644 --- a/sql/jsquery.sql +++ b/sql/jsquery.sql @@ -543,4 +543,24 @@ select v from test_jsquery where v @@ 'array && [2,3]' order by v; select v from test_jsquery where v @@ 'array @> [2,3]' order by v; select v from test_jsquery where v @@ 'array = [2,3]' order by v; +---MongoDB query translator tests +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : 1 }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $eq : 1 } }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $ne : 1 } }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $lt : 1 } }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $lte : 1 } }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $gt : 1 } }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $gte : 1 } }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $in : [2,3] } }'); +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $nin : [2,3] } }'); + +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : false } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : true } }'); + +select parse_mquery('{ is : { $lt: 1 } }')::jsquery; + +select v from test_jsquery where v @@ parse_mquery('{ array : { $all: [2,3] } }') order by v; + +select v from test_jsquery where v @@ parse_mquery('{ { $text: { $search: "Flew" } } }'); + RESET enable_seqscan; From 7757b7a2cbbb813f584f53feeeeb4de66d624dcb Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Mon, 17 Jul 2017 02:54:06 +0300 Subject: [PATCH 02/15] Update README.md --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 4a019b4..311fd58 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,27 @@ correspondingly. ---------------------------- y > 0 , entry 0 + +### parse\_mquery +This function is transofrm MongoDB query to JsQuery query. Function get string +like argument and return jsquery object. +Example: +MongoDB query: +``` +select '{"a": {"b": 1 } }'::jsonb @@ parse_mquery('{ "a.b" : { $lte : 1 } }'); +``` +Transformed to: +``` +select '{"a": {"b": 1 } }'::jsonb @@ 'a.b = 1'; +``` +And return: +``` +select '{"a": {"b": 1 } }'::jsonb @@ 'a.b = 1'; + ?column? +---------- + t +(1 row) +``` + Contribution ------------ From a2f116a7335e831602f23765fce4c91439ea39e8 Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Mon, 17 Jul 2017 03:24:35 +0300 Subject: [PATCH 03/15] New tests for parse_mquery --- expected/jsquery.out | 303 +++++++++++++++++++++++++++++++++++++++++++ sql/jsquery.sql | 65 ++++++++++ 2 files changed, 368 insertions(+) diff --git a/expected/jsquery.out b/expected/jsquery.out index a5d4655..dda85bb 100644 --- a/expected/jsquery.out +++ b/expected/jsquery.out @@ -2999,4 +2999,307 @@ select v from test_jsquery where v @@ parse_mquery('{ { $text: { $search: "Flew" --- (0 rows) +select '{ "a" : "ssl" }'::jsonb @@ parse_mquery('{ a: { $in: [ "ssl","security"] } }'); + ?column? +---------- + t +(1 row) + +select '{ "a" : 1 }'::jsonb @@ parse_mquery('{ a: { $in: [ "ssl","security"] } }'); + ?column? +---------- + f +(1 row) + +select '{ "a" : "ssl" }'::jsonb @@ parse_mquery('{ a: { $nin: [ "ssl","security"] } }'); + ?column? +---------- + f +(1 row) + +select '{ "a" : "sslqwerty" }'::jsonb @@ parse_mquery('{ a: { $nin: [ "ssl","security"] } }'); + ?column? +---------- + t +(1 row) + +select '{ "a" : [ "ssl","security"] }'::jsonb @@ parse_mquery('{ a: { $size: 2 } }'); + ?column? +---------- + t +(1 row) + +select '{ "a" : [ "ssl","security"] }'::jsonb @@ parse_mquery('{ a: { $size: 1 } }'); + ?column? +---------- + f +(1 row) + +select '{ "a" : [ "ssl","security", "pattern"] }'::jsonb @@ parse_mquery('{ a: { $all: [ "ssl","security"] } }'); + ?column? +---------- + t +(1 row) + +select '{ "a" : [ "ssl","pattern"] }'::jsonb @@ parse_mquery('{ a: { $all: [ "ssl","security"] } }'); + ?column? +---------- + f +(1 row) + +select '{ "a" : [ "ssl","security"] }'::jsonb @@ parse_mquery('{ a: { $all: [ "ssl","security"] } }'); + ?column? +---------- + t +(1 row) + +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : false } }'); + ?column? +---------- + f +(1 row) + +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : true } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : false } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : true } }'); + ?column? +---------- + f +(1 row) + +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "int" } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : "qwerttyu" }'::jsonb @@ parse_mquery('{ b: { $type: "int" } }'); + ?column? +---------- + f +(1 row) + +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "long" } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : "qwerttyu" }'::jsonb @@ parse_mquery('{ b: { $type: "long" } }'); + ?column? +---------- + f +(1 row) + +select '{ "b" : true }'::jsonb @@ parse_mquery('{ b: { $type: "bool" } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : "fklgjlksdfgsldflsgjslkrjekfjkl" }'::jsonb @@ parse_mquery('{ b: { $type: "bool" } }'); + ?column? +---------- + f +(1 row) + +select '{ "b" : "fklgjlksdfgsldflsgjslkrjekfjkl" }'::jsonb @@ parse_mquery('{ b: { $type: "array" } }'); + ?column? +---------- + f +(1 row) + +select '{ "b" : [1, 4] }'::jsonb @@ parse_mquery('{ b: { $type: "array" } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : "fklgjlksdfgsldflsgjslkrjekfjkl" }'::jsonb @@ parse_mquery('{ b: { $type: "string" } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : [1, 4] }'::jsonb @@ parse_mquery('{ b: { $type: "string" } }'); + ?column? +---------- + f +(1 row) + +select '{ "b" : 2.23432 }'::jsonb @@ parse_mquery('{ b: { $type: "double" } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "double" } }'); + ?column? +---------- + t +(1 row) + +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "decimal" } }'); + ?column? +---------- + t +(1 row) + +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "maxKey" } }'); +ERROR: Jsquery is not supported MongoDB "maxKey" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "binData" } }'); +ERROR: Jsquery is not supported MongoDB "binData" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "objectId" } }'); +ERROR: Jsquery is not supported MongoDB "objectId" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "javascript" } }'); +ERROR: Jsquery is not supported MongoDB "javascript" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "symbol" } }'); +ERROR: Jsquery is not supported MongoDB "symbol" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "javascriptWithScope" } }'); +ERROR: Jsquery is not supported MongoDB "javascriptWithScope" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "timestamp" } }'); +ERROR: Jsquery is not supported MongoDB "timestamp" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "minKey" } }'); +ERROR: Jsquery is not supported MongoDB "minKey" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "regex" } }'); +ERROR: Jsquery is not supported MongoDB "regex" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "null" } }'); +ERROR: Jsquery is not supported MongoDB "null" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "date" } }'); +ERROR: Jsquery is not supported MongoDB "date" value type +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "undefined" } }'); +ERROR: Jsquery is not supported MongoDB "undefined" value type +/* Or operator */ +select '{ "quantity" : 2, "price" : 10 }'::jsonb @@ parse_mquery('{ $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); + ?column? +---------- + t +(1 row) + +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); + ?column? +---------- + t +(1 row) + +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $or: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); + ?column? +---------- + f +(1 row) + +/* Nor operator */ +select '{ "quantity" : 2, "price" : 10 }'::jsonb @@ parse_mquery('{ $nor: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); + ?column? +---------- + f +(1 row) + +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $nor: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); + ?column? +---------- + t +(1 row) + +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $nor: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); + ?column? +---------- + t +(1 row) + +/* And operator */ +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $and: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); + ?column? +---------- + f +(1 row) + +select '{ "quantity" : 5, "price" : 100 }'::jsonb @@ parse_mquery('{ $and: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); + ?column? +---------- + t +(1 row) + +/* Not operator */ +select '{ "quantity" : 5, "price" : 100 }'::jsonb @@ parse_mquery('{ price: { $not: { $gt: 1.99 } } }'); + ?column? +---------- + f +(1 row) + +select '{ "quantity" : 5, "price" : 1 }'::jsonb @@ parse_mquery('{ price: { $not: { $gt: 1.99 } } }'); + ?column? +---------- + t +(1 row) + +/* Mod operator */ +select '{ "quantity" : 2, "price" : 10 }'::jsonb @@ parse_mquery('{ qty: { $mod: [ 4, 0 ] } } '); +ERROR: MongoDB module operator is not supported by jsquery +select '{"a": 5}'::jsonb @@ parse_mquery('{ a: { $eq: 5 } }'); + ?column? +---------- + t +(1 row) + +select '{"a": 5}'::jsonb @@ parse_mquery('{ a: { $eq: 6 } }'); + ?column? +---------- + f +(1 row) + +select '{ "quantity" : "qw", "price" : 10 }'::jsonb @@ parse_mquery('{ { $where: "qw"} }'); +ERROR: MongoDB where clause is not supported by jsquery +select '{ "quantity" : "qw", "price" : 10 }'::jsonb @@ parse_mquery('{ { $text: { $search: "qsddjkhjw" } } }'); + ?column? +---------- + f +(1 row) + +select '{ "quantity" : "qw", "price" : 10 }'::jsonb @@ parse_mquery('{ { $text: { $search: "qw" } } }'); + ?column? +---------- + t +(1 row) + +select '{"a": { "qwerty" : 5} }'::jsonb @@ parse_mquery('{ "a.qwerty" : { $eq: 6 } }'); + ?column? +---------- + f +(1 row) + +select '{"a": { "qwerty" : { "asdfgh" : { "fgfhg" : 5 } } } }'::jsonb @@ parse_mquery('{ "a.qwerty.asdfgh.fgfhg" : { $eq: 5 } }'); + ?column? +---------- + t +(1 row) + +select '{ "_id" : 3, "results" : [ { "product" : "abc", "score" : 7 }, { "product" : "abc", "score" : 8 } ] }' @@ parse_mquery('{ results: { $elemMatch: { product: "abc" } } }'); + ?column? +---------- + t +(1 row) + +select '{ "_id" : 3, "results" : [ 81, 84, 83] }' @@ parse_mquery('{ results: { $elemMatch: { $gte: 80, $lt: 85 } } }'); + ?column? +---------- + t +(1 row) + +select '{ "_id" : 3, "results" : [ 81, 86, 83] }' @@ parse_mquery('{ results: { $elemMatch: { $gte: 80, $lt: 85 } } }'); + ?column? +---------- + f +(1 row) + RESET enable_seqscan; diff --git a/sql/jsquery.sql b/sql/jsquery.sql index 117dbe8..3e178c0 100644 --- a/sql/jsquery.sql +++ b/sql/jsquery.sql @@ -563,4 +563,69 @@ select v from test_jsquery where v @@ parse_mquery('{ array : { $all: [2,3] } }' select v from test_jsquery where v @@ parse_mquery('{ { $text: { $search: "Flew" } } }'); +select '{ "a" : "ssl" }'::jsonb @@ parse_mquery('{ a: { $in: [ "ssl","security"] } }'); +select '{ "a" : 1 }'::jsonb @@ parse_mquery('{ a: { $in: [ "ssl","security"] } }'); +select '{ "a" : "ssl" }'::jsonb @@ parse_mquery('{ a: { $nin: [ "ssl","security"] } }'); +select '{ "a" : "sslqwerty" }'::jsonb @@ parse_mquery('{ a: { $nin: [ "ssl","security"] } }'); +select '{ "a" : [ "ssl","security"] }'::jsonb @@ parse_mquery('{ a: { $size: 2 } }'); +select '{ "a" : [ "ssl","security"] }'::jsonb @@ parse_mquery('{ a: { $size: 1 } }'); +select '{ "a" : [ "ssl","security", "pattern"] }'::jsonb @@ parse_mquery('{ a: { $all: [ "ssl","security"] } }'); +select '{ "a" : [ "ssl","pattern"] }'::jsonb @@ parse_mquery('{ a: { $all: [ "ssl","security"] } }'); +select '{ "a" : [ "ssl","security"] }'::jsonb @@ parse_mquery('{ a: { $all: [ "ssl","security"] } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : false } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : true } }'); +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : false } }'); +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ a : { $exists : true } }'); +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "int" } }'); +select '{ "b" : "qwerttyu" }'::jsonb @@ parse_mquery('{ b: { $type: "int" } }'); +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "long" } }'); +select '{ "b" : "qwerttyu" }'::jsonb @@ parse_mquery('{ b: { $type: "long" } }'); +select '{ "b" : true }'::jsonb @@ parse_mquery('{ b: { $type: "bool" } }'); +select '{ "b" : "fklgjlksdfgsldflsgjslkrjekfjkl" }'::jsonb @@ parse_mquery('{ b: { $type: "bool" } }'); +select '{ "b" : "fklgjlksdfgsldflsgjslkrjekfjkl" }'::jsonb @@ parse_mquery('{ b: { $type: "array" } }'); +select '{ "b" : [1, 4] }'::jsonb @@ parse_mquery('{ b: { $type: "array" } }'); +select '{ "b" : "fklgjlksdfgsldflsgjslkrjekfjkl" }'::jsonb @@ parse_mquery('{ b: { $type: "string" } }'); +select '{ "b" : [1, 4] }'::jsonb @@ parse_mquery('{ b: { $type: "string" } }'); +select '{ "b" : 2.23432 }'::jsonb @@ parse_mquery('{ b: { $type: "double" } }'); +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "double" } }'); +select '{ "b" : 2 }'::jsonb @@ parse_mquery('{ b: { $type: "decimal" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "maxKey" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "binData" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "objectId" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "javascript" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "symbol" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "javascriptWithScope" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "timestamp" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "minKey" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "regex" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "null" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "date" } }'); +select '{ "a" : 2 }'::jsonb @@ parse_mquery('{ y: { $type: "undefined" } }'); +/* Or operator */ +select '{ "quantity" : 2, "price" : 10 }'::jsonb @@ parse_mquery('{ $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $or: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); +/* Nor operator */ +select '{ "quantity" : 2, "price" : 10 }'::jsonb @@ parse_mquery('{ $nor: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $nor: [ { quantity: { $lt: 20 } }, { price: 10 } ] }'); +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $nor: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); +/* And operator */ +select '{ "quantity" : 200, "price" : 10 }'::jsonb @@ parse_mquery('{ $and: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); +select '{ "quantity" : 5, "price" : 100 }'::jsonb @@ parse_mquery('{ $and: [ { quantity: { $lt: 20 } }, { price: 100 } ] }'); +/* Not operator */ +select '{ "quantity" : 5, "price" : 100 }'::jsonb @@ parse_mquery('{ price: { $not: { $gt: 1.99 } } }'); +select '{ "quantity" : 5, "price" : 1 }'::jsonb @@ parse_mquery('{ price: { $not: { $gt: 1.99 } } }'); +/* Mod operator */ +select '{ "quantity" : 2, "price" : 10 }'::jsonb @@ parse_mquery('{ qty: { $mod: [ 4, 0 ] } } '); +select '{"a": 5}'::jsonb @@ parse_mquery('{ a: { $eq: 5 } }'); +select '{"a": 5}'::jsonb @@ parse_mquery('{ a: { $eq: 6 } }'); +select '{ "quantity" : "qw", "price" : 10 }'::jsonb @@ parse_mquery('{ { $where: "qw"} }'); +select '{ "quantity" : "qw", "price" : 10 }'::jsonb @@ parse_mquery('{ { $text: { $search: "qsddjkhjw" } } }'); +select '{ "quantity" : "qw", "price" : 10 }'::jsonb @@ parse_mquery('{ { $text: { $search: "qw" } } }'); +select '{"a": { "qwerty" : 5} }'::jsonb @@ parse_mquery('{ "a.qwerty" : { $eq: 6 } }'); +select '{"a": { "qwerty" : { "asdfgh" : { "fgfhg" : 5 } } } }'::jsonb @@ parse_mquery('{ "a.qwerty.asdfgh.fgfhg" : { $eq: 5 } }'); +select '{ "_id" : 3, "results" : [ { "product" : "abc", "score" : 7 }, { "product" : "abc", "score" : 8 } ] }' @@ parse_mquery('{ results: { $elemMatch: { product: "abc" } } }'); +select '{ "_id" : 3, "results" : [ 81, 84, 83] }' @@ parse_mquery('{ results: { $elemMatch: { $gte: 80, $lt: 85 } } }'); +select '{ "_id" : 3, "results" : [ 81, 86, 83] }' @@ parse_mquery('{ results: { $elemMatch: { $gte: 80, $lt: 85 } } }'); + RESET enable_seqscan; From 9edc9f4adaf3ae9a95525082173ed3d0d742ab73 Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 02:49:43 +0300 Subject: [PATCH 04/15] Version 1.1 --- jsquery--1.0.sql => jsquery--1.1.sql | 5 +++++ jsquery.control | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) rename jsquery--1.0.sql => jsquery--1.1.sql (98%) diff --git a/jsquery--1.0.sql b/jsquery--1.1.sql similarity index 98% rename from jsquery--1.0.sql rename to jsquery--1.1.sql index 3bf1d9b..0141bb4 100644 --- a/jsquery--1.0.sql +++ b/jsquery--1.1.sql @@ -291,3 +291,8 @@ CREATE OR REPLACE FUNCTION gin_debug_query_path_value(jsquery) RETURNS text AS 'MODULE_PATHNAME' LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION parse_mquery(cstring) + RETURNS jsquery + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; diff --git a/jsquery.control b/jsquery.control index 94510c8..d95ba24 100644 --- a/jsquery.control +++ b/jsquery.control @@ -1,6 +1,6 @@ # jsquery extension comment = 'data type for jsonb inspection' -default_version = '1.0' +default_version = '1.1' module_pathname = '$libdir/jsquery' relocatable = true From 3073f3d539597a3b6a628c9779b73bd561589598 Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 13:53:40 +0300 Subject: [PATCH 05/15] Migration script --- jsquery--1.0--1.1.sql | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 jsquery--1.0--1.1.sql diff --git a/jsquery--1.0--1.1.sql b/jsquery--1.0--1.1.sql new file mode 100644 index 0000000..f0d60b7 --- /dev/null +++ b/jsquery--1.0--1.1.sql @@ -0,0 +1,7 @@ +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION jsquery UPDATE TO '1.1'" to load this file. \quit + +CREATE OR REPLACE FUNCTION parse_mquery(cstring) + RETURNS jsquery + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; \ No newline at end of file From 51a2a78faf243f3cabe79d2b48b046b6f721acdc Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 13:56:21 +0300 Subject: [PATCH 06/15] Remove old files --- jsquery--1.0.1.sql | 298 --------------------------------------------- 1 file changed, 298 deletions(-) delete mode 100644 jsquery--1.0.1.sql diff --git a/jsquery--1.0.1.sql b/jsquery--1.0.1.sql deleted file mode 100644 index 0141bb4..0000000 --- a/jsquery--1.0.1.sql +++ /dev/null @@ -1,298 +0,0 @@ --- complain if script is sourced in psql, rather than via CREATE EXTENSION -\echo Use "CREATE EXTENSION jsquery" to load this file. \quit - -CREATE TYPE jsquery; - -CREATE FUNCTION jsquery_in(cstring) - RETURNS jsquery - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE FUNCTION jsquery_out(jsquery) - RETURNS cstring - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE TYPE jsquery ( - INTERNALLENGTH = -1, - INPUT = jsquery_in, - OUTPUT = jsquery_out, - STORAGE = extended -); - -CREATE FUNCTION jsquery_json_exec(jsquery, jsonb) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE FUNCTION json_jsquery_exec(jsonb, jsquery) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR @@ ( - LEFTARG = jsquery, - RIGHTARG = jsonb, - PROCEDURE = jsquery_json_exec, - COMMUTATOR = '@@', - RESTRICT = contsel, - JOIN = contjoinsel -); - -CREATE OPERATOR @@ ( - LEFTARG = jsonb, - RIGHTARG = jsquery, - PROCEDURE = json_jsquery_exec, - COMMUTATOR = '@@', - RESTRICT = contsel, - JOIN = contjoinsel -); - -CREATE FUNCTION jsquery_join_and(jsquery, jsquery) - RETURNS jsquery - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR & ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_join_and, - COMMUTATOR = '&' -); - -CREATE FUNCTION jsquery_join_or(jsquery, jsquery) - RETURNS jsquery - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR | ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_join_or, - COMMUTATOR = '|' -); - -CREATE FUNCTION jsquery_not(jsquery) - RETURNS jsquery - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR ! ( - RIGHTARG = jsquery, - PROCEDURE = jsquery_not -); - -CREATE FUNCTION jsquery_lt(jsquery, jsquery) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE FUNCTION jsquery_le(jsquery, jsquery) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE FUNCTION jsquery_eq(jsquery, jsquery) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE FUNCTION jsquery_ne(jsquery, jsquery) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE FUNCTION jsquery_ge(jsquery, jsquery) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE FUNCTION jsquery_gt(jsquery, jsquery) - RETURNS bool - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR < ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_lt, - COMMUTATOR = '>', - NEGATOR = '>=', - RESTRICT = scalarltsel, - JOIN = scalarltjoinsel -); - -CREATE OPERATOR <= ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_le, - COMMUTATOR = '>=', - NEGATOR = '>', - RESTRICT = scalarltsel, - JOIN = scalarltjoinsel -); - -CREATE OPERATOR = ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_eq, - COMMUTATOR = '=', - NEGATOR = '<>', - RESTRICT = eqsel, - JOIN = eqjoinsel, - HASHES, - MERGES -); - -CREATE OPERATOR <> ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_eq, - COMMUTATOR = '<>', - NEGATOR = '=', - RESTRICT = neqsel, - JOIN = neqjoinsel -); - -CREATE OPERATOR >= ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_ge, - COMMUTATOR = '<=', - NEGATOR = '<', - RESTRICT = scalargtsel, - JOIN = scalargtjoinsel -); - -CREATE OPERATOR > ( - LEFTARG = jsquery, - RIGHTARG = jsquery, - PROCEDURE = jsquery_ge, - COMMUTATOR = '<', - NEGATOR = '<=', - RESTRICT = scalargtsel, - JOIN = scalargtjoinsel -); - -CREATE FUNCTION jsquery_cmp(jsquery, jsquery) - RETURNS int4 - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR CLASS jsquery_ops - DEFAULT FOR TYPE jsquery USING btree AS - OPERATOR 1 < , - OPERATOR 2 <= , - OPERATOR 3 = , - OPERATOR 4 >= , - OPERATOR 5 >, - FUNCTION 1 jsquery_cmp(jsquery, jsquery); - -CREATE FUNCTION jsquery_hash(jsquery) - RETURNS int4 - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR CLASS jsquery_ops - DEFAULT FOR TYPE jsquery USING hash AS - OPERATOR 1 =, - FUNCTION 1 jsquery_hash(jsquery); - -CREATE OR REPLACE FUNCTION gin_compare_jsonb_value_path(bytea, bytea) - RETURNS integer - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_compare_partial_jsonb_value_path(bytea, bytea, smallint, internal) - RETURNS integer - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_extract_jsonb_value_path(internal, internal, internal) - RETURNS internal - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_extract_jsonb_query_value_path(anyarray, internal, smallint, internal, internal, internal, internal) - RETURNS internal - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_consistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal, internal) - RETURNS boolean - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_triconsistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal) - RETURNS boolean - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR CLASS jsonb_value_path_ops - FOR TYPE jsonb USING gin AS - OPERATOR 7 @>, - OPERATOR 14 @@ (jsonb, jsquery), - FUNCTION 1 gin_compare_jsonb_value_path(bytea, bytea), - FUNCTION 2 gin_extract_jsonb_value_path(internal, internal, internal), - FUNCTION 3 gin_extract_jsonb_query_value_path(anyarray, internal, smallint, internal, internal, internal, internal), - FUNCTION 4 gin_consistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal, internal), - FUNCTION 5 gin_compare_partial_jsonb_value_path(bytea, bytea, smallint, internal), - FUNCTION 6 gin_triconsistent_jsonb_value_path(internal, smallint, anyarray, integer, internal, internal, internal), - STORAGE bytea; - -CREATE OR REPLACE FUNCTION gin_compare_jsonb_path_value(bytea, bytea) - RETURNS integer - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_compare_partial_jsonb_path_value(bytea, bytea, smallint, internal) - RETURNS integer - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_extract_jsonb_path_value(internal, internal, internal) - RETURNS internal - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_extract_jsonb_query_path_value(anyarray, internal, smallint, internal, internal, internal, internal) - RETURNS internal - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_consistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal, internal) - RETURNS boolean - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_triconsistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal) - RETURNS boolean - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OPERATOR CLASS jsonb_path_value_ops - FOR TYPE jsonb USING gin AS - OPERATOR 7 @>, - OPERATOR 14 @@ (jsonb, jsquery), - FUNCTION 1 gin_compare_jsonb_path_value(bytea, bytea), - FUNCTION 2 gin_extract_jsonb_path_value(internal, internal, internal), - FUNCTION 3 gin_extract_jsonb_query_path_value(anyarray, internal, smallint, internal, internal, internal, internal), - FUNCTION 4 gin_consistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal, internal), - FUNCTION 5 gin_compare_partial_jsonb_path_value(bytea, bytea, smallint, internal), - FUNCTION 6 gin_triconsistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal), - STORAGE bytea; - -CREATE OR REPLACE FUNCTION gin_debug_query_value_path(jsquery) - RETURNS text - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION gin_debug_query_path_value(jsquery) - RETURNS text - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; - -CREATE OR REPLACE FUNCTION parse_mquery(cstring) - RETURNS jsquery - AS 'MODULE_PATHNAME' - LANGUAGE C STRICT IMMUTABLE; From c2d60711d49bb904e2ecdaa05ff6bc576e1c783a Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 13:59:56 +0300 Subject: [PATCH 07/15] Version 1.1 --- META.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/META.json b/META.json index 3121bd1..1eddfa1 100644 --- a/META.json +++ b/META.json @@ -1,4 +1,4 @@ -{ +{ "name": "JsQuery", "abstract": "JSON Query Language with GIN indexing support", "description": "JsQuery provides additional functionality for JSONB, such as a simple and effective way to search in nested objects and arrays, and more comparison operators with index support. It does this by implementing a specialized search syntax, the @@ operator, and the jsquery type for search strings.", From 8182fae0764fd7b756d3173fb77021e8e781a1a3 Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 14:02:51 +0300 Subject: [PATCH 08/15] Version 1.1 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ad1d169..e5ef040 100644 --- a/Makefile +++ b/Makefile @@ -37,4 +37,4 @@ maintainer-clean: install: installincludes installincludes: - $(INSTALL_DATA) $(addprefix $(srcdir)/, $(INCLUDES)) '$(DESTDIR)$(includedir_server)/' + $(INSTALL_DATA) $(addprefix $(srcdir)/, $(INCLUDES)) '$(DESTDIR)$(includedir_server)/' \ No newline at end of file From eb10fffdc40bd25b21f1a5afa44288e27c410181 Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 15:54:42 +0300 Subject: [PATCH 09/15] Update README.md --- README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/README.md b/README.md index 311fd58..2383358 100644 --- a/README.md +++ b/README.md @@ -362,6 +362,57 @@ select '{"a": {"b": 1 } }'::jsonb @@ 'a.b = 1'; (1 row) ``` +#### MongoDB operators supported by extension + +Number of MongoDB query operators is limited by opportunities of +JsQuery language, but main part is supported. + +##### Comparison operators: +* `$eq` - supported; +* `$ne` - supported; +* `$lt` - supported; +* `$lte` - supported; +* `$gt` - supported; +* `$gte` - supported; +* `$in` - supported; +* `$nin` - supported. + +##### Logical operators: +* `$and` - supported; +* `$or` - supported; +* `$not` - supported; +* `$nor` - supported. + +##### Element operators: +* `$exists` - supported; +* `$type` - supported. + +#### Evaluation operators: +* `$mod` - not supported; +* `$regex` - not supported; +* `$text` - supported; +* `$where` - not supported. + +##### Bitwise operators: +* All operators are not supported. + +#### Array operators: +* `$all` - supported; +* `$elemMatch` - supported; +* `$size` - supported. + +##### Comment operators: +* All operators are not supported. + +##### Geospatial operators: +* All operators are not supported. + +##### Projextion operators: +* All operators are not supported. + +Examples of queries with all this operators you can find in the file +[sql/jsquery.sql](https://github.com/postgrespro/jsquery/blob/master/sql/jsquery.sql) + Contribution ------------ From 81ad817d60a1c2a73827c6e3b86e0afa5ac07981 Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 15:55:30 +0300 Subject: [PATCH 10/15] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2383358..eb79653 100644 --- a/README.md +++ b/README.md @@ -387,7 +387,7 @@ JsQuery language, but main part is supported. * `$exists` - supported; * `$type` - supported. -#### Evaluation operators: +##### Evaluation operators: * `$mod` - not supported; * `$regex` - not supported; * `$text` - supported; @@ -396,7 +396,7 @@ JsQuery language, but main part is supported. ##### Bitwise operators: * All operators are not supported. -#### Array operators: +##### Array operators: * `$all` - supported; * `$elemMatch` - supported; * `$size` - supported. From bbf3c19c2c6468b8da4fb42a4933e837432a73ea Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Tue, 18 Jul 2017 15:56:26 +0300 Subject: [PATCH 11/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb79653..b8efd67 100644 --- a/README.md +++ b/README.md @@ -362,7 +362,7 @@ select '{"a": {"b": 1 } }'::jsonb @@ 'a.b = 1'; (1 row) ``` -#### MongoDB operators supported by extension +#### MongoDB operators supported by function Number of MongoDB query operators is limited by opportunities of JsQuery language, but main part is supported. From fb9eaffdbdeee8ba5d0b5f8f2536ef9f63972d27 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 18 Jul 2017 19:55:38 +0300 Subject: [PATCH 12/15] Fix wrong include directive. --- monq_scan.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monq_scan.l b/monq_scan.l index 6ed1114..963b8b2 100644 --- a/monq_scan.l +++ b/monq_scan.l @@ -1,7 +1,7 @@ %{ #include #include - #include "monq_structures.h" + #include "monq.h" #include "monq_gram.h" #include From 39b9442d7781373eff2698756a7d469bd09fee56 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 18 Jul 2017 19:55:57 +0300 Subject: [PATCH 13/15] Fix "make install". --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e5ef040..63dc120 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ OBJS = jsonb_gin_ops.o jsquery_constr.o jsquery_extract.o \ monq_gram.o monq_scan.o monq_get_jsquery.o monq_create_query.o monq_delete_query.o EXTENSION = jsquery -DATA = jsquery--1.0.1.sql +DATA = jsquery--1.1.sql jsquery--1.0--1.1.sql INCLUDES = jsquery.h monq.h REGRESS = jsquery From 4308010f49ef37e70bb14443053597a654c26a1a Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Tue, 18 Jul 2017 19:56:12 +0300 Subject: [PATCH 14/15] Add flex and bison generated files to .gitignore. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 8e194bc..379cab7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ jsquery_gram.c jsquery_scan.c jsquery_gram.h +monq_gram.c +monq_gram.h +monq_scan.c regression.diffs regression.out results From fea3186d8f615aa237a6eabe6deb89aeb7106e3e Mon Sep 17 00:00:00 2001 From: NikitOS94 Date: Wed, 19 Jul 2017 23:24:10 +0300 Subject: [PATCH 15/15] Update error message --- monq_gram.y | 17 +++---- monq_scan.l | 129 ++++++++++++++++++++++++++++------------------------ 2 files changed, 76 insertions(+), 70 deletions(-) diff --git a/monq_gram.y b/monq_gram.y index abc0858..a1ca822 100644 --- a/monq_gram.y +++ b/monq_gram.y @@ -9,26 +9,21 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int yylex(); - extern void yyerror(char *s); extern int yyparse(); + extern void yyerror(char *s); extern YY_BUFFER_STATE yy_scan_string(char * str); extern void yy_delete_buffer(YY_BUFFER_STATE buffer); - void - yyerror(char *s) - { - elog(ERROR,"%s",s); - exit(0); - } - + char *inputString; + int position; MQuery* parse(char *str) { - YY_BUFFER_STATE buffer = yy_scan_string(str); - + YY_BUFFER_STATE buffer = yy_scan_string(str); + inputString = str; yyparse(); yy_delete_buffer(buffer); - + position = 1; return RET; } %} diff --git a/monq_scan.l b/monq_scan.l index 963b8b2..efc485f 100644 --- a/monq_scan.l +++ b/monq_scan.l @@ -1,13 +1,31 @@ %{ #include #include - #include "monq.h" + #include "monq.h" #include "monq_gram.h" #include - extern int yylex(); + extern void yyerror(char *s); + int position = 1; + char *inputString; + + void + yyerror(char *s) + { + int val; + position -= yyleng; + val = position; + position = 1; + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("bad MongoDB representation"), + /* translator: first %s is typically "syntax error" */ + errdetail("%s \"%s\" on line %d position %d\n%s\n%*c", s, yytext, yylineno, val,inputString,val,'^'))); + + exit(0); + } %} %option yylineno @@ -19,78 +37,71 @@ [/][/].*\n ; // comment -[0-9]+ { yylval.strval=strdup(yytext); return INT; } -[0-9]+\.[0-9]+ { yylval.strval=strdup(yytext); return DOUBLE; } -(true|false|TRUE|FALSE) { yylval.boolval=(strcmp(strdup(yytext),"true")==0); return BOOLEAN; } - -\{ { return LSCOPE; } -\} { return RSCOPE; } -\[ { return LSQBRACKET; } -\] { return RSQBRACKET; } +[0-9]+ { yylval.strval=strdup(yytext); position += yyleng; return INT; } +[0-9]+\.[0-9]+ { yylval.strval=strdup(yytext); position += yyleng; return DOUBLE; } +(true|false|TRUE|FALSE) { yylval.boolval=(strcmp(strdup(yytext),"true")==0); position += yyleng; return BOOLEAN; } -\, { return COMMA; } +\{ { position += yyleng; return LSCOPE; } +\} { position += yyleng; return RSCOPE; } +\[ { position += yyleng; return LSQBRACKET; } +\] { position += yyleng; return RSQBRACKET; } -\: { yylval.valop_type=_EQ; return EQ; } -\$(eq|EQ) { yylval.valop_type=_EQ; return EQ; } -\$(lt|LT) { yylval.valop_type=_LESS; return LESS; } -\$(lte|LTE) { yylval.valop_type=_LESSEQ; return LESSEQ; } -\$(gt|GT) { yylval.valop_type=_GREAT; return GREAT; } -\$(gte|GTE) { yylval.valop_type=_GREATEQ; return GREATEQ; } -\$(ne|NE) { yylval.valop_type=_NOTEQ; return NOTEQ; } -\$type { yylval.valop_type=_TYPE; return TYPE; } -\$size { yylval.valop_type=_SIZE; return SIZE; } -\$exists { yylval.valop_type=_EXISTS; return EXISTS; } +\, { position += yyleng; return COMMA; } -\$in { yylval.aop_type=_IN; return IN; } -\$nin { yylval.aop_type=_NIN; return NIN; } -\$all { yylval.aop_type=_ALL; return ALL; } +\: { position += yyleng; yylval.valop_type=_EQ; return EQ; } +\$(eq|EQ) { position += yyleng; yylval.valop_type=_EQ; return EQ; } +\$(lt|LT) { position += yyleng; yylval.valop_type=_LESS; return LESS; } +\$(lte|LTE) { position += yyleng; yylval.valop_type=_LESSEQ; return LESSEQ; } +\$(gt|GT) { position += yyleng; yylval.valop_type=_GREAT; return GREAT; } +\$(gte|GTE) { position += yyleng; yylval.valop_type=_GREATEQ; return GREATEQ; } +\$(ne|NE) { position += yyleng; yylval.valop_type=_NOTEQ; return NOTEQ; } +\$type { position += yyleng; yylval.valop_type=_TYPE; return TYPE; } +\$size { position += yyleng; yylval.valop_type=_SIZE; return SIZE; } +\$exists { position += yyleng; yylval.valop_type=_EXISTS; return EXISTS; } -\$not { return NOT;} +\$in { position += yyleng; yylval.aop_type=_IN; return IN; } +\$nin { position += yyleng; yylval.aop_type=_NIN; return NIN; } +\$all { position += yyleng; yylval.aop_type=_ALL; return ALL; } -\$where { return WHERE_OPERATOR; } +\$not { position += yyleng; return NOT;} -\$elemMatch { return ELEMMATCH; } +\$where { position += yyleng; return WHERE_OPERATOR; } -\$or { yylval.exop_type=_OR; return OR; } -\$nor { yylval.exop_type=_NOR; return NOR; } -\$and { yylval.exop_type=_AND; return AND; } +\$elemMatch { position += yyleng; return ELEMMATCH; } -\$search { return SEARCH_OPERATOR; } -\$text { return TEXT_OPERATOR; } -\$language { return LANGUAGE_OPERATOR; } -\$caseSensitive { return CASE_SENSITIVE_OPERATOR; } -\$diacriticSensitive { return DIACRITIC_SENSITIVE_OPERATOR; } +\$or { position += yyleng; yylval.exop_type=_OR; return OR; } +\$nor { position += yyleng; yylval.exop_type=_NOR; return NOR; } +\$and { position += yyleng; yylval.exop_type=_AND; return AND; } -\$comment { return COMMENT_OPERATOR; } +\$search { position += yyleng; return SEARCH_OPERATOR; } +\$text { position += yyleng; return TEXT_OPERATOR; } +\$language { position += yyleng; return LANGUAGE_OPERATOR; } +\$caseSensitive { position += yyleng; return CASE_SENSITIVE_OPERATOR; } +\$diacriticSensitive { position += yyleng; return DIACRITIC_SENSITIVE_OPERATOR; } -\$mod { return MOD_OPERATOR; } +\$comment { position += yyleng; return COMMENT_OPERATOR; } -\"\" { yylval.strval=strdup(yytext); return STRING; } +\$mod { position += yyleng; return MOD_OPERATOR; } -[0-9a-zA-Z]+ { yylval.strval=strdup(yytext); return KEY_STRING; } +\"\" { position += yyleng; yylval.strval=strdup(yytext); return STRING; } -\"[\.0-9a-zA-Z]*\" { - char *str = strdup(yytext+1); - str[yyleng-2] = '\0'; - yylval.strval = str; - return KEY_STRING; - } +[0-9a-zA-Z]+ { position += yyleng; yylval.strval=strdup(yytext); return KEY_STRING; } -\"[(\\0)\.\, 0-9a-zA-Z]*\" { yylval.strval=strdup(yytext); return STRING; } +\"[\.0-9a-zA-Z]*\" { + char *str = strdup(yytext+1); + str[yyleng-2] = '\0'; + yylval.strval = str; + position += yyleng; + return KEY_STRING; + } -[ \t\r\n] ; // whitespace +\"[(\\\")(\\0)\;\!\@\#\$\%\^\&\*\(\)\.\, 0-9a-zA-Z]*\" { + position += yyleng; + yylval.strval=strdup(yytext); + return STRING; + } +[ \t\r\n] ; { position += yyleng; } // whitespace -%% - -/*MQuery* -parsemquery(const char *str, int len) -{ - YY_BUFFER_STATE buffer = yy_scan_string(str); - - yyparse(); - yy_delete_buffer(buffer); - return RET; -} -*/ +%% \ No newline at end of file pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy