diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index e08bf60..fe93058 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -9086,16 +9086,28 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
          <indexterm>
           <primary>setweight</primary>
          </indexterm>
-         <literal><function>setweight(<type>tsvector</>, <type>"char"</>)</function></literal>
+         <literal><function>setweight(<replaceable class="PARAMETER">tsin</replaceable> <type>tsvector</>, <replaceable class="PARAMETER">w</replaceable> <type>"char"</>)</function></literal>
         </entry>
         <entry><type>tsvector</type></entry>
-        <entry>assign weight to each element of <type>tsvector</></entry>
+        <entry>assign weight <replaceable class="PARAMETER">w</replaceable> to each element of <replaceable class="PARAMETER">tsin</replaceable></entry>
         <entry><literal>setweight('fat:2,4 cat:3 rat:5B'::tsvector, 'A')</literal></entry>
         <entry><literal>'cat':3A 'fat':2A,4A 'rat':5A</literal></entry>
        </row>
        <row>
         <entry>
          <indexterm>
+          <primary>setweight_by_filter</primary>
+         </indexterm>
+         <literal><function>setweight(<replaceable class="PARAMETER">tsin</replaceable> <type>tsvector</>, <replaceable class="PARAMETER">w</replaceable> <type>"char"</>, <replaceable class="PARAMETER">lexarr</replaceable> <type>"text"[]</>)</function></literal>
+        </entry>
+        <entry><type>tsvector</type></entry>
+        <entry>assign weight <replaceable class="PARAMETER">w</replaceable> to elements of <replaceable class="PARAMETER">tsin</replaceable> that are listed in lexemes array <replaceable class="PARAMETER">lexarr</replaceable></entry>
+        <entry><literal>setweight('fat:2,4 cat:3 rat:5B'::tsvector, 'A', '{cat,rat}')</literal></entry>
+        <entry><literal>'cat':3A 'fat':2,4 'rat':5A</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
           <primary>strip</primary>
          </indexterm>
          <literal><function>strip(<type>tsvector</>)</function></literal>
@@ -9108,6 +9120,108 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
        <row>
         <entry>
          <indexterm>
+          <primary>delete_str</primary>
+         </indexterm>
+         <literal><function>delete(<replaceable class="PARAMETER">tsin</replaceable> <type>tsvector</>, <replaceable class="PARAMETER">lexeme</replaceable> <type>text</>)</function></literal>
+        </entry>
+        <entry><type>tsvector</type></entry>
+        <entry>remove given <replaceable class="PARAMETER">lexeme</replaceable> from <replaceable class="PARAMETER">tsin</replaceable></entry>
+        <entry><literal>delete('fat:2,4 cat:3 rat:5A'::tsvector, 'fat')</literal></entry>
+        <entry><literal>'cat':3 'rat':5A</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>delete_arr</primary>
+         </indexterm>
+         <literal><function>delete(<replaceable class="PARAMETER">tsin</replaceable> <type>tsvector</>, <replaceable class="PARAMETER">lexarr</replaceable> <type>text[]</>)</function></literal>
+        </entry>
+        <entry><type>tsvector</type></entry>
+        <entry>remove any occurrence of lexemes in <replaceable class="PARAMETER">lexarr</replaceable> from <replaceable class="PARAMETER">tsin</replaceable></entry>
+        <entry><literal>delete('fat:2,4 cat:3 rat:5A'::tsvector, ARRAY['fat','rat'])</literal></entry>
+        <entry><literal>'cat':3</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>delete_tsvector</primary>
+         </indexterm>
+         <literal><function>delete(<replaceable class="PARAMETER">tsin</replaceable> <type>tsvector</>, <replaceable class="PARAMETER">tsv_filter</replaceable> <type>tsvector</>)</function></literal>
+        </entry>
+        <entry><type>tsvector</type></entry>
+        <entry>
+          Delete lexemes and/or positions of <replaceable class="PARAMETER">tsv_filter</replaceable> from <replaceable class="PARAMETER">tsin</replaceable>.
+          When lexeme in <replaceable class="PARAMETER">tsv_filter</replaceable> has no positions function will delete any occurence of same lexeme in <replaceable class="PARAMETER">tsin</replaceable>. When <replaceable class="PARAMETER">tsv_filter</replaceable> lexeme have positions function will delete them from positions of matching lexeme in <replaceable class="PARAMETER">tsin</replaceable>. If after such removal resulting positions set is empty then function will delete that lexeme from resulting tsvector.
+        </entry>
+        <entry><literal>delete('fat:2,4 cat:3 rat:5A'::tsvector, 'fat:2,6 rat'::tsvector)</literal></entry>
+        <entry><literal>'cat':3 'fat':4</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>unnest</primary>
+         </indexterm>
+         <literal><function>unnest(<type>tsvector</>)</function></literal>
+        </entry>
+        <entry><type>setof anyelement</type></entry>
+        <entry>expand a tsvector to a set of rows. Each row has following columns: lexeme, postings, weights.</entry>
+        <entry><literal>unnest('fat:2,4 cat:3 rat:5A'::tsvector)</literal></entry>
+        <entry><literallayout class="monospaced">cat    {3}    {A}
+fat    {2,4}  {D,D}
+rat    {5}    {A}
+(3 rows)</literallayout></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>to_array</primary>
+         </indexterm>
+         <literal><function>to_array(<type>tsvector</>)</function></literal>
+        </entry>
+        <entry><type>text[]</type></entry>
+        <entry>convert <type>tsvector</> to array of lexemes</entry>
+        <entry><literal>to_array('fat:2,4 cat:3 rat:5A'::tsvector)</literal></entry>
+        <entry><literal>{cat,fat,rat}</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>array_to_tsvector</primary>
+         </indexterm>
+         <literal><function>to_tsvector(<type>text[]</>)</function></literal>
+        </entry>
+        <entry><type>tsvector</type></entry>
+        <entry>convert array of lexemes to <type>tsvector</type></entry>
+        <entry><literal>to_tsvector('{fat,cat,rat}'::text[])</literal></entry>
+        <entry><literal>'fat' 'cat' 'rat'</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>filter</primary>
+         </indexterm>
+         <literal><function>filter(<replaceable class="PARAMETER">tsin</replaceable> <type>tsvector</>, <replaceable class="PARAMETER">weights</replaceable> <type>"char"[]</>)</function></literal>
+        </entry>
+        <entry><type>tsvector</type></entry>
+        <entry>Select only elements with given <replaceable class="PARAMETER">weights</replaceable> from <replaceable class="PARAMETER">tsin</replaceable></entry>
+        <entry><literal>filter('fat:2,4 cat:3b rat:5A'::tsvector, '{a,b}')</literal></entry>
+        <entry><literal>'cat':3B 'rat':5A</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
+          <primary>shift</primary>
+         </indexterm>
+         <literal><function>shift(<replaceable class="PARAMETER">tsin</replaceable> <type>tsvector</>, <replaceable class="PARAMETER">offset</replaceable> <type>int16</>)</function></literal>
+        </entry>
+        <entry><type>tsvector</type></entry>
+        <entry>Shift all positions in <replaceable class="PARAMETER">tsin</replaceable> by given <replaceable class="PARAMETER">offset</replaceable></entry>
+        <entry><literal>shift('fat:2,4 cat:3b rat:5A'::tsvector, 10)</literal></entry>
+        <entry><literal>'cat':13B 'fat':12,14 'rat':15A</literal></entry>
+       </row>
+       <row>
+        <entry>
+         <indexterm>
           <primary>to_tsquery</primary>
          </indexterm>
          <literal><function>to_tsquery(<optional> <replaceable class="PARAMETER">config</> <type>regconfig</> , </optional> <replaceable class="PARAMETER">query</> <type>text</type>)</function></literal>
diff --git a/doc/src/sgml/textsearch.sgml b/doc/src/sgml/textsearch.sgml
index d66b4d5..32033fa 100644
--- a/doc/src/sgml/textsearch.sgml
+++ b/doc/src/sgml/textsearch.sgml
@@ -1326,6 +1326,10 @@ FROM (SELECT id, body, q, ts_rank_cd(ti, q) AS rank
 
    </variablelist>
 
+   <para>
+    Full list of <type>tsvector</>-related functions available in <xref linkend="textsearch-functions-table">.
+   </para>
+
   </sect2>
 
   <sect2 id="textsearch-manipulate-tsquery">
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index e822ba8..adc2128 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -14,6 +14,7 @@
 
 #include "postgres.h"
 
+#include "access/htup_details.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_type.h"
 #include "commands/trigger.h"
@@ -65,6 +66,7 @@ typedef struct
 #define STATHDRSIZE (offsetof(TSVectorStat, data))
 
 static Datum tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column);
+static int tsvector_bsearch(TSVector tsin, char *lexin, int lexin_len);
 
 /*
  * Order: haspos, len, word, for all positions (pos, weight)
@@ -194,6 +196,83 @@ tsvector_length(PG_FUNCTION_ARGS)
 	PG_RETURN_INT32(ret);
 }
 
+/*
+ * setweight(tsin tsvector, w "char", lexarr "text"[])
+ *
+ * Assign weight w to elements of tsin that are listed in lexarr.
+ */
+Datum
+tsvector_setweight_by_filter(PG_FUNCTION_ARGS)
+{
+	TSVector	in = PG_GETARG_TSVECTOR(0);
+	char		cw = PG_GETARG_CHAR(1);
+	ArrayType  *lexarr = NULL;
+	TSVector	out;
+	int			i,
+				j,
+				nlex = 0,
+				lex_len,
+				w = 0,
+				lex_pos;
+	WordEntry  *entry;
+	WordEntryPos *p;
+	Datum	   *dlexemes;
+	bool	   *nulls;
+	char	   *lex;
+
+	switch (cw)
+	{
+		case 'A': case 'a':
+			w = 3;
+			break;
+		case 'B': case 'b':
+			w = 2;
+			break;
+		case 'C': case 'c':
+			w = 1;
+			break;
+		case 'D': case 'd':
+			w = 0;
+			break;
+		default:
+			/* internal error */
+			elog(ERROR, "unrecognized weight: %d", cw);
+	}
+
+	out = (TSVector) palloc(VARSIZE(in));
+	memcpy(out, in, VARSIZE(in));
+	entry = ARRPTR(out);
+
+	lexarr = PG_GETARG_ARRAYTYPE_P(2);
+	deconstruct_array(lexarr, TEXTOID, -1, false, 'i',
+					  &dlexemes, &nulls, &nlex);
+
+	/*
+	 * Assuming that lexarr is significantly shorter than tsvector
+	 * we can iterate through lexarr performing binary search
+	 * of each lexeme from lexarr in tsvector.
+	 */
+	for (i = 0; i < nlex; i++)
+	{
+		lex = VARDATA(dlexemes[i]);
+		lex_len = VARSIZE_ANY_EXHDR(dlexemes[i]);
+		lex_pos = tsvector_bsearch(out, lex, lex_len);
+
+		if (lex_pos >= 0 && (j = POSDATALEN(out, entry + lex_pos)) != 0 )
+		{
+			p = POSDATAPTR(out, entry + lex_pos);
+			while (j--)
+			{
+				WEP_SETWEIGHT(*p, w);
+				p++;
+			}
+		}
+	}
+
+	PG_FREE_IF_COPY(in, 0);
+	PG_RETURN_POINTER(out);
+}
+
 Datum
 tsvector_setweight(PG_FUNCTION_ARGS)
 {
@@ -291,6 +370,635 @@ add_pos(TSVector src, WordEntry *srcptr,
 	return *clen - startlen;
 }
 
+/*
+ * Perform binary search of given lexeme in TSVector.
+ * Returns lexeme position in TSVector's entry array or -1 if lexeme wasn't
+ * found.
+ */
+static int
+tsvector_bsearch(const TSVector tsv, char *lexeme, int lexeme_len)
+{
+	WordEntry  *arrin = ARRPTR(tsv);
+	int			StopLow = 0,
+				StopHigh = tsv->size,
+				StopMiddle,
+				cmp;
+
+	while (StopLow < StopHigh)
+	{
+		StopMiddle = (StopLow + StopHigh)/2;
+
+		cmp = tsCompareString(lexeme, lexeme_len,
+			STRPTR(tsv) + arrin[StopMiddle].pos,
+			arrin[StopMiddle].len,
+			false);
+
+		if (cmp < 0)
+			StopHigh = StopMiddle;
+		else if (cmp > 0)
+			StopLow = StopMiddle + 1;
+		else /* found it */
+			return StopMiddle;
+	}
+
+	return -1;
+}
+
+static int
+compareint(const void *va, const void *vb)
+{
+	int32		a = *((const int32 *) va);
+	int32		b = *((const int32 *) vb);
+
+	if (a == b)
+		return 0;
+	return (a > b) ? 1 : -1;
+}
+
+/*
+ * Internal routine to delete lexemes from TSVector by array of offsets.
+ *
+ * int *indices_to_delete -- array of lexeme offsets to delete
+ * int indices_count -- size of that array
+ *
+ * Returns new TSVector without given lexemes along with their positions 
+ * and weights.
+ */
+static TSVector
+_tsvector_delete(TSVector tsv, int *indices_to_delete, int indices_count)
+{
+	TSVector	tsout;
+	WordEntry  *arrin = ARRPTR(tsv),
+			   *arrout;
+	char	   *data = STRPTR(tsv),
+			   *dataout;
+	int			i, j, k,
+				curoff;
+
+	/*
+	 * Here we overestimates tsout size, since we don't know exact size
+	 * occupied by positions and weights. We will set exact size later
+	 * after a pass through TSVector.
+	 */
+	tsout = (TSVector) palloc0(VARSIZE(tsv));
+	arrout = ARRPTR(tsout);
+	tsout->size = tsv->size - indices_count;
+
+	/* Sort our filter array to simplify membership check later. */
+	qsort(indices_to_delete, indices_count, sizeof(int), compareint);
+
+	/*
+	 * Copy tsv to tsout skipping lexemes that enlisted in indices_to_delete.
+	 */
+	curoff = 0;
+	dataout = STRPTR(tsout);
+	for (i = j = k = 0; i < tsv->size; i++)
+	{
+		/*
+		 * Here we should check whether current i is present in indices_to_delete
+		 * or not. Since indices_to_delete is already sorted we can advance
+		 * it index only when we have match.
+		 */
+		if (k < indices_count && i == indices_to_delete[k]){
+			k++;
+			continue;
+		}
+
+		/* Copy lexeme, it's positions and weights */
+		memcpy(dataout + curoff, data + arrin[i].pos, arrin[i].len);
+		arrout[j].haspos = arrin[i].haspos;
+		arrout[j].len = arrin[i].len;
+		arrout[j].pos = curoff;
+		curoff += arrin[i].len;
+		if (arrin[i].haspos)
+		{
+			int len = POSDATALEN(tsv, arrin+i) * sizeof(WordEntryPos) + sizeof(uint16);
+			curoff = SHORTALIGN(curoff);
+			memcpy(dataout + curoff, (STRPTR(tsv) + SHORTALIGN(arrin[i].pos + arrin[i].len)), len);
+			curoff += len;
+		}
+
+		j++;
+	}
+
+	/*
+	 * After the pass through TSVector k should equals exactly to indices_count.
+	 * If it isn't then the caller provided us with indices outside of [0, tsv->size)
+	 * range and estimation of tsout's size is wrong.
+	 */
+	Assert(k == indices_count);
+
+	SET_VARSIZE(tsout, CALCDATASIZE(tsout->size, curoff));
+	return tsout;
+}
+
+/*
+ * Delete given lexeme from tsvector.
+ * Implementation of user-level delete(tsvector, text).
+ */
+Datum
+tsvector_delete_str(PG_FUNCTION_ARGS)
+{
+	TSVector	tsin = PG_GETARG_TSVECTOR(0),
+				tsout;
+	char	   *lexin = VARDATA(PG_GETARG_TEXT_P(1));
+	int			lexin_len = VARSIZE_ANY_EXHDR(PG_GETARG_TEXT_P(1)),
+				skip_index;
+
+	if ((skip_index = tsvector_bsearch(tsin, lexin, lexin_len)) == -1)
+		PG_RETURN_POINTER(tsin);
+
+	tsout = _tsvector_delete(tsin, &skip_index, 1);
+
+	PG_FREE_IF_COPY(tsin, 0);
+	PG_RETURN_POINTER(tsout);
+}
+
+/*
+ * Delete given array of lexemes from tsvector.
+ * Implementation of user-level delete(tsvector, text[]).
+ */
+Datum
+tsvector_delete_arr(PG_FUNCTION_ARGS)
+{
+	TSVector	tsin = PG_GETARG_TSVECTOR(0),
+				tsout;
+	ArrayType  *lexarr = PG_GETARG_ARRAYTYPE_P(1);
+	int			i, nlex,
+				skip_count,
+				*skip_indices;
+	Datum	   *dlexemes;
+	bool	   *nulls;
+
+	deconstruct_array(lexarr, TEXTOID, -1, false, 'i',
+					  &dlexemes, &nulls, &nlex);
+
+	/*
+	 * In typical use case array of lexemes to delete is relatively small.
+	 * So here we optimizing things for that scenario: iterate through lexarr
+	 * performing binary search of each lexeme from lexarr in tsvector.
+	 */
+	skip_indices = palloc0(nlex*sizeof(int));
+	for (i = skip_count = 0; i < nlex; i++)
+	{
+		char *lex = VARDATA(dlexemes[i]);
+		int lex_len = VARSIZE_ANY_EXHDR(dlexemes[i]);
+		int lex_pos = tsvector_bsearch(tsin, lex, lex_len);
+
+		if (lex_pos >= 0)
+			skip_indices[skip_count++] = lex_pos;
+	}
+
+	tsout = _tsvector_delete(tsin, skip_indices, skip_count);
+
+	pfree(skip_indices);
+	PG_FREE_IF_COPY(tsin, 0);
+	PG_RETURN_POINTER(tsout);
+}
+
+/*
+ * Delete lexemes and/or positions of second tsvector from first tsvector.
+ * Implementation of user-level delete(tsvector, tsvector).
+ *
+ * When lexeme in second tsvector (ts2) has no positions function will
+ * delete any occurence of same lexeme in first tsvector (ts1).
+ * When ts2 lexeme have positions function will delete them from positions
+ * of matching lexeme in ts1. If after such removal resulting positions set is
+ * empty then function will delete that lexeme from resulting tsvector.
+ */
+Datum
+tsvector_delete_tsvector(PG_FUNCTION_ARGS)
+{
+	TSVector	ts1 = PG_GETARG_TSVECTOR(0),
+				ts2 = PG_GETARG_TSVECTOR(1),
+				tsout;
+	WordEntry  *arr1 = ARRPTR(ts1),
+			   *arr2 = ARRPTR(ts2),
+			   *arrout;
+	char	   *data1 = STRPTR(ts1),
+			   *data2 = STRPTR(ts2),
+			   *dataout;
+	int			i_out, i1, i2,
+				curoff = 0,
+				match_count = 0;
+
+	/*
+	 * As in the tsvector_delete_arr() we optimize things for case with ts2
+	 * significantly smaller than ts1, so at first we find all occurences of
+	 * ts2 lexemes in ts1.
+	 */
+	int *matched_indices = palloc0(ts2->size*sizeof(int));
+	int *matched_indices_ts2 = palloc0(ts2->size*sizeof(int));
+	for (i2 = 0; i2 < ts2->size; i2++)
+	{
+		char *lex = data2 + arr2[i2].pos;
+		int lex_len = arr2[i2].len;
+		int lex_pos = tsvector_bsearch(ts1, lex, lex_len);
+		int m;
+
+		/*
+		 * Since ts2 can contain lexemes, that are not present in ts1
+		 * we need to store both indices.
+		 * Also both those arrays should be sorted because of lexemes sorting
+		 * in tsvector.
+		 */
+		if (lex_pos >= 0){
+			m = match_count++;
+			matched_indices[m] = lex_pos;
+			matched_indices_ts2[m] = i2;
+		}
+	}
+
+	/*
+	 * In contrast to tsvector_delete_arr() and tsvector_delete_str()
+	 * here we should have logic about deleting ts2 positions info from
+	 * ts1 position. So here the same logic as in _tsvector_delete(),
+	 * but also with positions handling inside main loop.
+	 */
+	tsout = (TSVector) palloc0(VARSIZE(ts1));
+	tsout->size = ts1->size;
+	arrout = ARRPTR(tsout);
+	dataout = STRPTR(tsout);
+
+	/*
+	 * Here we use indices starting with i for iterating through tsvectors and
+	 * indices starting from j for iterating through positions.
+	 */
+	for (i_out = i1 = i2 = 0; i1 < ts1->size; i1++)
+	{
+		if (i2 < match_count && i1 == matched_indices[i2])
+		{
+			/*
+			 * Lexeme matched. If filtering vector has some positions on that
+			 * lexeme than we should delete them from filtered vector.
+			 */
+			if (arr2[matched_indices_ts2[i2]].haspos && arr1[i1].haspos)
+			{
+				WordEntryPosVector *posv1 = _POSVECPTR(ts1, arr1 + i1);
+				WordEntryPosVector *posv2 = _POSVECPTR(ts2, arr2 + matched_indices_ts2[i2]);
+				int *pos_out = palloc0(posv1->npos*sizeof(int));
+				int j1, j2, j_out;
+
+				/*
+				 * Substract (as a set) ts2 lexeme positions from ts1 lexeme positions.
+				 * Here we used the fact that both positions arrays already sorted.
+				 */
+				for(j1 = j2 = j_out = 0; j1 < posv1->npos; j1++)
+				{
+					while (j2 < posv2->npos &&
+								WEP_GETPOS(posv1->pos[j1]) > WEP_GETPOS(posv2->pos[j2]))
+						j2++;
+
+					if (WEP_GETPOS(posv1->pos[j1]) < WEP_GETPOS(posv2->pos[j2]))
+						pos_out[j_out++] = posv1->pos[j1];
+				}
+
+				/*
+				 * If result is not empty than we can copy lexeme and positions.
+				 */
+				if (j_out > 0)
+				{
+					WordEntryPosVector *posv_out;
+					int k;
+
+					memcpy(dataout + curoff, data1 + arr1[i1].pos, arr1[i1].len);
+					arrout[i_out].haspos = arr1[i1].haspos;
+					arrout[i_out].len = arr1[i1].len;
+					arrout[i_out].pos = curoff;
+
+					curoff += arr1[i1].len;
+
+					posv_out = _POSVECPTR(tsout, arrout + i_out);
+					posv_out->npos = j_out;
+					for (k = 0; k < posv_out->npos; k++)
+						posv_out->pos[k] = pos_out[k];
+					curoff = SHORTALIGN(curoff);
+					curoff += j_out * sizeof(WordEntryPos) + sizeof(uint16);
+
+					i_out++;
+				}
+
+				pfree(pos_out);
+			}
+
+			i2++;
+		}
+		else
+		{
+			/*
+			 * Not a match, we can copy lexeme and positions unchanged.
+			 */
+			memcpy(dataout + curoff, data1 + arr1[i1].pos, arr1[i1].len);
+			arrout[i_out].haspos = arr1[i1].haspos;
+			arrout[i_out].len = arr1[i1].len;
+			arrout[i_out].pos = curoff;
+			curoff += arr1[i1].len;
+			if (arr1[i1].haspos)
+			{
+				int len = POSDATALEN(ts1, arr1 + i1) * sizeof(WordEntryPos) + sizeof(uint16);
+				curoff = SHORTALIGN(curoff);
+				memcpy(dataout + curoff,
+					STRPTR(ts1) + SHORTALIGN(arr1[i1].pos + arr1[i1].len), len);
+				curoff += len;
+			}
+
+			i_out++;
+		}
+	}
+
+	tsout->size = i_out;
+	if (dataout != STRPTR(tsout))
+		memmove(STRPTR(tsout), dataout, curoff);
+
+	SET_VARSIZE(tsout, CALCDATASIZE(tsout->size, curoff));
+
+	pfree(matched_indices);
+	pfree(matched_indices_ts2);
+	PG_FREE_IF_COPY(ts1, 0);
+	PG_FREE_IF_COPY(ts2, 0);
+	PG_RETURN_POINTER(tsout);
+}
+
+/*
+ * Expand tsvector as table with following columns:
+ *     lexeme: lexeme text
+ *     positions: integer array of lexeme positions
+ *     weights: char array of weights corresponding to positions
+ */
+Datum
+tsvector_unnest(PG_FUNCTION_ARGS)
+{
+	FuncCallContext	   *funcctx;
+	TSVector			tsin = PG_GETARG_TSVECTOR(0);
+	WordEntry		   *arrin = ARRPTR(tsin);
+	char			   *data = STRPTR(tsin);
+
+	if (SRF_IS_FIRSTCALL())
+	{
+		MemoryContext oldcontext;
+		TupleDesc	tupdesc;
+
+		funcctx = SRF_FIRSTCALL_INIT();
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		tupdesc = CreateTemplateTupleDesc(3, false);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "lexeme",
+						   TEXTOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "positions",
+						   INT2ARRAYOID, -1, 0);
+		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "weights",
+						   TEXTARRAYOID, -1, 0);
+		funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	funcctx = SRF_PERCALL_SETUP();
+
+	if (funcctx->call_cntr < tsin->size)
+	{
+		HeapTuple	tuple;
+		int			j,
+					i = funcctx->call_cntr;
+		bool		nulls[] = {false, false, false};
+		Datum		values[3];
+
+		values[0] = PointerGetDatum(cstring_to_text_with_len(data + arrin[i].pos, arrin[i].len));
+
+		if (arrin[i].haspos)
+		{
+			WordEntryPosVector *posv;
+			Datum		*positions;
+			Datum		*weights;
+			char 		weight;
+
+			/*
+			 * Internally tsvector stores position and weight in the same
+			 * uint16 (2 bits for weight, 14 for position). Here we extract that
+			 * in two separate arrays.
+			 */
+			posv = _POSVECPTR(tsin, arrin + i);
+			positions = palloc(posv->npos * sizeof(Datum));
+			weights   = palloc(posv->npos * sizeof(Datum));
+			for (j = 0; j < posv->npos; j++)
+			{
+				positions[j] = Int16GetDatum(WEP_GETPOS(posv->pos[j]));
+				weight = (WEP_GETWEIGHT(posv->pos[j]) >> 2) ?
+					'D' : 'D' - WEP_GETWEIGHT(posv->pos[j]);
+				weights[j] = PointerGetDatum(cstring_to_text_with_len(&weight, 1));
+			}
+
+			values[1] = PointerGetDatum(
+				construct_array(positions, posv->npos, INT2OID, 2, true, 's'));
+			values[2] = PointerGetDatum(
+				construct_array(weights, posv->npos, TEXTOID, -1, false, 'i'));
+		}
+		else
+		{
+			values[1] = PointerGetDatum(construct_array(NULL, 0, INT2OID, 2, true, 's'));
+			values[2] = PointerGetDatum(construct_array(NULL, 0, TEXTOID, -1, false, 'i'));
+		}
+
+		tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+		PG_FREE_IF_COPY(tsin, 0);
+		SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+	}
+	else
+		SRF_RETURN_DONE(funcctx);
+}
+
+/*
+ * Convert tsvector to array of lexemes.
+ */
+Datum
+tsvector_to_array(PG_FUNCTION_ARGS)
+{
+	TSVector			tsin  = PG_GETARG_TSVECTOR(0);
+	WordEntry 		   *arrin = ARRPTR(tsin);
+	Datum				elements[tsin->size];
+	int					i;
+	ArrayType 		   *array;
+
+	for (i = 0; i < tsin->size; i++)
+	{
+		elements[i] = PointerGetDatum(
+			cstring_to_text_with_len(STRPTR(tsin) + arrin[i].pos, arrin[i].len));
+	}
+	array = construct_array(elements, tsin->size, TEXTOID, -1, false, 'i');
+	PG_FREE_IF_COPY(tsin, 0);
+	PG_RETURN_POINTER(array);
+}
+
+/*
+ * Build tsvector from array of lexemes.
+ */
+Datum
+array_to_tsvector(PG_FUNCTION_ARGS)
+{
+	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
+	TSVector	tsout;
+	Datum	   *dlexemes;
+	WordEntry  *arrout;
+	bool	   *nulls;
+	int			nitems,
+				i,
+				tslen,
+				datalen = 0;
+	char	   *cur;
+
+	deconstruct_array(v, TEXTOID, -1, false, 'i', &dlexemes, &nulls, &nitems);
+
+	for (i = 0; i < nitems; i++)
+		datalen += VARSIZE_ANY_EXHDR(dlexemes[i]);
+
+	tslen = CALCDATASIZE(nitems, datalen);
+	tsout = (TSVector) palloc0(tslen);
+	SET_VARSIZE(tsout, tslen);
+	tsout->size = nitems;
+	arrout = ARRPTR(tsout);
+	cur = STRPTR(tsout);
+
+	for (i = 0; i < nitems; i++)
+	{
+		char *lex = VARDATA(dlexemes[i]);
+		int lex_len = VARSIZE_ANY_EXHDR(dlexemes[i]);
+
+		memcpy(cur, lex, lex_len);
+		arrout[i].haspos = 0;
+		arrout[i].len = lex_len;
+		arrout[i].pos = cur - STRPTR(tsout);
+		cur += lex_len;
+	}
+
+	PG_FREE_IF_COPY(v, 0);
+	PG_RETURN_POINTER(tsout);
+}
+
+/*
+ * Leave only elements with given weights from tsvector.
+ */
+Datum
+tsvector_filter(PG_FUNCTION_ARGS)
+{
+	TSVector	tsin = PG_GETARG_TSVECTOR(0),
+				tsout;
+	ArrayType  *weights = PG_GETARG_ARRAYTYPE_P(1);
+	WordEntry  *arrin = ARRPTR(tsin),
+			   *arrout;
+	char	   *datain = STRPTR(tsin),
+			   *dataout;
+	Datum	   *dweights;
+	bool	   *nulls;
+	int			nweigths;
+	int 		i, j;
+	char 		mask = 0,
+				cur_pos = 0;
+
+	deconstruct_array(weights, CHAROID, 1, true, 'c',
+					  &dweights, &nulls, &nweigths);
+
+	for (i = 0; i < nweigths; i++)
+	{
+		char cw = DatumGetChar(dweights[i]);
+		switch (cw)
+		{
+			case 'A': case 'a':
+				mask = mask | 8;
+				break;
+			case 'B': case 'b':
+				mask = mask | 4;
+				break;
+			case 'C': case 'c':
+				mask = mask | 2;
+				break;
+			case 'D': case 'd':
+				mask = mask | 1;
+				break;
+			default:
+				/* internal error */
+				elog(ERROR, "unrecognized weight: %c", cw);
+		}
+	}
+
+	tsout = (TSVector) palloc0(VARSIZE(tsin));
+	tsout->size = tsin->size;
+	arrout = ARRPTR(tsout);
+	dataout = STRPTR(tsout);
+
+	for (i = j = 0; i < tsin->size; i++)
+	{
+		WordEntryPosVector *posvin,
+						   *posvout;
+		int npos = 0;
+		int k;
+
+		if (!arrin[i].haspos)
+			continue;
+
+		posvin  = _POSVECPTR(tsin, arrin + i);
+		posvout = (WordEntryPosVector *)(dataout + SHORTALIGN(cur_pos + arrin[i].len));
+
+		for (k = 0; k < posvin->npos; k++)
+		{
+			if (mask & (1 << WEP_GETWEIGHT(posvin->pos[k])))
+				posvout->pos[npos++] = posvin->pos[k];
+		}
+
+		if (!npos) /* no satisfactory positions found, so skip that lexeme */
+			continue;
+
+		arrout[j].haspos = true;
+		arrout[j].len = arrin[i].len;
+		arrout[j].pos = cur_pos;
+
+		memcpy(dataout + cur_pos, datain + arrin[i].pos, arrin[i].len);
+		posvout->npos = npos;
+		cur_pos += SHORTALIGN(arrin[i].len);
+		cur_pos += POSDATALEN(tsout, arrout+j) * sizeof(WordEntryPos) + sizeof(uint16);
+		j++;
+	}
+
+	tsout->size = j;
+	if (dataout != STRPTR(tsout))
+		memmove(STRPTR(tsout), dataout, cur_pos);
+
+	SET_VARSIZE(tsout, CALCDATASIZE(tsout->size, cur_pos));
+
+	PG_FREE_IF_COPY(tsin, 0);
+	PG_RETURN_POINTER(tsout);
+}
+
+/*
+ * Shift all positions in tsvector by given value.
+ */
+Datum
+tsvector_shift(PG_FUNCTION_ARGS)
+{
+	TSVector	tsin = PG_GETARG_TSVECTOR(0),
+				tsout;
+	int16 		offset = PG_GETARG_INT16(1);
+	WordEntry  *arrout;
+	int			i;
+
+	tsout = (TSVector) palloc0(VARSIZE(tsin));
+	memcpy(tsout, tsin, VARSIZE(tsin));
+	arrout = ARRPTR(tsout);
+
+	for (i = 0; i < tsout->size; i++)
+	{
+		int j, newpos;
+		WordEntryPosVector *posvout = _POSVECPTR(tsout, arrout + i);
+
+		for (j = 0; j < posvout->npos; j++)
+		{
+			newpos = LIMITPOS(WEP_GETPOS(posvout->pos[j]) + offset);
+			WEP_SETPOS(posvout->pos[j], newpos > 0 ? newpos : 0);
+		}
+	}
+
+	PG_FREE_IF_COPY(tsin, 0);
+	PG_RETURN_POINTER(tsout);
+}
 
 Datum
 tsvector_concat(PG_FUNCTION_ARGS)
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index d8640db..84604dc 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4575,8 +4575,26 @@ DESCR("number of lexemes");
 DATA(insert OID = 3623 (  strip					PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 3614 "3614" _null_ _null_ _null_ _null_ _null_ tsvector_strip _null_ _null_ _null_ ));
 DESCR("strip position information");
 DATA(insert OID = 3624 (  setweight				PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 3614 "3614 18" _null_ _null_ _null_ _null_ _null_ tsvector_setweight _null_ _null_ _null_ ));
-DESCR("set weight of lexeme's entries");
-DATA(insert OID = 3625 (  tsvector_concat		PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 3614 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_concat _null_ _null_ _null_ ));
+DESCR("set given weight for whole tsvector");
+DATA(insert OID = 3320 (  setweight				PGNSP PGUID 12 1 0  0 0 f f f f t f i s 3 0 3614 "3614 18 1009" _null_ _null_ _null_ _null_ _null_ tsvector_setweight_by_filter _null_ _null_ _null_ ));
+DESCR("set given weight for given lexemes");
+DATA(insert OID = 3625 (  tsvector_concat		PGNSP PGUID 12 1 0  0 0 f f f f t f i s 2 0 3614 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_concat _null_ _null_ _null_ ));
+DATA(insert OID = 3321 (  delete				PGNSP PGUID 12 1 0  0 0 f f f f t f i s 2 0 3614 "3614 25" _null_ _null_ _null_ _null_ _null_ tsvector_delete_str _null_ _null_ _null_ ));
+DESCR("delete lexeme");
+DATA(insert OID = 3323 (  delete				PGNSP PGUID 12 1 0  0 0 f f f f t f i s 2 0 3614 "3614 1009" _null_ _null_ _null_ _null_ _null_ tsvector_delete_arr _null_ _null_ _null_ ));
+DESCR("delete given lexemes");
+DATA(insert OID = 3324 (  delete				PGNSP PGUID 12 1 0  0 0 f f f f t f i s 2 0 3614 "3614 3614" _null_ _null_ _null_ _null_ _null_ tsvector_delete_tsvector _null_ _null_ _null_ ));
+DESCR("delete lexemes that given as tsvector");
+DATA(insert OID = 3322 (  unnest				PGNSP PGUID 12 1 10 0 0 f f f f t t i s 1 0 2249 "3614" "{3614,25,1005,1009}" "{i,o,o,o}" "{tsvector,lexeme,positions,weights}"  _null_ _null_ tsvector_unnest _null_ _null_ _null_ ));
+DESCR("expand tsvector to set of rows");
+DATA(insert OID = 3317 (  to_array				PGNSP PGUID 12 1 0  0 0 f f f f t f i s 1 0 1009 "3614" _null_ _null_ _null_ _null_ _null_ tsvector_to_array _null_ _null_ _null_ ));
+DESCR("convert to lexeme's array");
+DATA(insert OID = 3318 (  to_tsvector			PGNSP PGUID 12 1 0  0 0 f f f f t f i s 1 0 3614 "1009" _null_ _null_ _null_ _null_ _null_ array_to_tsvector _null_ _null_ _null_ ));
+DESCR("build tsvector from lexeme's array");
+DATA(insert OID = 3319 (  filter				PGNSP PGUID 12 1 0  0 0 f f f f t f i s 2 0 3614 "3614 1002" _null_ _null_ _null_ _null_ _null_ tsvector_filter _null_ _null_ _null_ ));
+DESCR("returns tsvector that contain only postings with given weights");
+DATA(insert OID = 3325 (  shift					PGNSP PGUID 12 1 0  0 0 f f f f t f i s 2 0 3614 "3614 23" _null_ _null_ _null_ _null_ _null_ tsvector_shift _null_ _null_ _null_ ));
+DESCR("shift all positions in tsvector by given value");
 
 DATA(insert OID = 3634 (  ts_match_vq			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "3614 3615" _null_ _null_ _null_ _null_ _null_ ts_match_vq _null_ _null_ _null_ ));
 DATA(insert OID = 3635 (  ts_match_qv			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "3615 3614" _null_ _null_ _null_ _null_ _null_ ts_match_qv _null_ _null_ _null_ ));
diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h
index 281cdd6..f72a718 100644
--- a/src/include/tsearch/ts_type.h
+++ b/src/include/tsearch/ts_type.h
@@ -141,7 +141,16 @@ extern Datum tsvector_cmp(PG_FUNCTION_ARGS);
 extern Datum tsvector_length(PG_FUNCTION_ARGS);
 extern Datum tsvector_strip(PG_FUNCTION_ARGS);
 extern Datum tsvector_setweight(PG_FUNCTION_ARGS);
+extern Datum tsvector_setweight_by_filter(PG_FUNCTION_ARGS);
 extern Datum tsvector_concat(PG_FUNCTION_ARGS);
+extern Datum tsvector_delete_str(PG_FUNCTION_ARGS);
+extern Datum tsvector_delete_arr(PG_FUNCTION_ARGS);
+extern Datum tsvector_delete_tsvector(PG_FUNCTION_ARGS);
+extern Datum tsvector_unnest(PG_FUNCTION_ARGS);
+extern Datum tsvector_to_array(PG_FUNCTION_ARGS);
+extern Datum array_to_tsvector(PG_FUNCTION_ARGS);
+extern Datum tsvector_filter(PG_FUNCTION_ARGS);
+extern Datum tsvector_shift(PG_FUNCTION_ARGS);
 extern Datum tsvector_update_trigger_byid(PG_FUNCTION_ARGS);
 extern Datum tsvector_update_trigger_bycolumn(PG_FUNCTION_ARGS);
 
diff --git a/src/test/regress/expected/tstypes.out b/src/test/regress/expected/tstypes.out
index 6284fb6..9c55664 100644
--- a/src/test/regress/expected/tstypes.out
+++ b/src/test/regress/expected/tstypes.out
@@ -83,18 +83,6 @@ SELECT 'a:3A b:2a'::tsvector || 'ba:1234 a:1B';
  'a':3A,4B 'b':2A 'ba':1237
 (1 row)
 
-SELECT setweight('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd zxc:81,567,222A'::tsvector, 'c');
-                        setweight                         
-----------------------------------------------------------
- 'a':1C,3C 'asd':1C 'w':5C,6C,12C,13C 'zxc':81C,222C,567C
-(1 row)
-
-SELECT strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);
-     strip     
----------------
- 'a' 'asd' 'w'
-(1 row)
-
 --Base tsquery test
 SELECT '1'::tsquery;
  tsquery 
@@ -625,3 +613,276 @@ SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a & s');
         0.1
 (1 row)
 
+-- tsvector editing operations
+SELECT strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);
+     strip     
+---------------
+ 'a' 'asd' 'w'
+(1 row)
+
+SELECT strip('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+                    strip                     
+----------------------------------------------
+ 'base' 'hidden' 'rebel' 'spaceship' 'strike'
+(1 row)
+
+SELECT strip('base hidden rebel spaceship strike'::tsvector);
+                    strip                     
+----------------------------------------------
+ 'base' 'hidden' 'rebel' 'spaceship' 'strike'
+(1 row)
+
+SELECT delete(to_tsvector('english', 'Rebel spaceships, striking from a hidden base'), 'spaceship');
+                  delete                  
+------------------------------------------
+ 'base':7 'hidden':6 'rebel':1 'strike':3
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base');
+                            delete                            
+--------------------------------------------------------------
+ 'hidden':6 'rebel':1 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'bas');
+                                delete                                 
+-----------------------------------------------------------------------
+ 'base':7 'hidden':6 'rebel':1 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'bases');
+                                delete                                 
+-----------------------------------------------------------------------
+ 'base':7 'hidden':6 'rebel':1 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship');
+                  delete                  
+------------------------------------------
+ 'base':7 'hidden':6 'rebel':1 'strike':3
+(1 row)
+
+SELECT delete('base hidden rebel spaceship strike'::tsvector, 'spaceship');
+              delete              
+----------------------------------
+ 'base' 'hidden' 'rebel' 'strike'
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceship','rebel']);
+             delete             
+--------------------------------
+ 'base':7 'hidden':6 'strike':3
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceships','rebel']);
+                           delete                            
+-------------------------------------------------------------
+ 'base':7 'hidden':6 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceshi','rebel']);
+                           delete                            
+-------------------------------------------------------------
+ 'base':7 'hidden':6 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceship','leya','rebel']);
+             delete             
+--------------------------------
+ 'base':7 'hidden':6 'strike':3
+(1 row)
+
+SELECT delete('base hidden rebel spaceship strike'::tsvector, ARRAY['spaceship','leya','rebel']);
+          delete          
+--------------------------
+ 'base' 'hidden' 'strike'
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base'::tsvector);
+                            delete                            
+--------------------------------------------------------------
+ 'hidden':6 'rebel':1 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base:7,9'::tsvector);
+                                delete                                 
+-----------------------------------------------------------------------
+ 'base':8 'hidden':6 'rebel':1 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base:7,8,9'::tsvector);
+                            delete                            
+--------------------------------------------------------------
+ 'hidden':6 'rebel':1 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base:1,7,8,9,10'::tsvector);
+                            delete                            
+--------------------------------------------------------------
+ 'hidden':6 'rebel':1 'spaceship':2,33A,34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship'::tsvector);
+                    delete                    
+----------------------------------------------
+ 'base':7,8,9 'hidden':6 'rebel':1 'strike':3
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship:2,33'::tsvector);
+                               delete                                
+---------------------------------------------------------------------
+ 'base':7,8,9 'hidden':6 'rebel':1 'spaceship':34B,35C,36 'strike':3
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship:2,33,34,35,36'::tsvector);
+                    delete                    
+----------------------------------------------
+ 'base':7,8,9 'hidden':6 'rebel':1 'strike':3
+(1 row)
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship:2B,33C,34B,35C,36B'::tsvector);
+                    delete                    
+----------------------------------------------
+ 'base':7,8,9 'hidden':6 'rebel':1 'strike':3
+(1 row)
+
+SELECT delete('base hidden rebel spaceship strike'::tsvector, 'spaceship:2 rebel'::tsvector);
+          delete          
+--------------------------
+ 'base' 'hidden' 'strike'
+(1 row)
+
+SELECT delete('cat:3 fat:2,4 rat:5A'::tsvector, 'aaa fat:2,6'::tsvector);
+          delete          
+--------------------------
+ 'cat':3 'fat':4 'rat':5A
+(1 row)
+
+SELECT unnest('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+                   unnest                    
+---------------------------------------------
+ (base,{7},{D})
+ (hidden,{6},{D})
+ (rebel,{1},{D})
+ (spaceship,"{2,33,34,35,36}","{D,A,B,C,D}")
+ (strike,{3},{D})
+(5 rows)
+
+SELECT unnest('base hidden rebel spaceship strike'::tsvector);
+      unnest       
+-------------------
+ (base,{},{})
+ (hidden,{},{})
+ (rebel,{},{})
+ (spaceship,{},{})
+ (strike,{},{})
+(5 rows)
+
+SELECT * FROM unnest('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+  lexeme   |    positions    |   weights   
+-----------+-----------------+-------------
+ base      | {7}             | {D}
+ hidden    | {6}             | {D}
+ rebel     | {1}             | {D}
+ spaceship | {2,33,34,35,36} | {D,A,B,C,D}
+ strike    | {3}             | {D}
+(5 rows)
+
+SELECT * FROM unnest('base hidden rebel spaceship strike'::tsvector);
+  lexeme   | positions | weights 
+-----------+-----------+---------
+ base      | {}        | {}
+ hidden    | {}        | {}
+ rebel     | {}        | {}
+ spaceship | {}        | {}
+ strike    | {}        | {}
+(5 rows)
+
+SELECT lexeme, positions[1] from unnest('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+  lexeme   | positions 
+-----------+-----------
+ base      |         7
+ hidden    |         6
+ rebel     |         1
+ spaceship |         2
+ strike    |         3
+(5 rows)
+
+SELECT to_array('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+               to_array               
+--------------------------------------
+ {base,hidden,rebel,spaceship,strike}
+(1 row)
+
+SELECT to_array('base hidden rebel spaceship strike'::tsvector);
+               to_array               
+--------------------------------------
+ {base,hidden,rebel,spaceship,strike}
+(1 row)
+
+SELECT to_tsvector(ARRAY['base','hidden','rebel','spaceship','strike']);
+                 to_tsvector                  
+----------------------------------------------
+ 'base' 'hidden' 'rebel' 'spaceship' 'strike'
+(1 row)
+
+SELECT setweight('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd zxc:81,567,222A'::tsvector, 'c');
+                        setweight                         
+----------------------------------------------------------
+ 'a':1C,3C 'asd':1C 'w':5C,6C,12C,13C 'zxc':81C,222C,567C
+(1 row)
+
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c');
+                        setweight                         
+----------------------------------------------------------
+ 'a':1C,3C 'asd':1C 'w':5C,6C,12C,13C 'zxc':81C,222C,567C
+(1 row)
+
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c', '{a}');
+                      setweight                       
+------------------------------------------------------
+ 'a':1C,3C 'asd':1C 'w':5,6,12B,13A 'zxc':81,222A,567
+(1 row)
+
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c', '{a}');
+                      setweight                       
+------------------------------------------------------
+ 'a':1C,3C 'asd':1C 'w':5,6,12B,13A 'zxc':81,222A,567
+(1 row)
+
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c', '{a,zxc}');
+                       setweight                        
+--------------------------------------------------------
+ 'a':1C,3C 'asd':1C 'w':5,6,12B,13A 'zxc':81C,222C,567C
+(1 row)
+
+SELECT setweight('a asd w:5,6,12B,13A zxc'::tsvector, 'c', '{a,zxc}');
+            setweight            
+---------------------------------
+ 'a' 'asd' 'w':5,6,12B,13A 'zxc'
+(1 row)
+
+SELECT filter('base:7A empir:17 evil:15 first:11 galact:16 hidden:6A rebel:1A spaceship:2A strike:3A victori:12 won:9'::tsvector, '{a}');
+                           filter                            
+-------------------------------------------------------------
+ 'base':7A 'hidden':6A 'rebel':1A 'spaceship':2A 'strike':3A
+(1 row)
+
+SELECT filter('base hidden rebel spaceship strike'::tsvector, '{a}');
+ filter 
+--------
+ 
+(1 row)
+
+SELECT shift('fat:2,4 cat:3 rat:5A'::tsvector, 10);
+             shift              
+--------------------------------
+ 'cat':13 'fat':12,14 'rat':15A
+(1 row)
+
+SELECT shift('fat:2,4 cat:3 rat:5A'::tsvector, -3);
+           shift            
+----------------------------
+ 'cat':0 'fat':0,1 'rat':2A
+(1 row)
+
diff --git a/src/test/regress/sql/tstypes.sql b/src/test/regress/sql/tstypes.sql
index fd7c702..52a1923 100644
--- a/src/test/regress/sql/tstypes.sql
+++ b/src/test/regress/sql/tstypes.sql
@@ -14,8 +14,6 @@ SELECT $$'\\as' ab\c ab\\c AB\\\c ab\\\\c$$::tsvector;
 SELECT tsvectorin(tsvectorout($$'\\as' ab\c ab\\c AB\\\c ab\\\\c$$::tsvector));
 SELECT '''w'':4A,3B,2C,1D,5 a:8';
 SELECT 'a:3A b:2a'::tsvector || 'ba:1234 a:1B';
-SELECT setweight('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd zxc:81,567,222A'::tsvector, 'c');
-SELECT strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);
 
 --Base tsquery test
 SELECT '1'::tsquery;
@@ -115,3 +113,58 @@ SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a | s');
 SELECT ts_rank_cd(' a:1 s:2C d g'::tsvector, 'a & s');
 SELECT ts_rank_cd(' a:1 s:2B d g'::tsvector, 'a & s');
 SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a & s');
+
+-- tsvector editing operations
+
+SELECT strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);
+SELECT strip('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+SELECT strip('base hidden rebel spaceship strike'::tsvector);
+
+SELECT delete(to_tsvector('english', 'Rebel spaceships, striking from a hidden base'), 'spaceship');
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base');
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'bas');
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'bases');
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship');
+SELECT delete('base hidden rebel spaceship strike'::tsvector, 'spaceship');
+
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceship','rebel']);
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceships','rebel']);
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceshi','rebel']);
+SELECT delete('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, ARRAY['spaceship','leya','rebel']);
+SELECT delete('base hidden rebel spaceship strike'::tsvector, ARRAY['spaceship','leya','rebel']);
+
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base'::tsvector);
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base:7,9'::tsvector);
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base:7,8,9'::tsvector);
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'base:1,7,8,9,10'::tsvector);
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship'::tsvector);
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship:2,33'::tsvector);
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship:2,33,34,35,36'::tsvector);
+SELECT delete('base:7,8,9 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector, 'spaceship:2B,33C,34B,35C,36B'::tsvector);
+SELECT delete('base hidden rebel spaceship strike'::tsvector, 'spaceship:2 rebel'::tsvector);
+SELECT delete('cat:3 fat:2,4 rat:5A'::tsvector, 'aaa fat:2,6'::tsvector);
+
+SELECT unnest('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+SELECT unnest('base hidden rebel spaceship strike'::tsvector);
+SELECT * FROM unnest('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+SELECT * FROM unnest('base hidden rebel spaceship strike'::tsvector);
+SELECT lexeme, positions[1] from unnest('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+
+SELECT to_array('base:7 hidden:6 rebel:1 spaceship:2,33A,34B,35C,36D strike:3'::tsvector);
+SELECT to_array('base hidden rebel spaceship strike'::tsvector);
+
+SELECT to_tsvector(ARRAY['base','hidden','rebel','spaceship','strike']);
+
+SELECT setweight('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd zxc:81,567,222A'::tsvector, 'c');
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c');
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c', '{a}');
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c', '{a}');
+SELECT setweight('a:1,3A asd:1C w:5,6,12B,13A zxc:81,222A,567'::tsvector, 'c', '{a,zxc}');
+SELECT setweight('a asd w:5,6,12B,13A zxc'::tsvector, 'c', '{a,zxc}');
+
+SELECT filter('base:7A empir:17 evil:15 first:11 galact:16 hidden:6A rebel:1A spaceship:2A strike:3A victori:12 won:9'::tsvector, '{a}');
+SELECT filter('base hidden rebel spaceship strike'::tsvector, '{a}');
+
+SELECT shift('fat:2,4 cat:3 rat:5A'::tsvector, 10);
+SELECT shift('fat:2,4 cat:3 rat:5A'::tsvector, -3);
+
