Skip to content

Commit 87153d3

Browse files
committed
implement IS needed for schema check feature. Index doesnt support it yet
1 parent 7ddf618 commit 87153d3

File tree

8 files changed

+200
-18
lines changed

8 files changed

+200
-18
lines changed

Diff for: expected/jsquery.out

+67
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,73 @@ ERROR: bad jsquery representation
958958
LINE 1: select 'a\r = x"\\abcd"'::jsquery AS err;
959959
^
960960
DETAIL: syntax error, unexpected STRING_P, expecting $end at or near """
961+
--IS
962+
select 'as IS boolean | as is ARRAY | as is ObJect | as is Number | as is string'::jsquery;
963+
jsquery
964+
--------------------------------------------------------------------------------------------
965+
(((("as" IS BOOLEAN | "as" IS ARRAY) | "as" IS OBJECT) | "as" IS NUMBER) | "as" IS STRING)
966+
(1 row)
967+
968+
select '{"as": "xxx"}' @@ 'as IS string'::jsquery;
969+
?column?
970+
----------
971+
t
972+
(1 row)
973+
974+
select '{"as": "xxx"}' @@ 'as IS boolean | as is ARRAY | as is ObJect | as is Number'::jsquery;
975+
?column?
976+
----------
977+
f
978+
(1 row)
979+
980+
select '{"as": 5}' @@ 'as is Number'::jsquery;
981+
?column?
982+
----------
983+
t
984+
(1 row)
985+
986+
select '{"as": true}' @@ 'as is boolean'::jsquery;
987+
?column?
988+
----------
989+
t
990+
(1 row)
991+
992+
select '{"as": false}' @@ 'as is boolean'::jsquery;
993+
?column?
994+
----------
995+
t
996+
(1 row)
997+
998+
select '{"as": "false"}' @@ 'as is boolean'::jsquery;
999+
?column?
1000+
----------
1001+
f
1002+
(1 row)
1003+
1004+
select '["xxx"]' @@ '$ IS array'::jsquery;
1005+
?column?
1006+
----------
1007+
t
1008+
(1 row)
1009+
1010+
select '{"as": false}' @@ '$ IS object'::jsquery;
1011+
?column?
1012+
----------
1013+
t
1014+
(1 row)
1015+
1016+
select '"xxx"' @@ '$ IS string'::jsquery;
1017+
?column?
1018+
----------
1019+
t
1020+
(1 row)
1021+
1022+
select '"xxx"' @@ '$ IS number'::jsquery;
1023+
?column?
1024+
----------
1025+
f
1026+
(1 row)
1027+
9611028
---table and index
9621029
select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 0;
9631030
count

Diff for: jsquery.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ typedef enum JsQueryItemType {
5151
jqiAnyKey = '%',
5252
jqiKey = 'K',
5353
jqiCurrent = '$',
54-
jqiIn = 'I'
54+
jqiIn = 'I',
55+
jqiIs = 'i'
5556
} JsQueryItemType;
5657

5758
/*
@@ -87,8 +88,6 @@ typedef struct JsQueryItem {
8788
int32 *arrayPtr;
8889
} array;
8990
};
90-
91-
9291
} JsQueryItem;
9392

9493
extern void jsqInit(JsQueryItem *v, JsQuery *js);
@@ -99,6 +98,7 @@ extern void jsqGetLeftArg(JsQueryItem *v, JsQueryItem *a);
9998
extern void jsqGetRightArg(JsQueryItem *v, JsQueryItem *a);
10099
extern Numeric jsqGetNumeric(JsQueryItem *v);
101100
extern bool jsqGetBool(JsQueryItem *v);
101+
extern int32 jsqGetIsType(JsQueryItem *v);
102102
extern char * jsqGetString(JsQueryItem *v, int32 *len);
103103
extern void jsqIterateInit(JsQueryItem *v);
104104
extern bool jsqIterateArray(JsQueryItem *v, JsQueryItem *e);
@@ -122,6 +122,7 @@ struct JsQueryParseItem {
122122
} args;
123123

124124
JsQueryParseItem *arg;
125+
int8 isType; /* jbv* values */
125126

126127
Numeric numeric;
127128
bool boolean;

Diff for: jsquery_gram.y

+40-11
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ makeItemUnary(int type, JsQueryParseItem* a)
152152
return v;
153153
}
154154

155+
static JsQueryParseItem*
156+
makeItemIs(int isType)
157+
{
158+
JsQueryParseItem *v = makeItemType(jqiIs);
159+
160+
v->isType = isType;
161+
162+
return v;
163+
}
164+
155165
static JsQueryParseItem*
156166
makeItemList(List *list) {
157167
JsQueryParseItem *head, *end;
@@ -183,21 +193,23 @@ makeItemList(List *list) {
183193

184194
%union {
185195
string str;
186-
Numeric numeric;
187196
List *elems; /* list of JsQueryParseItem */
188197

189198
JsQueryParseItem *value;
190199
}
191200

192-
%token <str> NULL_P STRING_P TRUE_P FALSE_P
193-
NUMERIC_P IN_P
201+
%token <str> IN_P IS_P NULL_P TRUE_P ARRAY_P
202+
FALSE_P NUMBER_P OBJECT_P TEXT_P
203+
BOOLEAN_P
204+
205+
%token <str> STRING_P NUMERIC_P
194206

195-
%type <value> result scalar_value
196-
%type <str> key
207+
%type <value> result scalar_value
208+
%type <str> key
197209

198-
%type <elems> path value_list
210+
%type <elems> path value_list
199211

200-
%type <value> path_elem right_expr expr array
212+
%type <value> path_elem right_expr expr array
201213

202214
%left '|'
203215
%left '&'
@@ -216,11 +228,17 @@ array:
216228
;
217229

218230
scalar_value:
219-
NULL_P { $$ = makeItemString(NULL); }
220-
| STRING_P { $$ = makeItemString(&$1); }
231+
STRING_P { $$ = makeItemString(&$1); }
221232
| IN_P { $$ = makeItemString(&$1); }
233+
| IS_P { $$ = makeItemString(&$1); }
234+
| NULL_P { $$ = makeItemString(NULL); }
222235
| TRUE_P { $$ = makeItemBool(true); }
236+
| ARRAY_P { $$ = makeItemString(&$1); }
223237
| FALSE_P { $$ = makeItemBool(false); }
238+
| NUMBER_P { $$ = makeItemString(&$1); }
239+
| OBJECT_P { $$ = makeItemString(&$1); }
240+
| TEXT_P { $$ = makeItemString(&$1); }
241+
| BOOLEAN_P { $$ = makeItemString(&$1); }
224242
| NUMERIC_P { $$ = makeItemNumeric(&$1); }
225243
;
226244

@@ -241,6 +259,11 @@ right_expr:
241259
| '@' '>' array { $$ = makeItemUnary(jqiContains, $3); }
242260
| '<' '@' array { $$ = makeItemUnary(jqiContained, $3); }
243261
| '&' '&' array { $$ = makeItemUnary(jqiOverlap, $3); }
262+
| IS_P ARRAY_P { $$ = makeItemIs(jbvArray); }
263+
| IS_P NUMBER_P { $$ = makeItemIs(jbvNumeric); }
264+
| IS_P OBJECT_P { $$ = makeItemIs(jbvObject); }
265+
| IS_P TEXT_P { $$ = makeItemIs(jbvString); }
266+
| IS_P BOOLEAN_P { $$ = makeItemIs(jbvBool); }
244267
;
245268

246269
expr:
@@ -257,11 +280,17 @@ expr:
257280
*/
258281
key:
259282
STRING_P { $$ = $1; }
283+
| IN_P { $$ = $1; }
284+
| IS_P { $$ = $1; }
285+
| NULL_P { $$ = $1; }
260286
| TRUE_P { $$ = $1; }
287+
| ARRAY_P { $$ = $1; }
261288
| FALSE_P { $$ = $1; }
289+
| NUMBER_P { $$ = $1; }
290+
| OBJECT_P { $$ = $1; }
291+
| TEXT_P { $$ = $1; }
292+
| BOOLEAN_P { $$ = $1; }
262293
| NUMERIC_P { $$ = $1; }
263-
| NULL_P { $$ = $1; }
264-
| IN_P { $$ = $1; }
265294
;
266295

267296
path_elem:

Diff for: jsquery_io.c

+28-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ flattenJsQueryParseItem(StringInfo buf, JsQueryParseItem *item)
5050
case jqiBool:
5151
appendBinaryStringInfo(buf, (char*)&item->boolean, sizeof(item->boolean));
5252
break;
53+
case jqiIs:
54+
appendBinaryStringInfo(buf, (char*)&item->isType, sizeof(item->isType));
55+
break;
5356
case jqiArray:
5457
{
5558
int32 i, arrayStart;
@@ -203,13 +206,37 @@ printJsQueryItem(StringInfo buf, JsQueryItem *v, bool inKey, bool printBracketes
203206
appendStringInfoString(buf,
204207
DatumGetCString(DirectFunctionCall1(numeric_out,
205208
PointerGetDatum(jsqGetNumeric(v)))));
206-
break;
209+
break;
207210
case jqiBool:
208211
if (jsqGetBool(v))
209212
appendBinaryStringInfo(buf, "true", 4);
210213
else
211214
appendBinaryStringInfo(buf, "false", 5);
212215
break;
216+
case jqiIs:
217+
appendBinaryStringInfo(buf, " IS ", 4);
218+
switch(jsqGetIsType(v))
219+
{
220+
case jbvString:
221+
appendBinaryStringInfo(buf, "STRING", 6);
222+
break;
223+
case jbvNumeric:
224+
appendBinaryStringInfo(buf, "NUMBER", 6);
225+
break;
226+
case jbvBool:
227+
appendBinaryStringInfo(buf, "BOOLEAN", 7);
228+
break;
229+
case jbvArray:
230+
appendBinaryStringInfo(buf, "ARRAY", 5);
231+
break;
232+
case jbvObject:
233+
appendBinaryStringInfo(buf, "OBJECT", 6);
234+
break;
235+
default:
236+
elog(ERROR, "Unknown type for IS: %d", jsqGetIsType(v));
237+
break;
238+
}
239+
break;
213240
case jqiArray:
214241
if (printBracketes)
215242
appendStringInfoChar(buf, '[');

Diff for: jsquery_op.c

+24
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,30 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb)
427427
jsqGetArg(jsq, &elem);
428428
res = executeExpr(&elem, jsq->type, jb);
429429
break;
430+
case jqiIs:
431+
if (JsonbType(jb) == jbvScalar)
432+
{
433+
JsonbIterator *it;
434+
int32 r;
435+
JsonbValue v;
436+
437+
it = JsonbIteratorInit(jb->val.binary.data);
438+
439+
r = JsonbIteratorNext(&it, &v, true);
440+
Assert(r == WJB_BEGIN_ARRAY);
441+
Assert(v.val.array.rawScalar == 1);
442+
Assert(v.val.array.nElems == 1);
443+
444+
r = JsonbIteratorNext(&it, &v, true);
445+
Assert(r == WJB_ELEM);
446+
447+
res = (jsqGetIsType(jsq) == JsonbType(&v));
448+
}
449+
else
450+
{
451+
res = (jsqGetIsType(jsq) == JsonbType(jb));
452+
}
453+
break;
430454
default:
431455
elog(ERROR,"Wrong state: %d", jsq->type);
432456
}

Diff for: jsquery_scan.l

+14-3
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,22 @@ typedef struct keyword
191191
char *keyword;
192192
} keyword;
193193

194+
/*
195+
* Array of key words should be sorted by length and then
196+
* alphabetical order
197+
*/
198+
194199
static keyword keywords[] = {
195-
{ 2, false, IN_P, "in" },
200+
{ 2, false, IN_P, "in"},
201+
{ 2, false, IS_P, "is"},
196202
{ 4, true, NULL_P, "null"},
197203
{ 4, true, TRUE_P, "true"},
198-
{ 5, true, FALSE_P, "false"}
204+
{ 5, false, ARRAY_P, "array"},
205+
{ 5, true, FALSE_P, "false"},
206+
{ 6, false, NUMBER_P, "number"},
207+
{ 6, false, OBJECT_P, "object"},
208+
{ 6, false, TEXT_P, "string"},
209+
{ 7, false, BOOLEAN_P, "boolean"},
199210
};
200211

201212
static int
@@ -212,7 +223,7 @@ checkSpecialVal()
212223

213224
while(StopLow < StopHigh)
214225
{
215-
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
226+
StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
216227

217228
if (StopMiddle->len == scanstring.len)
218229
diff = pg_strncasecmp(StopMiddle->keyword, scanstring.val, scanstring.len);

Diff for: jsquery_support.c

+9
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ jsqInitByBuffer(JsQueryItem *v, char *base, int32 pos)
7979
/* follow next */
8080
case jqiNumeric:
8181
case jqiBool:
82+
case jqiIs:
8283
v->value.data = base + pos;
8384
break;
8485
case jqiArray:
@@ -186,6 +187,14 @@ jsqGetNumeric(JsQueryItem *v)
186187
return (Numeric)v->value.data;
187188
}
188189

190+
int32
191+
jsqGetIsType(JsQueryItem *v)
192+
{
193+
Assert(v->type = jqiIs);
194+
195+
return (int32)*v->value.data;
196+
}
197+
189198
char*
190199
jsqGetString(JsQueryItem *v, int32 *len)
191200
{

Diff for: sql/jsquery.sql

+14
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,20 @@ select 'a\r = "\abcdx"'::jsquery AS err;
193193
select 'a\r = "\\abcdx"'::jsquery;
194194
select 'a\r = x"\\abcd"'::jsquery AS err;
195195

196+
--IS
197+
198+
select 'as IS boolean | as is ARRAY | as is ObJect | as is Number | as is string'::jsquery;
199+
select '{"as": "xxx"}' @@ 'as IS string'::jsquery;
200+
select '{"as": "xxx"}' @@ 'as IS boolean | as is ARRAY | as is ObJect | as is Number'::jsquery;
201+
select '{"as": 5}' @@ 'as is Number'::jsquery;
202+
select '{"as": true}' @@ 'as is boolean'::jsquery;
203+
select '{"as": false}' @@ 'as is boolean'::jsquery;
204+
select '{"as": "false"}' @@ 'as is boolean'::jsquery;
205+
select '["xxx"]' @@ '$ IS array'::jsquery;
206+
select '{"as": false}' @@ '$ IS object'::jsquery;
207+
select '"xxx"' @@ '$ IS string'::jsquery;
208+
select '"xxx"' @@ '$ IS number'::jsquery;
209+
196210
---table and index
197211

198212
select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 0;

0 commit comments

Comments
 (0)