mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Add json(b)_to_tsvector function
Jsonb has a complex nature so there isn't best-for-everything way to convert it to tsvector for full text search. Current to_tsvector(json(b)) suggests to convert only string values, but it's possible to index keys, numerics and even booleans value. To solve that json(b)_to_tsvector has a second required argument contained a list of desired types of json fields. Second argument is a jsonb scalar or array right now with possibility to add new options in a future. Bump catalog version Author: Dmitry Dolgov with some editorization by me Reviewed by: Teodor Sigaev Discussion: https://www.postgresql.org/message-id/CA+q6zcXJQbS1b4kJ_HeAOoOc=unfnOrUEL=KGgE32QKDww7d8g@mail.gmail.com
This commit is contained in:
		
							parent
							
								
									529ab7bd1f
								
							
						
					
					
						commit
						1c1791e000
					
				| @ -9727,6 +9727,26 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple | |||||||
|         <entry><literal>to_tsvector('english', '{"a": "The Fat Rats"}'::json)</literal></entry> |         <entry><literal>to_tsvector('english', '{"a": "The Fat Rats"}'::json)</literal></entry> | ||||||
|         <entry><literal>'fat':2 'rat':3</literal></entry> |         <entry><literal>'fat':2 'rat':3</literal></entry> | ||||||
|        </row> |        </row> | ||||||
|  |        <row> | ||||||
|  |         <entry> | ||||||
|  |          <literal><function>json(b)_to_tsvector(<optional> <replaceable class="parameter">config</replaceable> <type>regconfig</type>, | ||||||
|  |          </optional> <replaceable class="parameter">document</replaceable> <type>json(b)</type>, | ||||||
|  |          <replaceable class="parameter">filter</replaceable> <type>json(b)</type>)</function></literal> | ||||||
|  |         </entry> | ||||||
|  |         <entry><type>tsvector</type></entry> | ||||||
|  |         <entry> | ||||||
|  |           reduce each value in the document, specified by <replaceable class="parameter">filter</replaceable> to a <type>tsvector</type>, | ||||||
|  |           and then concatenate those in document order to produce a single <type>tsvector</type>. | ||||||
|  |           <replaceable class="parameter">filter</replaceable> is a jsonb array, that enumerates what kind of elements need to be included | ||||||
|  |           into the resulting <type>tsvector</type>. Possible values for <replaceable class="parameter">filter</replaceable> are | ||||||
|  |           <literal>"string"</literal> (to include all string values), <literal>"numeric"</literal> (to include all numeric values in the string format), | ||||||
|  |           <literal>"boolean"</literal> (to include all boolean values in the string format "true"/"false"), | ||||||
|  |           <literal>"key"</literal> (to include all keys) or <literal>"all"</literal> (to include all above). These values | ||||||
|  |           can be combined together to include, e.g. all string and numeric values. | ||||||
|  |         </entry> | ||||||
|  |         <entry><literal>json_to_tsvector('english', '{"a": "The Fat Rats", "b": 123}'::json, '["string", "numeric"]')</literal></entry> | ||||||
|  |         <entry><literal>'123':5 'fat':2 'rat':3</literal></entry> | ||||||
|  |        </row> | ||||||
|        <row> |        <row> | ||||||
|         <entry> |         <entry> | ||||||
|          <indexterm> |          <indexterm> | ||||||
|  | |||||||
| @ -267,12 +267,12 @@ to_tsvector(PG_FUNCTION_ARGS) | |||||||
| 										PointerGetDatum(in))); | 										PointerGetDatum(in))); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Datum | /*
 | ||||||
| jsonb_to_tsvector_byid(PG_FUNCTION_ARGS) |  * Worker function for jsonb(_string)_to_tsvector(_byid) | ||||||
|  |  */ | ||||||
|  | static TSVector | ||||||
|  | jsonb_to_tsvector_worker(Oid cfgId, Jsonb *jb, uint32 flags) | ||||||
| { | { | ||||||
| 	Oid			cfgId = PG_GETARG_OID(0); |  | ||||||
| 	Jsonb	   *jb = PG_GETARG_JSONB_P(1); |  | ||||||
| 	TSVector	result; |  | ||||||
| 	TSVectorBuildState state; | 	TSVectorBuildState state; | ||||||
| 	ParsedText	prs; | 	ParsedText	prs; | ||||||
| 
 | 
 | ||||||
| @ -281,11 +281,50 @@ jsonb_to_tsvector_byid(PG_FUNCTION_ARGS) | |||||||
| 	state.prs = &prs; | 	state.prs = &prs; | ||||||
| 	state.cfgId = cfgId; | 	state.cfgId = cfgId; | ||||||
| 
 | 
 | ||||||
| 	iterate_jsonb_string_values(jb, &state, add_to_tsvector); | 	iterate_jsonb_values(jb, flags, &state, add_to_tsvector); | ||||||
| 
 | 
 | ||||||
|  | 	return make_tsvector(&prs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Datum | ||||||
|  | jsonb_string_to_tsvector_byid(PG_FUNCTION_ARGS) | ||||||
|  | { | ||||||
|  | 	Oid			cfgId = PG_GETARG_OID(0); | ||||||
|  | 	Jsonb	   *jb = PG_GETARG_JSONB_P(1); | ||||||
|  | 	TSVector	result; | ||||||
|  | 
 | ||||||
|  | 	result = jsonb_to_tsvector_worker(cfgId, jb, jtiString); | ||||||
| 	PG_FREE_IF_COPY(jb, 1); | 	PG_FREE_IF_COPY(jb, 1); | ||||||
| 
 | 
 | ||||||
| 	result = make_tsvector(&prs); | 	PG_RETURN_TSVECTOR(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Datum | ||||||
|  | jsonb_string_to_tsvector(PG_FUNCTION_ARGS) | ||||||
|  | { | ||||||
|  | 	Jsonb	   *jb = PG_GETARG_JSONB_P(0); | ||||||
|  | 	Oid			cfgId; | ||||||
|  | 	TSVector	result; | ||||||
|  | 
 | ||||||
|  | 	cfgId = getTSCurrentConfig(true); | ||||||
|  | 	result = jsonb_to_tsvector_worker(cfgId, jb, jtiString); | ||||||
|  | 	PG_FREE_IF_COPY(jb, 0); | ||||||
|  | 
 | ||||||
|  | 	PG_RETURN_TSVECTOR(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Datum | ||||||
|  | jsonb_to_tsvector_byid(PG_FUNCTION_ARGS) | ||||||
|  | { | ||||||
|  | 	Oid			cfgId = PG_GETARG_OID(0); | ||||||
|  | 	Jsonb	   *jb = PG_GETARG_JSONB_P(1); | ||||||
|  | 	Jsonb	   *jbFlags = PG_GETARG_JSONB_P(2); | ||||||
|  | 	TSVector	result; | ||||||
|  | 	uint32		flags = parse_jsonb_index_flags(jbFlags); | ||||||
|  | 
 | ||||||
|  | 	result = jsonb_to_tsvector_worker(cfgId, jb, flags); | ||||||
|  | 	PG_FREE_IF_COPY(jb, 1); | ||||||
|  | 	PG_FREE_IF_COPY(jbFlags, 2); | ||||||
| 
 | 
 | ||||||
| 	PG_RETURN_TSVECTOR(result); | 	PG_RETURN_TSVECTOR(result); | ||||||
| } | } | ||||||
| @ -294,20 +333,25 @@ Datum | |||||||
| jsonb_to_tsvector(PG_FUNCTION_ARGS) | jsonb_to_tsvector(PG_FUNCTION_ARGS) | ||||||
| { | { | ||||||
| 	Jsonb	   *jb = PG_GETARG_JSONB_P(0); | 	Jsonb	   *jb = PG_GETARG_JSONB_P(0); | ||||||
|  | 	Jsonb	   *jbFlags = PG_GETARG_JSONB_P(1); | ||||||
| 	Oid			cfgId; | 	Oid			cfgId; | ||||||
|  | 	TSVector	result; | ||||||
|  | 	uint32		flags = parse_jsonb_index_flags(jbFlags); | ||||||
| 
 | 
 | ||||||
| 	cfgId = getTSCurrentConfig(true); | 	cfgId = getTSCurrentConfig(true); | ||||||
| 	PG_RETURN_DATUM(DirectFunctionCall2(jsonb_to_tsvector_byid, | 	result = jsonb_to_tsvector_worker(cfgId, jb, flags); | ||||||
| 										ObjectIdGetDatum(cfgId), | 	PG_FREE_IF_COPY(jb, 0); | ||||||
| 										JsonbPGetDatum(jb))); | 	PG_FREE_IF_COPY(jbFlags, 1); | ||||||
|  | 
 | ||||||
|  | 	PG_RETURN_TSVECTOR(result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Datum | /*
 | ||||||
| json_to_tsvector_byid(PG_FUNCTION_ARGS) |  * Worker function for json(_string)_to_tsvector(_byid) | ||||||
|  |  */ | ||||||
|  | static TSVector | ||||||
|  | json_to_tsvector_worker(Oid cfgId, text *json, uint32 flags) | ||||||
| { | { | ||||||
| 	Oid			cfgId = PG_GETARG_OID(0); |  | ||||||
| 	text	   *json = PG_GETARG_TEXT_P(1); |  | ||||||
| 	TSVector	result; |  | ||||||
| 	TSVectorBuildState state; | 	TSVectorBuildState state; | ||||||
| 	ParsedText	prs; | 	ParsedText	prs; | ||||||
| 
 | 
 | ||||||
| @ -316,11 +360,50 @@ json_to_tsvector_byid(PG_FUNCTION_ARGS) | |||||||
| 	state.prs = &prs; | 	state.prs = &prs; | ||||||
| 	state.cfgId = cfgId; | 	state.cfgId = cfgId; | ||||||
| 
 | 
 | ||||||
| 	iterate_json_string_values(json, &state, add_to_tsvector); | 	iterate_json_values(json, flags, &state, add_to_tsvector); | ||||||
| 
 | 
 | ||||||
|  | 	return make_tsvector(&prs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Datum | ||||||
|  | json_string_to_tsvector_byid(PG_FUNCTION_ARGS) | ||||||
|  | { | ||||||
|  | 	Oid			cfgId = PG_GETARG_OID(0); | ||||||
|  | 	text	   *json = PG_GETARG_TEXT_P(1); | ||||||
|  | 	TSVector	result; | ||||||
|  | 
 | ||||||
|  | 	result = json_to_tsvector_worker(cfgId, json, jtiString); | ||||||
| 	PG_FREE_IF_COPY(json, 1); | 	PG_FREE_IF_COPY(json, 1); | ||||||
| 
 | 
 | ||||||
| 	result = make_tsvector(&prs); | 	PG_RETURN_TSVECTOR(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Datum | ||||||
|  | json_string_to_tsvector(PG_FUNCTION_ARGS) | ||||||
|  | { | ||||||
|  | 	text	   *json = PG_GETARG_TEXT_P(0); | ||||||
|  | 	Oid			cfgId; | ||||||
|  | 	TSVector	result; | ||||||
|  | 
 | ||||||
|  | 	cfgId = getTSCurrentConfig(true); | ||||||
|  | 	result = json_to_tsvector_worker(cfgId, json, jtiString); | ||||||
|  | 	PG_FREE_IF_COPY(json, 0); | ||||||
|  | 
 | ||||||
|  | 	PG_RETURN_TSVECTOR(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Datum | ||||||
|  | json_to_tsvector_byid(PG_FUNCTION_ARGS) | ||||||
|  | { | ||||||
|  | 	Oid			cfgId = PG_GETARG_OID(0); | ||||||
|  | 	text	   *json = PG_GETARG_TEXT_P(1); | ||||||
|  | 	Jsonb	   *jbFlags = PG_GETARG_JSONB_P(2); | ||||||
|  | 	TSVector	result; | ||||||
|  | 	uint32		flags = parse_jsonb_index_flags(jbFlags); | ||||||
|  | 
 | ||||||
|  | 	result = json_to_tsvector_worker(cfgId, json, flags); | ||||||
|  | 	PG_FREE_IF_COPY(json, 1); | ||||||
|  | 	PG_FREE_IF_COPY(jbFlags, 2); | ||||||
| 
 | 
 | ||||||
| 	PG_RETURN_TSVECTOR(result); | 	PG_RETURN_TSVECTOR(result); | ||||||
| } | } | ||||||
| @ -329,12 +412,17 @@ Datum | |||||||
| json_to_tsvector(PG_FUNCTION_ARGS) | json_to_tsvector(PG_FUNCTION_ARGS) | ||||||
| { | { | ||||||
| 	text	   *json = PG_GETARG_TEXT_P(0); | 	text	   *json = PG_GETARG_TEXT_P(0); | ||||||
|  | 	Jsonb	   *jbFlags = PG_GETARG_JSONB_P(1); | ||||||
| 	Oid			cfgId; | 	Oid			cfgId; | ||||||
|  | 	TSVector	result; | ||||||
|  | 	uint32		flags = parse_jsonb_index_flags(jbFlags); | ||||||
| 
 | 
 | ||||||
| 	cfgId = getTSCurrentConfig(true); | 	cfgId = getTSCurrentConfig(true); | ||||||
| 	PG_RETURN_DATUM(DirectFunctionCall2(json_to_tsvector_byid, | 	result = json_to_tsvector_worker(cfgId, json, flags); | ||||||
| 										ObjectIdGetDatum(cfgId), | 	PG_FREE_IF_COPY(json, 0); | ||||||
| 										PointerGetDatum(json))); | 	PG_FREE_IF_COPY(jbFlags, 1); | ||||||
|  | 
 | ||||||
|  | 	PG_RETURN_TSVECTOR(result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -353,7 +441,7 @@ add_to_tsvector(void *_state, char *elem_value, int elem_len) | |||||||
| 		 * First time through: initialize words array to a reasonable size. | 		 * First time through: initialize words array to a reasonable size. | ||||||
| 		 * (parsetext() will realloc it bigger as needed.) | 		 * (parsetext() will realloc it bigger as needed.) | ||||||
| 		 */ | 		 */ | ||||||
| 		prs->lenwords = Max(elem_len / 6, 64); | 		prs->lenwords = 16; | ||||||
| 		prs->words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs->lenwords); | 		prs->words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs->lenwords); | ||||||
| 		prs->curwords = 0; | 		prs->curwords = 0; | ||||||
| 		prs->pos = 0; | 		prs->pos = 0; | ||||||
|  | |||||||
| @ -60,6 +60,7 @@ typedef struct IterateJsonStringValuesState | |||||||
| 	JsonIterateStringValuesAction action;	/* an action that will be applied
 | 	JsonIterateStringValuesAction action;	/* an action that will be applied
 | ||||||
| 											 * to each json value */ | 											 * to each json value */ | ||||||
| 	void	   *action_state;	/* any necessary context for iteration */ | 	void	   *action_state;	/* any necessary context for iteration */ | ||||||
|  | 	uint32      flags;			/* what kind of elements from a json we want to iterate */ | ||||||
| } IterateJsonStringValuesState; | } IterateJsonStringValuesState; | ||||||
| 
 | 
 | ||||||
| /* state for transform_json_string_values function */ | /* state for transform_json_string_values function */ | ||||||
| @ -474,8 +475,9 @@ static void setPathArray(JsonbIterator **it, Datum *path_elems, | |||||||
| 			 int level, Jsonb *newval, uint32 nelems, int op_type); | 			 int level, Jsonb *newval, uint32 nelems, int op_type); | ||||||
| static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb); | static void addJsonbToParseState(JsonbParseState **jbps, Jsonb *jb); | ||||||
| 
 | 
 | ||||||
| /* function supporting iterate_json_string_values */ | /* function supporting iterate_json_values */ | ||||||
| static void iterate_string_values_scalar(void *state, char *token, JsonTokenType tokentype); | static void iterate_values_scalar(void *state, char *token, JsonTokenType tokentype); | ||||||
|  | static void iterate_values_object_field_start(void *state, char *fname, bool isnull); | ||||||
| 
 | 
 | ||||||
| /* functions supporting transform_json_string_values */ | /* functions supporting transform_json_string_values */ | ||||||
| static void transform_string_values_object_start(void *state); | static void transform_string_values_object_start(void *state); | ||||||
| @ -4939,11 +4941,79 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Iterate over jsonb string values or elements, and pass them together with an |  * Parse information about what elements of a jsonb document we want to iterate | ||||||
|  * iteration state to a specified JsonIterateStringValuesAction. |  * in functions iterate_json(b)_values. This information is presented in jsonb | ||||||
|  |  * format, so that it can be easily extended in the future. | ||||||
|  |  */ | ||||||
|  | uint32 | ||||||
|  | parse_jsonb_index_flags(Jsonb *jb) | ||||||
|  | { | ||||||
|  | 	JsonbIterator	   *it; | ||||||
|  | 	JsonbValue			v; | ||||||
|  | 	JsonbIteratorToken	type; | ||||||
|  | 	uint32				flags = 0; | ||||||
|  | 
 | ||||||
|  | 	it = JsonbIteratorInit(&jb->root); | ||||||
|  | 
 | ||||||
|  | 	type = JsonbIteratorNext(&it, &v, false); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * We iterate over array (scalar internally is represented as array, so, we | ||||||
|  | 	 * will accept it too) to check all its elements. Flag's names are choosen | ||||||
|  | 	 * the same as jsonb_typeof uses. | ||||||
|  | 	 */ | ||||||
|  | 	if (type != WJB_BEGIN_ARRAY) | ||||||
|  | 		ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||||||
|  | 						errmsg("wrong flag type, only arrays and scalars are allowed"))); | ||||||
|  | 
 | ||||||
|  | 	while ((type = JsonbIteratorNext(&it, &v, false)) == WJB_ELEM) | ||||||
|  | 	{ | ||||||
|  | 		if (v.type != jbvString) | ||||||
|  | 			ereport(ERROR, | ||||||
|  | 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||||||
|  | 					 errmsg("flag array element is not a string"), | ||||||
|  | 					 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\" and \"all\""))); | ||||||
|  | 
 | ||||||
|  | 		if (v.val.string.len == 3 && | ||||||
|  | 				 pg_strncasecmp(v.val.string.val, "all", 3) == 0) | ||||||
|  | 			flags |= jtiAll; | ||||||
|  | 		else if (v.val.string.len == 3 && | ||||||
|  | 				 pg_strncasecmp(v.val.string.val, "key", 3) == 0) | ||||||
|  | 			flags |= jtiKey; | ||||||
|  | 		else if (v.val.string.len == 6 && | ||||||
|  | 				 pg_strncasecmp(v.val.string.val, "string", 5) == 0) | ||||||
|  | 			flags |= jtiString; | ||||||
|  | 		else if (v.val.string.len == 7 && | ||||||
|  | 				 pg_strncasecmp(v.val.string.val, "numeric", 7) == 0) | ||||||
|  | 			flags |= jtiNumeric; | ||||||
|  | 		else if (v.val.string.len == 7 && | ||||||
|  | 				 pg_strncasecmp(v.val.string.val, "boolean", 7) == 0) | ||||||
|  | 			flags |= jtiBool; | ||||||
|  | 		else | ||||||
|  | 			ereport(ERROR, | ||||||
|  | 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||||||
|  | 					 errmsg("wrong flag in flag array: \"%s\"", | ||||||
|  | 							pnstrdup(v.val.string.val, v.val.string.len)), | ||||||
|  | 					 errhint("Possible values are: \"string\", \"numeric\", \"boolean\", \"key\" and \"all\""))); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* user should not get it */ | ||||||
|  | 	if (type != WJB_END_ARRAY) | ||||||
|  | 		elog(ERROR, "unexpected end of flag array"); | ||||||
|  | 
 | ||||||
|  | 	/* get final WJB_DONE and free iterator */ | ||||||
|  | 	JsonbIteratorNext(&it, &v, false); | ||||||
|  | 
 | ||||||
|  | 	return flags; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Iterate over jsonb values or elements, specified by flags, and pass them | ||||||
|  |  * together with an iteration state to a specified JsonIterateStringValuesAction. | ||||||
|  */ |  */ | ||||||
| void | void | ||||||
| iterate_jsonb_string_values(Jsonb *jb, void *state, JsonIterateStringValuesAction action) | iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, | ||||||
|  | 					 JsonIterateStringValuesAction action) | ||||||
| { | { | ||||||
| 	JsonbIterator *it; | 	JsonbIterator *it; | ||||||
| 	JsonbValue	v; | 	JsonbValue	v; | ||||||
| @ -4951,21 +5021,67 @@ iterate_jsonb_string_values(Jsonb *jb, void *state, JsonIterateStringValuesActio | |||||||
| 
 | 
 | ||||||
| 	it = JsonbIteratorInit(&jb->root); | 	it = JsonbIteratorInit(&jb->root); | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Just recursively iterating over jsonb and call callback on all | ||||||
|  | 	 * correspoding elements | ||||||
|  | 	 */ | ||||||
| 	while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) | 	while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) | ||||||
| 	{ | 	{ | ||||||
| 		if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString) | 		if (type == WJB_KEY) | ||||||
| 		{ | 		{ | ||||||
| 			action(state, v.val.string.val, v.val.string.len); | 			if (flags & jtiKey) | ||||||
|  | 				action(state, v.val.string.val, v.val.string.len); | ||||||
|  | 
 | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 		else if (!(type == WJB_VALUE || type == WJB_ELEM)) | ||||||
|  | 		{ | ||||||
|  | 			/* do not call callback for composite JsonbValue */ | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* JsonbValue is a value of object or element of array */ | ||||||
|  | 		switch(v.type) | ||||||
|  | 		{ | ||||||
|  | 			case jbvString: | ||||||
|  | 				if (flags & jtiString) | ||||||
|  | 					action(state, v.val.string.val, v.val.string.len); | ||||||
|  | 				break; | ||||||
|  | 			case jbvNumeric: | ||||||
|  | 				if (flags & jtiNumeric) | ||||||
|  | 				{ | ||||||
|  | 					char *val; | ||||||
|  | 
 | ||||||
|  | 					val = DatumGetCString(DirectFunctionCall1(numeric_out, | ||||||
|  | 								NumericGetDatum(v.val.numeric))); | ||||||
|  | 
 | ||||||
|  | 					action(state, val, strlen(val)); | ||||||
|  | 					pfree(val); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			case jbvBool: | ||||||
|  | 				if (flags & jtiBool) | ||||||
|  | 				{ | ||||||
|  | 					if (v.val.boolean) | ||||||
|  | 						action(state, "true", 4); | ||||||
|  | 					else | ||||||
|  | 						action(state, "false", 5); | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				/* do not call callback for composite JsonbValue */ | ||||||
|  | 				break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Iterate over json string values or elements, and pass them together with an |  * Iterate over json values and elements, specified by flags, and pass them | ||||||
|  * iteration state to a specified JsonIterateStringValuesAction. |  * together with an iteration state to a specified JsonIterateStringValuesAction. | ||||||
|  */ |  */ | ||||||
| void | void | ||||||
| iterate_json_string_values(text *json, void *action_state, JsonIterateStringValuesAction action) | iterate_json_values(text *json, uint32 flags, void *action_state, | ||||||
|  | 					JsonIterateStringValuesAction action) | ||||||
| { | { | ||||||
| 	JsonLexContext *lex = makeJsonLexContext(json, true); | 	JsonLexContext *lex = makeJsonLexContext(json, true); | ||||||
| 	JsonSemAction *sem = palloc0(sizeof(JsonSemAction)); | 	JsonSemAction *sem = palloc0(sizeof(JsonSemAction)); | ||||||
| @ -4974,24 +5090,55 @@ iterate_json_string_values(text *json, void *action_state, JsonIterateStringValu | |||||||
| 	state->lex = lex; | 	state->lex = lex; | ||||||
| 	state->action = action; | 	state->action = action; | ||||||
| 	state->action_state = action_state; | 	state->action_state = action_state; | ||||||
|  | 	state->flags = flags; | ||||||
| 
 | 
 | ||||||
| 	sem->semstate = (void *) state; | 	sem->semstate = (void *) state; | ||||||
| 	sem->scalar = iterate_string_values_scalar; | 	sem->scalar = iterate_values_scalar; | ||||||
|  | 	sem->object_field_start = iterate_values_object_field_start; | ||||||
| 
 | 
 | ||||||
| 	pg_parse_json(lex, sem); | 	pg_parse_json(lex, sem); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * An auxiliary function for iterate_json_string_values to invoke a specified |  * An auxiliary function for iterate_json_values to invoke a specified | ||||||
|  * JsonIterateStringValuesAction. |  * JsonIterateStringValuesAction for specified values. | ||||||
|  */ |  */ | ||||||
| static void | static void | ||||||
| iterate_string_values_scalar(void *state, char *token, JsonTokenType tokentype) | iterate_values_scalar(void *state, char *token, JsonTokenType tokentype) | ||||||
| { | { | ||||||
| 	IterateJsonStringValuesState *_state = (IterateJsonStringValuesState *) state; | 	IterateJsonStringValuesState *_state = (IterateJsonStringValuesState *) state; | ||||||
| 
 | 
 | ||||||
| 	if (tokentype == JSON_TOKEN_STRING) | 	switch(tokentype) | ||||||
| 		_state->action(_state->action_state, token, strlen(token)); | 	{ | ||||||
|  | 		case JSON_TOKEN_STRING: | ||||||
|  | 			if (_state->flags & jtiString) | ||||||
|  | 				_state->action(_state->action_state, token, strlen(token)); | ||||||
|  | 			break; | ||||||
|  | 		case JSON_TOKEN_NUMBER: | ||||||
|  | 			if (_state->flags & jtiNumeric) | ||||||
|  | 				_state->action(_state->action_state, token, strlen(token)); | ||||||
|  | 			break; | ||||||
|  | 		case JSON_TOKEN_TRUE: | ||||||
|  | 		case JSON_TOKEN_FALSE: | ||||||
|  | 			if (_state->flags & jtiBool) | ||||||
|  | 				_state->action(_state->action_state, token, strlen(token)); | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			/* do not call callback for any other token */ | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | iterate_values_object_field_start(void *state, char *fname, bool isnull) | ||||||
|  | { | ||||||
|  | 	IterateJsonStringValuesState *_state = (IterateJsonStringValuesState *) state; | ||||||
|  | 
 | ||||||
|  | 	if (_state->flags & jtiKey) | ||||||
|  | 	{ | ||||||
|  | 		char *val = pstrdup(fname); | ||||||
|  | 		_state->action(_state->action_state, val, strlen(val)); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | |||||||
| @ -53,6 +53,6 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /*							yyyymmddN */ | /*							yyyymmddN */ | ||||||
| #define CATALOG_VERSION_NO	201804071 | #define CATALOG_VERSION_NO	201804072 | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -4987,14 +4987,22 @@ DATA(insert OID = 5001 (  phraseto_tsquery	PGNSP PGUID 12 100 0 0 0 f f f t f s | |||||||
| DESCR("transform to tsquery"); | DESCR("transform to tsquery"); | ||||||
| DATA(insert OID = 8890 (  websearch_to_tsquery	PGNSP PGUID 12 100 0 0 0 f f f t f s s 1 0 3615 "25" _null_ _null_ _null_ _null_ _null_ websearch_to_tsquery _null_ _null_ _null_ )); | DATA(insert OID = 8890 (  websearch_to_tsquery	PGNSP PGUID 12 100 0 0 0 f f f t f s s 1 0 3615 "25" _null_ _null_ _null_ _null_ _null_ websearch_to_tsquery _null_ _null_ _null_ )); | ||||||
| DESCR("transform to tsquery"); | DESCR("transform to tsquery"); | ||||||
| DATA(insert OID = 4209 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f s s 1 0 3614 "3802" _null_ _null_ _null_ _null_ _null_ jsonb_to_tsvector _null_ _null_ _null_ )); | DATA(insert OID = 4209 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f s s 1 0 3614 "3802" _null_ _null_ _null_ _null_ _null_ jsonb_string_to_tsvector _null_ _null_ _null_ )); | ||||||
| DESCR("transform jsonb to tsvector"); | DESCR("transform string values from jsonb to tsvector"); | ||||||
| DATA(insert OID = 4210 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f s s 1 0 3614 "114" _null_ _null_ _null_ _null_ _null_ json_to_tsvector _null_ _null_ _null_ )); | DATA(insert OID = 4213 (  jsonb_to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f s s 2 0 3614 "3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_to_tsvector _null_ _null_ _null_ )); | ||||||
| DESCR("transform json to tsvector"); | DESCR("transform specified values from jsonb to tsvector"); | ||||||
| DATA(insert OID = 4211 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f i s 2 0 3614 "3734 3802" _null_ _null_ _null_ _null_ _null_ jsonb_to_tsvector_byid _null_ _null_ _null_ )); | DATA(insert OID = 4210 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f s s 1 0 3614 "114" _null_ _null_ _null_ _null_ _null_ json_string_to_tsvector _null_ _null_ _null_ )); | ||||||
| DESCR("transform jsonb to tsvector"); | DESCR("transform string values from json to tsvector"); | ||||||
| DATA(insert OID = 4212 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f i s 2 0 3614 "3734 114" _null_ _null_ _null_ _null_ _null_ json_to_tsvector_byid _null_ _null_ _null_ )); | DATA(insert OID = 4215 (  json_to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f s s 2 0 3614 "114 3802" _null_ _null_ _null_ _null_ _null_ json_to_tsvector _null_ _null_ _null_ )); | ||||||
| DESCR("transform json to tsvector"); | DESCR("transform specified values from json to tsvector"); | ||||||
|  | DATA(insert OID = 4211 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f i s 2 0 3614 "3734 3802" _null_ _null_ _null_ _null_ _null_ jsonb_string_to_tsvector_byid _null_ _null_ _null_ )); | ||||||
|  | DESCR("transform string values from jsonb to tsvector"); | ||||||
|  | DATA(insert OID = 4214 (  jsonb_to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f i s 3 0 3614 "3734 3802 3802" _null_ _null_ _null_ _null_ _null_ jsonb_to_tsvector_byid _null_ _null_ _null_ )); | ||||||
|  | DESCR("transform specified values from jsonb to tsvector"); | ||||||
|  | DATA(insert OID = 4212 (  to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f i s 2 0 3614 "3734 114" _null_ _null_ _null_ _null_ _null_ json_string_to_tsvector_byid _null_ _null_ _null_ )); | ||||||
|  | DESCR("transform string values from json to tsvector"); | ||||||
|  | DATA(insert OID = 4216 (  json_to_tsvector		PGNSP PGUID 12 100 0 0 0 f f f t f i s 3 0 3614 "3734 114 3802" _null_ _null_ _null_ _null_ _null_ json_to_tsvector_byid _null_ _null_ _null_ )); | ||||||
|  | DESCR("transform specified values from json to tsvector"); | ||||||
| 
 | 
 | ||||||
| DATA(insert OID = 3752 (  tsvector_update_trigger			PGNSP PGUID 12 1 0 0 0 f f f f f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ tsvector_update_trigger_byid _null_ _null_ _null_ )); | DATA(insert OID = 3752 (  tsvector_update_trigger			PGNSP PGUID 12 1 0 0 0 f f f f f v s 0 0 2279 "" _null_ _null_ _null_ _null_ _null_ tsvector_update_trigger_byid _null_ _null_ _null_ )); | ||||||
| DESCR("trigger for automatic update of tsvector column"); | DESCR("trigger for automatic update of tsvector column"); | ||||||
|  | |||||||
| @ -132,15 +132,28 @@ extern JsonLexContext *makeJsonLexContextCstringLen(char *json, | |||||||
|  */ |  */ | ||||||
| extern bool IsValidJsonNumber(const char *str, int len); | extern bool IsValidJsonNumber(const char *str, int len); | ||||||
| 
 | 
 | ||||||
| /* an action that will be applied to each value in iterate_json(b)_string_vaues functions */ | /*
 | ||||||
|  |  * Flag types for iterate_json(b)_values to specify what elements from a | ||||||
|  |  * json(b) document we want to iterate. | ||||||
|  |  */ | ||||||
|  | typedef enum JsonToIndex { | ||||||
|  | 	jtiKey		= 0x01, | ||||||
|  | 	jtiString	= 0x02, | ||||||
|  | 	jtiNumeric	= 0x04, | ||||||
|  | 	jtiBool		= 0x08, | ||||||
|  | 	jtiAll		= jtiKey | jtiString | jtiNumeric | jtiBool | ||||||
|  | } JsonToIndex; | ||||||
|  | 
 | ||||||
|  | /* an action that will be applied to each value in iterate_json(b)_vaues functions */ | ||||||
| typedef void (*JsonIterateStringValuesAction) (void *state, char *elem_value, int elem_len); | typedef void (*JsonIterateStringValuesAction) (void *state, char *elem_value, int elem_len); | ||||||
| 
 | 
 | ||||||
| /* an action that will be applied to each value in transform_json(b)_string_values functions */ | /* an action that will be applied to each value in transform_json(b)_values functions */ | ||||||
| typedef text *(*JsonTransformStringValuesAction) (void *state, char *elem_value, int elem_len); | typedef text *(*JsonTransformStringValuesAction) (void *state, char *elem_value, int elem_len); | ||||||
| 
 | 
 | ||||||
| extern void iterate_jsonb_string_values(Jsonb *jb, void *state, | extern uint32 parse_jsonb_index_flags(Jsonb *jb); | ||||||
|  | extern void iterate_jsonb_values(Jsonb *jb, uint32 flags, void *state, | ||||||
| 							JsonIterateStringValuesAction action); | 							JsonIterateStringValuesAction action); | ||||||
| extern void iterate_json_string_values(text *json, void *action_state, | extern void iterate_json_values(text *json, uint32 flags, void *action_state, | ||||||
| 						   JsonIterateStringValuesAction action); | 						   JsonIterateStringValuesAction action); | ||||||
| extern Jsonb *transform_jsonb_string_values(Jsonb *jsonb, void *action_state, | extern Jsonb *transform_jsonb_string_values(Jsonb *jsonb, void *action_state, | ||||||
| 							  JsonTransformStringValuesAction transform_action); | 							  JsonTransformStringValuesAction transform_action); | ||||||
|  | |||||||
| @ -2324,6 +2324,86 @@ select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": ["the eee fff gg | |||||||
|  'aaa':1 'bbb':3 'ccc':5 'ddd':4 'eee':8 'fff':9 'ggg':10 'hhh':12 'iii':13 |  'aaa':1 'bbb':3 'ccc':5 'ddd':4 'eee':8 'fff':9 'ggg':10 'hhh':12 'iii':13 | ||||||
| (1 row) | (1 row) | ||||||
| 
 | 
 | ||||||
|  | -- json to tsvector with numeric values | ||||||
|  | select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": 123, "c": 456}'::json); | ||||||
|  |            to_tsvector            | ||||||
|  | --------------------------------- | ||||||
|  |  'aaa':1 'bbb':3 'ccc':5 'ddd':4 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | -- json_to_tsvector | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"all"'); | ||||||
|  |                                     json_to_tsvector                                     | ||||||
|  | ---------------------------------------------------------------------------------------- | ||||||
|  |  '123':8 '456':12 'aaa':2 'b':6 'bbb':4 'c':10 'd':14 'f':18 'fals':20 'g':22 'true':16 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"key"'); | ||||||
|  |         json_to_tsvector         | ||||||
|  | -------------------------------- | ||||||
|  |  'b':2 'c':4 'd':6 'f':8 'g':10 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"string"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |  'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"numeric"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |  '123':1 '456':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"boolean"'); | ||||||
|  |  json_to_tsvector   | ||||||
|  | ------------------- | ||||||
|  |  'fals':3 'true':1 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '["string", "numeric"]'); | ||||||
|  |         json_to_tsvector          | ||||||
|  | --------------------------------- | ||||||
|  |  '123':5 '456':7 'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"all"'); | ||||||
|  |                                     json_to_tsvector                                     | ||||||
|  | ---------------------------------------------------------------------------------------- | ||||||
|  |  '123':8 '456':12 'aaa':2 'b':6 'bbb':4 'c':10 'd':14 'f':18 'fals':20 'g':22 'true':16 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"key"'); | ||||||
|  |         json_to_tsvector         | ||||||
|  | -------------------------------- | ||||||
|  |  'b':2 'c':4 'd':6 'f':8 'g':10 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"string"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |  'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"numeric"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |  '123':1 '456':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"boolean"'); | ||||||
|  |  json_to_tsvector   | ||||||
|  | ------------------- | ||||||
|  |  'fals':3 'true':1 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '["string", "numeric"]'); | ||||||
|  |         json_to_tsvector          | ||||||
|  | --------------------------------- | ||||||
|  |  '123':5 '456':7 'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
| -- ts_vector corner cases | -- ts_vector corner cases | ||||||
| select to_tsvector('""'::json); | select to_tsvector('""'::json); | ||||||
|  to_tsvector  |  to_tsvector  | ||||||
| @ -2349,6 +2429,48 @@ select to_tsvector('null'::json); | |||||||
|   |   | ||||||
| (1 row) | (1 row) | ||||||
| 
 | 
 | ||||||
|  | -- json_to_tsvector corner cases | ||||||
|  | select json_to_tsvector('""'::json, '"all"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{}'::json, '"all"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('[]'::json, '"all"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('null'::json, '"all"'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '""'); | ||||||
|  | ERROR:  wrong flag in flag array: "" | ||||||
|  | HINT:  Possible values are: "string", "numeric", "boolean", "key" and "all" | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '{}'); | ||||||
|  | ERROR:  wrong flag type, only arrays and scalars are allowed | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '[]'); | ||||||
|  |  json_to_tsvector  | ||||||
|  | ------------------ | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, 'null'); | ||||||
|  | ERROR:  flag array element is not a string | ||||||
|  | HINT:  Possible values are: "string", "numeric", "boolean", "key" and "all" | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '["all", null]'); | ||||||
|  | ERROR:  flag array element is not a string | ||||||
|  | HINT:  Possible values are: "string", "numeric", "boolean", "key" and "all" | ||||||
| -- ts_headline for json | -- ts_headline for json | ||||||
| select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::json, tsquery('bbb & ddd & hhh')); | select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::json, tsquery('bbb & ddd & hhh')); | ||||||
|                                                ts_headline                                                |                                                ts_headline                                                | ||||||
|  | |||||||
| @ -4122,6 +4122,86 @@ select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": ["the eee fff gg | |||||||
|  'aaa':1 'bbb':3 'ccc':5 'ddd':4 'eee':8 'fff':9 'ggg':10 'hhh':12 'iii':13 |  'aaa':1 'bbb':3 'ccc':5 'ddd':4 'eee':8 'fff':9 'ggg':10 'hhh':12 'iii':13 | ||||||
| (1 row) | (1 row) | ||||||
| 
 | 
 | ||||||
|  | -- jsonb to tsvector with numeric values | ||||||
|  | select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": 123, "c": 456}'::jsonb); | ||||||
|  |            to_tsvector            | ||||||
|  | --------------------------------- | ||||||
|  |  'aaa':1 'bbb':3 'ccc':5 'ddd':4 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | -- jsonb_to_tsvector | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"all"'); | ||||||
|  |                                    jsonb_to_tsvector                                     | ||||||
|  | ---------------------------------------------------------------------------------------- | ||||||
|  |  '123':8 '456':12 'aaa':2 'b':6 'bbb':4 'c':10 'd':14 'f':18 'fals':20 'g':22 'true':16 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"key"'); | ||||||
|  |        jsonb_to_tsvector         | ||||||
|  | -------------------------------- | ||||||
|  |  'b':2 'c':4 'd':6 'f':8 'g':10 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"string"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |  'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"numeric"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |  '123':1 '456':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"boolean"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |  'fals':3 'true':1 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["string", "numeric"]'); | ||||||
|  |         jsonb_to_tsvector         | ||||||
|  | --------------------------------- | ||||||
|  |  '123':5 '456':7 'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"all"'); | ||||||
|  |                                    jsonb_to_tsvector                                     | ||||||
|  | ---------------------------------------------------------------------------------------- | ||||||
|  |  '123':8 '456':12 'aaa':2 'b':6 'bbb':4 'c':10 'd':14 'f':18 'fals':20 'g':22 'true':16 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"key"'); | ||||||
|  |        jsonb_to_tsvector         | ||||||
|  | -------------------------------- | ||||||
|  |  'b':2 'c':4 'd':6 'f':8 'g':10 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"string"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |  'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"numeric"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |  '123':1 '456':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"boolean"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |  'fals':3 'true':1 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["string", "numeric"]'); | ||||||
|  |         jsonb_to_tsvector         | ||||||
|  | --------------------------------- | ||||||
|  |  '123':5 '456':7 'aaa':1 'bbb':3 | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
| -- ts_vector corner cases | -- ts_vector corner cases | ||||||
| select to_tsvector('""'::jsonb); | select to_tsvector('""'::jsonb); | ||||||
|  to_tsvector  |  to_tsvector  | ||||||
| @ -4147,6 +4227,48 @@ select to_tsvector('null'::jsonb); | |||||||
|   |   | ||||||
| (1 row) | (1 row) | ||||||
| 
 | 
 | ||||||
|  | -- jsonb_to_tsvector corner cases | ||||||
|  | select jsonb_to_tsvector('""'::jsonb, '"all"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{}'::jsonb, '"all"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('[]'::jsonb, '"all"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('null'::jsonb, '"all"'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '""'); | ||||||
|  | ERROR:  wrong flag in flag array: "" | ||||||
|  | HINT:  Possible values are: "string", "numeric", "boolean", "key" and "all" | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '{}'); | ||||||
|  | ERROR:  wrong flag type, only arrays and scalars are allowed | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '[]'); | ||||||
|  |  jsonb_to_tsvector  | ||||||
|  | ------------------- | ||||||
|  |   | ||||||
|  | (1 row) | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, 'null'); | ||||||
|  | ERROR:  flag array element is not a string | ||||||
|  | HINT:  Possible values are: "string", "numeric", "boolean", "key" and "all" | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["all", null]'); | ||||||
|  | ERROR:  flag array element is not a string | ||||||
|  | HINT:  Possible values are: "string", "numeric", "boolean", "key" and "all" | ||||||
| -- ts_headline for jsonb | -- ts_headline for jsonb | ||||||
| select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh')); | select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh')); | ||||||
|                                                    ts_headline                                                     |                                                    ts_headline                                                     | ||||||
|  | |||||||
| @ -763,12 +763,42 @@ select to_tsvector('simple', '{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c" | |||||||
| -- json to tsvector with stop words | -- json to tsvector with stop words | ||||||
| select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": ["the eee fff ggg"], "c": {"d": "hhh. iii"}}'::json); | select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": ["the eee fff ggg"], "c": {"d": "hhh. iii"}}'::json); | ||||||
| 
 | 
 | ||||||
|  | -- json to tsvector with numeric values | ||||||
|  | select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": 123, "c": 456}'::json); | ||||||
|  | 
 | ||||||
|  | -- json_to_tsvector | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"all"'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"key"'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"string"'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"numeric"'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"boolean"'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '["string", "numeric"]'); | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"all"'); | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"key"'); | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"string"'); | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"numeric"'); | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '"boolean"'); | ||||||
|  | select json_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '["string", "numeric"]'); | ||||||
|  | 
 | ||||||
| -- ts_vector corner cases | -- ts_vector corner cases | ||||||
| select to_tsvector('""'::json); | select to_tsvector('""'::json); | ||||||
| select to_tsvector('{}'::json); | select to_tsvector('{}'::json); | ||||||
| select to_tsvector('[]'::json); | select to_tsvector('[]'::json); | ||||||
| select to_tsvector('null'::json); | select to_tsvector('null'::json); | ||||||
| 
 | 
 | ||||||
|  | -- json_to_tsvector corner cases | ||||||
|  | select json_to_tsvector('""'::json, '"all"'); | ||||||
|  | select json_to_tsvector('{}'::json, '"all"'); | ||||||
|  | select json_to_tsvector('[]'::json, '"all"'); | ||||||
|  | select json_to_tsvector('null'::json, '"all"'); | ||||||
|  | 
 | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '""'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '{}'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '[]'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, 'null'); | ||||||
|  | select json_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::json, '["all", null]'); | ||||||
|  | 
 | ||||||
| -- ts_headline for json | -- ts_headline for json | ||||||
| select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::json, tsquery('bbb & ddd & hhh')); | select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::json, tsquery('bbb & ddd & hhh')); | ||||||
| select ts_headline('english', '{"a": "aaa bbb", "b": {"c": "ccc ddd fff"}, "d": ["ggg hhh", "iii jjj"]}'::json, tsquery('bbb & ddd & hhh')); | select ts_headline('english', '{"a": "aaa bbb", "b": {"c": "ccc ddd fff"}, "d": ["ggg hhh", "iii jjj"]}'::json, tsquery('bbb & ddd & hhh')); | ||||||
|  | |||||||
| @ -1089,12 +1089,42 @@ select to_tsvector('simple', '{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c" | |||||||
| -- jsonb to tsvector with stop words | -- jsonb to tsvector with stop words | ||||||
| select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": ["the eee fff ggg"], "c": {"d": "hhh. iii"}}'::jsonb); | select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": ["the eee fff ggg"], "c": {"d": "hhh. iii"}}'::jsonb); | ||||||
| 
 | 
 | ||||||
|  | -- jsonb to tsvector with numeric values | ||||||
|  | select to_tsvector('english', '{"a": "aaa in bbb ddd ccc", "b": 123, "c": 456}'::jsonb); | ||||||
|  | 
 | ||||||
|  | -- jsonb_to_tsvector | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"all"'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"key"'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"string"'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"numeric"'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"boolean"'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["string", "numeric"]'); | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"all"'); | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"key"'); | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"string"'); | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"numeric"'); | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '"boolean"'); | ||||||
|  | select jsonb_to_tsvector('english', '{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["string", "numeric"]'); | ||||||
|  | 
 | ||||||
| -- ts_vector corner cases | -- ts_vector corner cases | ||||||
| select to_tsvector('""'::jsonb); | select to_tsvector('""'::jsonb); | ||||||
| select to_tsvector('{}'::jsonb); | select to_tsvector('{}'::jsonb); | ||||||
| select to_tsvector('[]'::jsonb); | select to_tsvector('[]'::jsonb); | ||||||
| select to_tsvector('null'::jsonb); | select to_tsvector('null'::jsonb); | ||||||
| 
 | 
 | ||||||
|  | -- jsonb_to_tsvector corner cases | ||||||
|  | select jsonb_to_tsvector('""'::jsonb, '"all"'); | ||||||
|  | select jsonb_to_tsvector('{}'::jsonb, '"all"'); | ||||||
|  | select jsonb_to_tsvector('[]'::jsonb, '"all"'); | ||||||
|  | select jsonb_to_tsvector('null'::jsonb, '"all"'); | ||||||
|  | 
 | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '""'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '{}'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '[]'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, 'null'); | ||||||
|  | select jsonb_to_tsvector('{"a": "aaa in bbb", "b": 123, "c": 456, "d": true, "f": false, "g": null}'::jsonb, '["all", null]'); | ||||||
|  | 
 | ||||||
| -- ts_headline for jsonb | -- ts_headline for jsonb | ||||||
| select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh')); | select ts_headline('{"a": "aaa bbb", "b": {"c": "ccc ddd fff", "c1": "ccc1 ddd1"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh')); | ||||||
| select ts_headline('english', '{"a": "aaa bbb", "b": {"c": "ccc ddd fff"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh')); | select ts_headline('english', '{"a": "aaa bbb", "b": {"c": "ccc ddd fff"}, "d": ["ggg hhh", "iii jjj"]}'::jsonb, tsquery('bbb & ddd & hhh')); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user