From 5229a8407d48d1d4fadc765819bb6eded1f680d0 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Sat, 1 Apr 2023 16:32:37 +0300
Subject: [PATCH v6 04/11] Implement read-only dot notation for hstore

---
 contrib/hstore/expected/hstore.out | 14 +++++++++++++-
 contrib/hstore/hstore_subs.c       | 25 ++++++++++++++++++-------
 contrib/hstore/sql/hstore.sql      |  2 ++
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out
index 9e2421750fb..3dd2b2d7283 100644
--- a/contrib/hstore/expected/hstore.out
+++ b/contrib/hstore/expected/hstore.out
@@ -1604,12 +1604,20 @@ select f2['d'], f2['x'] is null as x_isnull from test_json_agg;
         | t
 (3 rows)
 
+select (f2).d, (f2).x is null as x_isnull from test_json_agg;
+   d    | x_isnull 
+--------+----------
+ 12345  | t
+ -12345 | t
+        | t
+(3 rows)
+
 select f2['d']['e'] from test_json_agg;  -- error
 ERROR:  cannot subscript type text because it does not support subscripting
 LINE 1: select f2['d']['e'] from test_json_agg;
                ^
 select f2['d':'e'] from test_json_agg;  -- error
-ERROR:  hstore allows only one subscript
+ERROR:  hstore does not support slicing
 update test_json_agg set f2['d'] = f2['e'], f2['x'] = 'xyzzy';
 select f2 from test_json_agg;
                                                          f2                                                          
@@ -1619,6 +1627,10 @@ select f2 from test_json_agg;
  "d"=>NULL, "x"=>"xyzzy"
 (3 rows)
 
+update test_json_agg set f2.d = (f2).x, f2."123" = 'aaa';
+ERROR:  cannot assign to field "d" of column "f2" because its type hstore is not a composite type
+LINE 1: update test_json_agg set f2.d = (f2).x, f2."123" = 'aaa';
+                                 ^
 -- Test subscripting in plpgsql
 do $$ declare h hstore;
 begin h['a'] := 'b'; raise notice 'h = %, h[a] = %', h, h['a']; end $$;
diff --git a/contrib/hstore/hstore_subs.c b/contrib/hstore/hstore_subs.c
index 304cee8c024..7c106c2268e 100644
--- a/contrib/hstore/hstore_subs.c
+++ b/contrib/hstore/hstore_subs.c
@@ -25,6 +25,7 @@
 
 #include "executor/execExpr.h"
 #include "hstore.h"
+#include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "nodes/subscripting.h"
 #include "parser/parse_coerce.h"
@@ -48,18 +49,22 @@ hstore_subscript_transform(SubscriptingRef *sbsref,
 	Node	   *ind = linitial(*indirection);
 	Node	   *subexpr;
 
-	/* We support only single-subscript, non-slice cases */
-	if (isSlice || list_length(*indirection) < 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("hstore allows only one subscript"),
-				 parser_errposition(pstate,
-									exprLocation((Node *) *indirection))));
+	if (!*indirection)
+		return;
 
 	if (IsA(ind, A_Indices))
 	{
 		A_Indices  *ai = castNode(A_Indices, ind);
 
+		/* We support only single-subscript, non-slice cases */
+		if (ai->is_slice)
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("hstore does not support slicing"),
+					 parser_errposition(pstate,
+										exprLocation((Node *) *indirection))));
+
+
 		/* Transform the subscript expression to type text */
 		ai = linitial_node(A_Indices, *indirection);
 		Assert(ai->uidx != NULL && ai->lidx == NULL && !ai->is_slice);
@@ -78,6 +83,12 @@ hstore_subscript_transform(SubscriptingRef *sbsref,
 					 errmsg("hstore subscript must have type text"),
 					 parser_errposition(pstate, exprLocation(ai->uidx))));
 	}
+	else if (IsA(ind, String))
+	{
+		Datum		field_txt = CStringGetTextDatum(strVal(ind));
+
+		subexpr = (Node *) makeConst(TEXTOID, -1, InvalidOid, -1, field_txt, false, false);
+	}
 	else
 		return;
 
diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql
index efef91292a3..0502a63a27e 100644
--- a/contrib/hstore/sql/hstore.sql
+++ b/contrib/hstore/sql/hstore.sql
@@ -378,10 +378,12 @@ select json_agg(q) from (select f1, hstore_to_json_loose(f2) as f2 from test_jso
 -- Test subscripting
 insert into test_json_agg default values;
 select f2['d'], f2['x'] is null as x_isnull from test_json_agg;
+select (f2).d, (f2).x is null as x_isnull from test_json_agg;
 select f2['d']['e'] from test_json_agg;  -- error
 select f2['d':'e'] from test_json_agg;  -- error
 update test_json_agg set f2['d'] = f2['e'], f2['x'] = 'xyzzy';
 select f2 from test_json_agg;
+update test_json_agg set f2.d = (f2).x, f2."123" = 'aaa';
 
 -- Test subscripting in plpgsql
 do $$ declare h hstore;
-- 
2.25.1

