commit b7e56144366a0b97ddd0a77c06aac9e6051b5f5a
Author: Joel Jakobsson <joel@compiler.org>
Date:   Tue Jun 27 09:39:15 2023 +0200

    Align null semantics with SQL:2023 array and multiset standards
    
    * Introduced a new boolean field, null_element, in the int4hashset_t type.
    
    * Rename hashset_count() to hashset_cardinality().
    
    * Rename hashset_merge() to hashset_union().
    
    * Rename hashset_equals() to hashset_eq().
    
    * Rename hashset_neq() to hashset_ne().
    
    * Add hashset_to_sorted_array().
    
    * Handle null semantics to work as in arrays and multisets.
    
    * Update int4hashset_add() to allow creating a new set if none exists.
    
    * Use more portable int32 typedef instead of int32_t.
    
    This also adds a thorough test suite in array-and-multiset-semantics.sql,
    which aims to test all relevant combinations of operations and values.

diff --git a/Makefile b/Makefile
index cfb8362..ee62511 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ SERVER_INCLUDES=-I$(shell pg_config --includedir-server)
 CLIENT_INCLUDES=-I$(shell pg_config --includedir)
 LIBRARY_PATH = -L$(shell pg_config --libdir)
 
-REGRESS = prelude basic io_varying_lengths random table invalid parsing reported_bugs strict
+REGRESS = prelude basic io_varying_lengths random table invalid parsing reported_bugs array-and-multiset-semantics
 REGRESS_OPTS = --inputdir=test
 
 PG_CONFIG = pg_config
diff --git a/README.md b/README.md
index 9c26cf6..91af6ee 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ UPDATE users SET user_likes = hashset_add(user_likes, 202) WHERE user_id = 1;
 SELECT hashset_contains(user_likes, 101) FROM users WHERE user_id = 1; -- true
 
 -- Count the number of likes a user has
-SELECT hashset_count(user_likes) FROM users WHERE user_id = 1; -- 2
+SELECT hashset_cardinality(user_likes) FROM users WHERE user_id = 1; -- 2
 ```
 
 You can also use the aggregate functions to perform operations on multiple rows.
@@ -75,9 +75,9 @@ a variable-length type.
         - 3=Naive hash function
 - `hashset_add(int4hashset, int) -> int4hashset`: Adds an integer to an int4hashset.
 - `hashset_contains(int4hashset, int) -> boolean`: Checks if an int4hashset contains a given integer.
-- `hashset_merge(int4hashset, int4hashset) -> int4hashset`: Merges two int4hashsets into a new int4hashset.
+- `hashset_union(int4hashset, int4hashset) -> int4hashset`: Merges two int4hashsets into a new int4hashset.
 - `hashset_to_array(int4hashset) -> int[]`: Converts an int4hashset to an array of integers.
-- `hashset_count(int4hashset) -> bigint`: Returns the number of elements in an int4hashset.
+- `hashset_cardinality(int4hashset) -> bigint`: Returns the number of elements in an int4hashset.
 - `hashset_capacity(int4hashset) -> bigint`: Returns the current capacity of an int4hashset.
 - `hashset_max_collisions(int4hashset) -> bigint`: Returns the maximum number of collisions that have occurred for a single element
 - `hashset_intersection(int4hashset, int4hashset) -> int4hashset`: Returns a new int4hashset that is the intersection of the two input sets.
diff --git a/hashset--0.0.1.sql b/hashset--0.0.1.sql
index d48260f..d0478ce 100644
--- a/hashset--0.0.1.sql
+++ b/hashset--0.0.1.sql
@@ -50,16 +50,16 @@ LANGUAGE C IMMUTABLE;
 CREATE OR REPLACE FUNCTION hashset_add(int4hashset, int)
 RETURNS int4hashset
 AS 'hashset', 'int4hashset_add'
-LANGUAGE C IMMUTABLE STRICT;
+LANGUAGE C IMMUTABLE;
 
 CREATE OR REPLACE FUNCTION hashset_contains(int4hashset, int)
-RETURNS bool
+RETURNS boolean
 AS 'hashset', 'int4hashset_contains'
-LANGUAGE C IMMUTABLE STRICT;
+LANGUAGE C IMMUTABLE;
 
-CREATE OR REPLACE FUNCTION hashset_merge(int4hashset, int4hashset)
+CREATE OR REPLACE FUNCTION hashset_union(int4hashset, int4hashset)
 RETURNS int4hashset
-AS 'hashset', 'int4hashset_merge'
+AS 'hashset', 'int4hashset_union'
 LANGUAGE C IMMUTABLE STRICT;
 
 CREATE OR REPLACE FUNCTION hashset_to_array(int4hashset)
@@ -67,9 +67,14 @@ RETURNS int[]
 AS 'hashset', 'int4hashset_to_array'
 LANGUAGE C IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION hashset_count(int4hashset)
+CREATE OR REPLACE FUNCTION hashset_to_sorted_array(int4hashset)
+RETURNS int[]
+AS 'hashset', 'int4hashset_to_sorted_array'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE OR REPLACE FUNCTION hashset_cardinality(int4hashset)
 RETURNS bigint
-AS 'hashset', 'int4hashset_count'
+AS 'hashset', 'int4hashset_cardinality'
 LANGUAGE C IMMUTABLE STRICT;
 
 CREATE OR REPLACE FUNCTION hashset_capacity(int4hashset)
@@ -162,28 +167,28 @@ CREATE AGGREGATE hashset_agg(int4hashset) (
  * Operator Definitions
  */
 
-CREATE OR REPLACE FUNCTION hashset_equals(int4hashset, int4hashset)
-RETURNS bool
-AS 'hashset', 'int4hashset_equals'
+CREATE OR REPLACE FUNCTION hashset_eq(int4hashset, int4hashset)
+RETURNS boolean
+AS 'hashset', 'int4hashset_eq'
 LANGUAGE C IMMUTABLE STRICT;
 
 CREATE OPERATOR = (
     LEFTARG = int4hashset,
     RIGHTARG = int4hashset,
-    PROCEDURE = hashset_equals,
+    PROCEDURE = hashset_eq,
     COMMUTATOR = =,
     HASHES
 );
 
-CREATE OR REPLACE FUNCTION hashset_neq(int4hashset, int4hashset)
-RETURNS bool
-AS 'hashset', 'int4hashset_neq'
+CREATE OR REPLACE FUNCTION hashset_ne(int4hashset, int4hashset)
+RETURNS boolean
+AS 'hashset', 'int4hashset_ne'
 LANGUAGE C IMMUTABLE STRICT;
 
 CREATE OPERATOR <> (
     LEFTARG = int4hashset,
     RIGHTARG = int4hashset,
-    PROCEDURE = hashset_neq,
+    PROCEDURE = hashset_ne,
     COMMUTATOR = '<>',
     NEGATOR = '=',
     RESTRICT = neqsel,
@@ -224,7 +229,7 @@ FUNCTION 1 hashset_hash(int4hashset);
  */
 
 CREATE OR REPLACE FUNCTION hashset_lt(int4hashset, int4hashset)
-RETURNS bool
+RETURNS boolean
 AS 'hashset', 'int4hashset_lt'
 LANGUAGE C IMMUTABLE STRICT;
 
diff --git a/hashset-api.c b/hashset-api.c
index e00ef0c..a4beef4 100644
--- a/hashset-api.c
+++ b/hashset-api.c
@@ -18,8 +18,8 @@ PG_FUNCTION_INFO_V1(int4hashset_send);
 PG_FUNCTION_INFO_V1(int4hashset_recv);
 PG_FUNCTION_INFO_V1(int4hashset_add);
 PG_FUNCTION_INFO_V1(int4hashset_contains);
-PG_FUNCTION_INFO_V1(int4hashset_count);
-PG_FUNCTION_INFO_V1(int4hashset_merge);
+PG_FUNCTION_INFO_V1(int4hashset_cardinality);
+PG_FUNCTION_INFO_V1(int4hashset_union);
 PG_FUNCTION_INFO_V1(int4hashset_init);
 PG_FUNCTION_INFO_V1(int4hashset_capacity);
 PG_FUNCTION_INFO_V1(int4hashset_collisions);
@@ -29,8 +29,9 @@ PG_FUNCTION_INFO_V1(int4hashset_agg_add_set);
 PG_FUNCTION_INFO_V1(int4hashset_agg_final);
 PG_FUNCTION_INFO_V1(int4hashset_agg_combine);
 PG_FUNCTION_INFO_V1(int4hashset_to_array);
-PG_FUNCTION_INFO_V1(int4hashset_equals);
-PG_FUNCTION_INFO_V1(int4hashset_neq);
+PG_FUNCTION_INFO_V1(int4hashset_to_sorted_array);
+PG_FUNCTION_INFO_V1(int4hashset_eq);
+PG_FUNCTION_INFO_V1(int4hashset_ne);
 PG_FUNCTION_INFO_V1(int4hashset_hash);
 PG_FUNCTION_INFO_V1(int4hashset_lt);
 PG_FUNCTION_INFO_V1(int4hashset_le);
@@ -47,8 +48,8 @@ Datum int4hashset_send(PG_FUNCTION_ARGS);
 Datum int4hashset_recv(PG_FUNCTION_ARGS);
 Datum int4hashset_add(PG_FUNCTION_ARGS);
 Datum int4hashset_contains(PG_FUNCTION_ARGS);
-Datum int4hashset_count(PG_FUNCTION_ARGS);
-Datum int4hashset_merge(PG_FUNCTION_ARGS);
+Datum int4hashset_cardinality(PG_FUNCTION_ARGS);
+Datum int4hashset_union(PG_FUNCTION_ARGS);
 Datum int4hashset_init(PG_FUNCTION_ARGS);
 Datum int4hashset_capacity(PG_FUNCTION_ARGS);
 Datum int4hashset_collisions(PG_FUNCTION_ARGS);
@@ -58,8 +59,9 @@ Datum int4hashset_agg_add_set(PG_FUNCTION_ARGS);
 Datum int4hashset_agg_final(PG_FUNCTION_ARGS);
 Datum int4hashset_agg_combine(PG_FUNCTION_ARGS);
 Datum int4hashset_to_array(PG_FUNCTION_ARGS);
-Datum int4hashset_equals(PG_FUNCTION_ARGS);
-Datum int4hashset_neq(PG_FUNCTION_ARGS);
+Datum int4hashset_to_sorted_array(PG_FUNCTION_ARGS);
+Datum int4hashset_eq(PG_FUNCTION_ARGS);
+Datum int4hashset_ne(PG_FUNCTION_ARGS);
 Datum int4hashset_hash(PG_FUNCTION_ARGS);
 Datum int4hashset_lt(PG_FUNCTION_ARGS);
 Datum int4hashset_le(PG_FUNCTION_ARGS);
@@ -114,33 +116,42 @@ int4hashset_in(PG_FUNCTION_ARGS)
 			break;
 		}
 
-		/* Parse the number */
-		value = strtol(str, &endptr, 10);
-
-		if (errno == ERANGE || value < PG_INT32_MIN || value > PG_INT32_MAX)
+		/* Check if "null" is encountered (case-insensitive) */
+		if (strncasecmp(str, "null", 4) == 0)
 		{
-			ereport(ERROR,
-					(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-					errmsg("value \"%s\" is out of range for type %s", str,
-							"integer")));
+			set->null_element = true;
+			str = str + 4; /* Move past "null" */
 		}
-
-		/* Add the value to the hashset, resize if needed */
-		if (set->nelements >= set->capacity)
+		else
 		{
-			set = int4hashset_resize(set);
-		}
-		set = int4hashset_add_element(set, (int32)value);
+			/* Parse the number */
+			value = strtol(str, &endptr, 10);
 
-		/* Error handling for strtol */
-		if (endptr == str)
-		{
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-					errmsg("invalid input syntax for integer: \"%s\"", str)));
-		}
+			if (errno == ERANGE || value < PG_INT32_MIN || value > PG_INT32_MAX)
+			{
+				ereport(ERROR,
+						(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+						errmsg("value \"%s\" is out of range for type %s", str,
+								"integer")));
+			}
+
+			/* Add the value to the hashset, resize if needed */
+			if (set->nelements >= set->capacity)
+			{
+				set = int4hashset_resize(set);
+			}
+			set = int4hashset_add_element(set, (int32)value);
 
-		str = endptr; /* Move to next potential number or closing brace */
+			/* Error handling for strtol */
+			if (endptr == str)
+			{
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+						errmsg("invalid input syntax for integer: \"%s\"", str)));
+			}
+
+			str = endptr; /* Move to next number, "null" or closing brace */
+		}
 
         /* Skip spaces before the next number or closing brace */
 		while (hashset_isspace(*str)) str++;
@@ -209,6 +220,14 @@ int4hashset_out(PG_FUNCTION_ARGS)
 		}
 	}
 
+	/* Check if the null_element field is set */
+	if (set->null_element)
+	{
+		if (str.len > 1)
+			appendStringInfoChar(&str, ',');
+		appendStringInfoString(&str, "NULL");
+	}
+
 	/* Append the closing brace for the output hashset string */
 	appendStringInfoChar(&str, '}');
 
@@ -240,6 +259,7 @@ int4hashset_send(PG_FUNCTION_ARGS)
 	pq_sendint32(&buf, set->ncollisions);
 	pq_sendint32(&buf, set->max_collisions);
 	pq_sendint32(&buf, set->hash);
+    pq_sendbyte(&buf, set->null_element ? 1 : 0);
 
 	/* Compute and send the size of the data field */
 	data_size = VARSIZE(set) - offsetof(int4hashset_t, data);
@@ -266,6 +286,7 @@ int4hashset_recv(PG_FUNCTION_ARGS)
 	int32			ncollisions;
 	int32			max_collisions;
 	int32			hash;
+	bool			null_element;
 
 	version = pq_getmsgint(buf, 1);
 	if (version != 1)
@@ -281,6 +302,7 @@ int4hashset_recv(PG_FUNCTION_ARGS)
 	ncollisions = pq_getmsgint(buf, 4);
 	max_collisions = pq_getmsgint(buf, 4);
 	hash = pq_getmsgint(buf, 4);
+	null_element = pq_getmsgbyte(buf) == 1;
 
 	/* Compute the size of the data field */
 	data_size = buf->len - buf->cursor;
@@ -310,6 +332,7 @@ int4hashset_recv(PG_FUNCTION_ARGS)
 	set->ncollisions = ncollisions;
 	set->max_collisions = max_collisions;
 	set->hash = hash;
+	set->null_element = null_element;
 	memcpy(set->data, binary_data, data_size);
 
 	PG_RETURN_POINTER(set);
@@ -318,10 +341,31 @@ int4hashset_recv(PG_FUNCTION_ARGS)
 Datum
 int4hashset_add(PG_FUNCTION_ARGS)
 {
-	int4hashset_t *set = int4hashset_add_element(
-		PG_GETARG_INT4HASHSET_COPY(0),
-		PG_GETARG_INT32(1)
-	);
+	int4hashset_t *set;
+	/* If there's no hashset allocated, create it now */
+	if (PG_ARGISNULL(0))
+	{
+		set = int4hashset_allocate(
+				DEFAULT_INITIAL_CAPACITY,
+				DEFAULT_LOAD_FACTOR,
+				DEFAULT_GROWTH_FACTOR,
+				DEFAULT_HASHFN_ID
+		);
+	}
+	else
+	{
+		set = PG_GETARG_INT4HASHSET_COPY(0);
+	}
+
+	if (PG_ARGISNULL(1))
+	{
+		set->null_element = true;
+	}
+	else
+	{
+		int32 element = PG_GETARG_INT32(1);
+		set = int4hashset_add_element(set, element);
+	}
 
 	PG_RETURN_POINTER(set);
 }
@@ -329,28 +373,47 @@ int4hashset_add(PG_FUNCTION_ARGS)
 Datum
 int4hashset_contains(PG_FUNCTION_ARGS)
 {
-	int4hashset_t  *set = PG_GETARG_INT4HASHSET(0);
-	int32			value = PG_GETARG_INT32(1);
+	int4hashset_t  *set;
+	int32			value;
+	bool			result;
 
-	PG_RETURN_BOOL(int4hashset_contains_element(set, value));
+	if (PG_ARGISNULL(0))
+		PG_RETURN_NULL();
+
+	set = PG_GETARG_INT4HASHSET(0);
+
+	if (set->nelements == 0 && !set->null_element)
+		PG_RETURN_BOOL(false);
+
+	if (PG_ARGISNULL(1))
+		PG_RETURN_NULL();
+
+	value = PG_GETARG_INT32(1);
+	result = int4hashset_contains_element(set, value);
+
+	if (!result && set->null_element)
+		PG_RETURN_NULL();
+
+	PG_RETURN_BOOL(result);
 }
 
 Datum
-int4hashset_count(PG_FUNCTION_ARGS)
+int4hashset_cardinality(PG_FUNCTION_ARGS)
 {
 	int4hashset_t	*set = PG_GETARG_INT4HASHSET(0);
+	int64			 cardinality = set->nelements + (set->null_element ? 1 : 0);
 
-	PG_RETURN_INT64(set->nelements);
+	PG_RETURN_INT64(cardinality);
 }
 
 Datum
-int4hashset_merge(PG_FUNCTION_ARGS)
+int4hashset_union(PG_FUNCTION_ARGS)
 {
 	int				i;
 	int4hashset_t  *seta = PG_GETARG_INT4HASHSET_COPY(0);
 	int4hashset_t  *setb = PG_GETARG_INT4HASHSET(1);
 	char		   *bitmap = setb->data;
-	int32_t		   *values = (int32 *) (bitmap + CEIL_DIV(setb->capacity, 8));
+	int32		   *values = (int32 *) (bitmap + CEIL_DIV(setb->capacity, 8));
 
 	for (i = 0; i < setb->capacity; i++)
 	{
@@ -361,6 +424,9 @@ int4hashset_merge(PG_FUNCTION_ARGS)
 			seta = int4hashset_add_element(seta, values[i]);
 	}
 
+	if (!seta->null_element && setb->null_element)
+		seta->null_element = true;
+
 	PG_RETURN_POINTER(seta);
 }
 
@@ -629,6 +695,12 @@ int4hashset_to_array(PG_FUNCTION_ARGS)
 
 	set = PG_GETARG_INT4HASHSET(0);
 
+	/* if hashset is empty and does not contain null, return an empty array */
+	if(set->nelements == 0 && !set->null_element) {
+		Datum d = PointerGetDatum(construct_empty_array(INT4OID));
+		PG_RETURN_ARRAYTYPE_P(d);
+	}
+
 	sbitmap = set->data;
 	svalues = (int32 *) (set->data + CEIL_DIV(set->capacity, 8));
 
@@ -648,11 +720,35 @@ int4hashset_to_array(PG_FUNCTION_ARGS)
 
 	Assert(idx == nvalues);
 
-	return int32_to_array(fcinfo, values, nvalues);
+	return int32_to_array(fcinfo, values, nvalues, set->null_element);
 }
 
 Datum
-int4hashset_equals(PG_FUNCTION_ARGS)
+int4hashset_to_sorted_array(PG_FUNCTION_ARGS)
+{
+	int4hashset_t	   *set;
+	int32			   *values;
+	int					nvalues;
+
+	set = PG_GETARG_INT4HASHSET(0);
+
+	/* if hashset is empty and does not contain null, return an empty array */
+	if(set->nelements == 0 && !set->null_element) {
+		Datum d = PointerGetDatum(construct_empty_array(INT4OID));
+		PG_RETURN_ARRAYTYPE_P(d);
+	}
+
+	/* extract the sorted elements from the hashset */
+	values = int4hashset_extract_sorted_elements(set);
+
+	/* number of values to store in the array */
+	nvalues = set->nelements;
+
+	return int32_to_array(fcinfo, values, nvalues, set->null_element);
+}
+
+Datum
+int4hashset_eq(PG_FUNCTION_ARGS)
 {
 	int				i;
 	int4hashset_t  *a = PG_GETARG_INT4HASHSET(0);
@@ -686,6 +782,9 @@ int4hashset_equals(PG_FUNCTION_ARGS)
 		}
 	}
 
+	if (a->null_element != b->null_element)
+		PG_RETURN_BOOL(false);
+
 	/*
 	 * All elements in a are in b and the number of elements is the same,
 	 * so the sets must be equal.
@@ -695,13 +794,13 @@ int4hashset_equals(PG_FUNCTION_ARGS)
 
 
 Datum
-int4hashset_neq(PG_FUNCTION_ARGS)
+int4hashset_ne(PG_FUNCTION_ARGS)
 {
     int4hashset_t *a = PG_GETARG_INT4HASHSET(0);
     int4hashset_t *b = PG_GETARG_INT4HASHSET(1);
 
     /* If a is not equal to b, then they are not equal */
-    if (!DatumGetBool(DirectFunctionCall2(int4hashset_equals, PointerGetDatum(a), PointerGetDatum(b))))
+    if (!DatumGetBool(DirectFunctionCall2(int4hashset_eq, PointerGetDatum(a), PointerGetDatum(b))))
         PG_RETURN_BOOL(true);
 
     PG_RETURN_BOOL(false);
@@ -842,7 +941,7 @@ int4hashset_intersection(PG_FUNCTION_ARGS)
 	int4hashset_t  *seta = PG_GETARG_INT4HASHSET(0);
 	int4hashset_t  *setb = PG_GETARG_INT4HASHSET(1);
 	char		   *bitmap = setb->data;
-	int32_t		   *values = (int32_t *)(bitmap + CEIL_DIV(setb->capacity, 8));
+	int32		   *values = (int32 *)(bitmap + CEIL_DIV(setb->capacity, 8));
 	int4hashset_t  *intersection;
 
 	intersection = int4hashset_allocate(
@@ -864,6 +963,9 @@ int4hashset_intersection(PG_FUNCTION_ARGS)
 		}
 	}
 
+	if (seta->null_element && setb->null_element)
+		intersection->null_element = true;
+
 	PG_RETURN_POINTER(intersection);
 }
 
@@ -875,7 +977,7 @@ int4hashset_difference(PG_FUNCTION_ARGS)
 	int4hashset_t	*setb = PG_GETARG_INT4HASHSET(1);
 	int4hashset_t	*difference;
 	char			*bitmap = seta->data;
-	int32_t			*values = (int32_t *)(bitmap + CEIL_DIV(seta->capacity, 8));
+	int32			*values = (int32 *)(bitmap + CEIL_DIV(seta->capacity, 8));
 
 	difference = int4hashset_allocate(
 		seta->capacity,
@@ -896,6 +998,9 @@ int4hashset_difference(PG_FUNCTION_ARGS)
 		}
 	}
 
+	if (seta->null_element && !setb->null_element)
+		difference->null_element = true;
+
 	PG_RETURN_POINTER(difference);
 }
 
@@ -908,8 +1013,8 @@ int4hashset_symmetric_difference(PG_FUNCTION_ARGS)
 	int4hashset_t  *result;
 	char		   *bitmapa = seta->data;
 	char		   *bitmapb = setb->data;
-	int32_t		   *valuesa = (int32 *) (bitmapa + CEIL_DIV(seta->capacity, 8));
-	int32_t		   *valuesb = (int32 *) (bitmapb + CEIL_DIV(setb->capacity, 8));
+	int32		   *valuesa = (int32 *) (bitmapa + CEIL_DIV(seta->capacity, 8));
+	int32		   *valuesb = (int32 *) (bitmapb + CEIL_DIV(setb->capacity, 8));
 
 	result = int4hashset_allocate(
 		seta->nelements + setb->nelements,
@@ -946,5 +1051,8 @@ int4hashset_symmetric_difference(PG_FUNCTION_ARGS)
 		}
 	}
 
+	if (seta->null_element ^ setb->null_element)
+		result->null_element = true;
+
 	PG_RETURN_POINTER(result);
 }
diff --git a/hashset.c b/hashset.c
index 67cbdf3..91907ab 100644
--- a/hashset.c
+++ b/hashset.c
@@ -46,6 +46,7 @@ int4hashset_allocate(
 	set->ncollisions = 0;
 	set->max_collisions = 0;
 	set->hash = 0; /* Initial hash value */
+	set->null_element = false; /* No null element initially */
 
 	set->flags |= 0;
 
@@ -298,7 +299,7 @@ hashset_isspace(char ch)
  * Construct an SQL array from a simple C double array
  */
 Datum
-int32_to_array(FunctionCallInfo fcinfo, int32 *d, int len)
+int32_to_array(FunctionCallInfo fcinfo, int32 *d, int len, bool null_element)
 {
 	ArrayBuildState *astate = NULL;
 	int		 i;
@@ -313,6 +314,15 @@ int32_to_array(FunctionCallInfo fcinfo, int32 *d, int len)
 								  CurrentMemoryContext);
 	}
 
+	if (null_element)
+	{
+		astate = accumArrayResult(astate,
+								  (Datum) 0,
+								  true,
+								  INT4OID,
+								  CurrentMemoryContext);
+	}
+
 	PG_RETURN_DATUM(makeArrayResult(astate,
 					CurrentMemoryContext));
 }
diff --git a/hashset.h b/hashset.h
index 3f22133..86f5d1b 100644
--- a/hashset.h
+++ b/hashset.h
@@ -28,16 +28,17 @@
 #define DEFAULT_HASHFN_ID JENKINS_LOOKUP3_HASHFN_ID
 
 typedef struct int4hashset_t {
-	int32		vl_len_;		/* varlena header (do not touch directly!) */
-	int32		flags;			/* reserved for future use (versioning, ...) */
-	int32		capacity;		/* max number of element we have space for */
-	int32		nelements;		/* number of items added to the hashset */
+	int32		vl_len_;		/* Varlena header (do not touch directly!) */
+	int32		flags;			/* Reserved for future use (versioning, ...) */
+	int32		capacity;		/* Max number of element we have space for */
+	int32		nelements;		/* Number of items added to the hashset */
 	int32		hashfn_id;		/* ID of the hash function used */
 	float4		load_factor;	/* Load factor before triggering resize */
 	float4		growth_factor;	/* Growth factor when resizing the hashset */
 	int32		ncollisions;	/* Number of collisions */
 	int32		max_collisions;	/* Maximum collisions for a single element */
 	int32		hash;			/* Stored hash value of the hashset */
+	bool		null_element;	/* Indicates if null is present in hashset */
 	char		data[FLEXIBLE_ARRAY_MEMBER];
 } int4hashset_t;
 
@@ -48,6 +49,6 @@ bool int4hashset_contains_element(int4hashset_t *set, int32 value);
 int32 *int4hashset_extract_sorted_elements(int4hashset_t *set);
 int4hashset_t *int4hashset_copy(int4hashset_t *src);
 bool hashset_isspace(char ch);
-Datum int32_to_array(FunctionCallInfo fcinfo, int32 *d, int len);
+Datum int32_to_array(FunctionCallInfo fcinfo, int32 *d, int len, bool null_element);
 
 #endif /* HASHSET_H */
diff --git a/test/expected/array-and-multiset-semantics.out b/test/expected/array-and-multiset-semantics.out
new file mode 100644
index 0000000..8f989a1
--- /dev/null
+++ b/test/expected/array-and-multiset-semantics.out
@@ -0,0 +1,365 @@
+CREATE OR REPLACE FUNCTION array_union(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT unnest($1)
+                UNION
+                SELECT unnest($2)
+            ) q
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+CREATE OR REPLACE FUNCTION array_intersection(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT unnest($1)
+                INTERSECT
+                SELECT unnest($2)
+            ) q
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+CREATE OR REPLACE FUNCTION array_difference(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT unnest($1)
+                EXCEPT
+                SELECT unnest($2)
+            ) q
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+CREATE OR REPLACE FUNCTION array_symmetric_difference(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT
+                    *
+                FROM
+                (
+                    SELECT unnest($1)
+                    UNION
+                    SELECT unnest($2)
+                ) AS q1
+                EXCEPT
+                SELECT
+                    *
+                FROM
+                (
+                    SELECT unnest($1)
+                    INTERSECT
+                    SELECT unnest($2)
+                ) AS q2
+            ) AS q3
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+CREATE OR REPLACE FUNCTION array_sort_distinct(int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            cardinality($1) = 0
+        THEN
+            '{}'::int4[]
+        ELSE
+        (
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM unnest($1)
+        )
+    END
+$$ LANGUAGE sql;
+DROP TABLE IF EXISTS hashset_test_results_1;
+NOTICE:  table "hashset_test_results_1" does not exist, skipping
+CREATE TABLE hashset_test_results_1 AS
+SELECT
+    arg1,
+    arg2,
+    hashset_add(arg1::int4hashset, arg2),
+    array_append(arg1::int4[], arg2),
+    hashset_contains(arg1::int4hashset, arg2),
+    arg2 = ANY(arg1::int4[]) AS "= ANY(...)"
+FROM (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS a(arg1)
+CROSS JOIN (VALUES (NULL::int4), (1::int4), (4::int4)) AS b(arg2);
+DROP TABLE IF EXISTS hashset_test_results_2;
+NOTICE:  table "hashset_test_results_2" does not exist, skipping
+CREATE TABLE hashset_test_results_2 AS
+SELECT
+    arg1,
+    arg2,
+    hashset_union(arg1::int4hashset, arg2::int4hashset),
+    array_union(arg1::int4[], arg2::int4[]),
+    hashset_intersection(arg1::int4hashset, arg2::int4hashset),
+    array_intersection(arg1::int4[], arg2::int4[]),
+    hashset_difference(arg1::int4hashset, arg2::int4hashset),
+    array_difference(arg1::int4[], arg2::int4[]),
+    hashset_symmetric_difference(arg1::int4hashset, arg2::int4hashset),
+    array_symmetric_difference(arg1::int4[], arg2::int4[]),
+    hashset_eq(arg1::int4hashset, arg2::int4hashset),
+    array_eq(arg1::int4[], arg2::int4[]),
+    hashset_ne(arg1::int4hashset, arg2::int4hashset),
+    array_ne(arg1::int4[], arg2::int4[])
+FROM (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{1,NULL}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS a(arg1)
+CROSS JOIN (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{1,NULL}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS b(arg2);
+DROP TABLE IF EXISTS hashset_test_results_3;
+NOTICE:  table "hashset_test_results_3" does not exist, skipping
+CREATE TABLE hashset_test_results_3 AS
+SELECT
+    arg1,
+    hashset_cardinality(arg1::int4hashset),
+    cardinality(arg1::int4[])
+FROM (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS a(arg1);
+SELECT * FROM hashset_test_results_1;
+  arg1  | arg2 | hashset_add | array_append | hashset_contains | = ANY(...) 
+--------+------+-------------+--------------+------------------+------------
+        |      | {NULL}      | {NULL}       |                  | 
+        |    1 | {1}         | {1}          |                  | 
+        |    4 | {4}         | {4}          |                  | 
+ {}     |      | {NULL}      | {NULL}       | f                | f
+ {}     |    1 | {1}         | {1}          | f                | f
+ {}     |    4 | {4}         | {4}          | f                | f
+ {NULL} |      | {NULL}      | {NULL,NULL}  |                  | 
+ {NULL} |    1 | {1,NULL}    | {NULL,1}     |                  | 
+ {NULL} |    4 | {4,NULL}    | {NULL,4}     |                  | 
+ {1}    |      | {1,NULL}    | {1,NULL}     |                  | 
+ {1}    |    1 | {1}         | {1,1}        | t                | t
+ {1}    |    4 | {1,4}       | {1,4}        | f                | f
+ {2}    |      | {2,NULL}    | {2,NULL}     |                  | 
+ {2}    |    1 | {2,1}       | {2,1}        | f                | f
+ {2}    |    4 | {2,4}       | {2,4}        | f                | f
+ {1,2}  |      | {1,2,NULL}  | {1,2,NULL}   |                  | 
+ {1,2}  |    1 | {1,2}       | {1,2,1}      | t                | t
+ {1,2}  |    4 | {4,1,2}     | {1,2,4}      | f                | f
+ {2,3}  |      | {2,3,NULL}  | {2,3,NULL}   |                  | 
+ {2,3}  |    1 | {1,2,3}     | {2,3,1}      | f                | f
+ {2,3}  |    4 | {4,2,3}     | {2,3,4}      | f                | f
+(21 rows)
+
+SELECT * FROM hashset_test_results_2;
+   arg1   |   arg2   | hashset_union | array_union  | hashset_intersection | array_intersection | hashset_difference | array_difference | hashset_symmetric_difference | array_symmetric_difference | hashset_eq | array_eq | hashset_ne | array_ne 
+----------+----------+---------------+--------------+----------------------+--------------------+--------------------+------------------+------------------------------+----------------------------+------------+----------+------------+----------
+          |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+          | {}       |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+          | {NULL}   |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+          | {1}      |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+          | {1,NULL} |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+          | {2}      |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+          | {1,2}    |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+          | {2,3}    |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {}       |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {}       | {}       | {}            | {}           | {}                   | {}                 | {}                 | {}               | {}                           | {}                         | t          | t        | f          | f
+ {}       | {NULL}   | {NULL}        | {NULL}       | {}                   | {}                 | {}                 | {}               | {NULL}                       | {NULL}                     | f          | f        | t          | t
+ {}       | {1}      | {1}           | {1}          | {}                   | {}                 | {}                 | {}               | {1}                          | {1}                        | f          | f        | t          | t
+ {}       | {1,NULL} | {1,NULL}      | {1,NULL}     | {}                   | {}                 | {}                 | {}               | {1,NULL}                     | {1,NULL}                   | f          | f        | t          | t
+ {}       | {2}      | {2}           | {2}          | {}                   | {}                 | {}                 | {}               | {2}                          | {2}                        | f          | f        | t          | t
+ {}       | {1,2}    | {1,2}         | {1,2}        | {}                   | {}                 | {}                 | {}               | {1,2}                        | {1,2}                      | f          | f        | t          | t
+ {}       | {2,3}    | {2,3}         | {2,3}        | {}                   | {}                 | {}                 | {}               | {2,3}                        | {2,3}                      | f          | f        | t          | t
+ {NULL}   |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {NULL}   | {}       | {NULL}        | {NULL}       | {}                   | {}                 | {NULL}             | {NULL}           | {NULL}                       | {NULL}                     | f          | f        | t          | t
+ {NULL}   | {NULL}   | {NULL}        | {NULL}       | {NULL}               | {NULL}             | {}                 | {}               | {}                           | {}                         | t          | t        | f          | f
+ {NULL}   | {1}      | {1,NULL}      | {1,NULL}     | {}                   | {}                 | {NULL}             | {NULL}           | {1,NULL}                     | {1,NULL}                   | f          | f        | t          | t
+ {NULL}   | {1,NULL} | {1,NULL}      | {1,NULL}     | {NULL}               | {NULL}             | {}                 | {}               | {1}                          | {1}                        | f          | f        | t          | t
+ {NULL}   | {2}      | {2,NULL}      | {2,NULL}     | {}                   | {}                 | {NULL}             | {NULL}           | {2,NULL}                     | {2,NULL}                   | f          | f        | t          | t
+ {NULL}   | {1,2}    | {2,1,NULL}    | {1,2,NULL}   | {}                   | {}                 | {NULL}             | {NULL}           | {1,2,NULL}                   | {1,2,NULL}                 | f          | f        | t          | t
+ {NULL}   | {2,3}    | {3,2,NULL}    | {2,3,NULL}   | {}                   | {}                 | {NULL}             | {NULL}           | {2,3,NULL}                   | {2,3,NULL}                 | f          | f        | t          | t
+ {1}      |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {1}      | {}       | {1}           | {1}          | {}                   | {}                 | {1}                | {1}              | {1}                          | {1}                        | f          | f        | t          | t
+ {1}      | {NULL}   | {1,NULL}      | {1,NULL}     | {}                   | {}                 | {1}                | {1}              | {1,NULL}                     | {1,NULL}                   | f          | f        | t          | t
+ {1}      | {1}      | {1}           | {1}          | {1}                  | {1}                | {}                 | {}               | {}                           | {}                         | t          | t        | f          | f
+ {1}      | {1,NULL} | {1,NULL}      | {1,NULL}     | {1}                  | {1}                | {}                 | {}               | {NULL}                       | {NULL}                     | f          | f        | t          | t
+ {1}      | {2}      | {1,2}         | {1,2}        | {}                   | {}                 | {1}                | {1}              | {1,2}                        | {1,2}                      | f          | f        | t          | t
+ {1}      | {1,2}    | {1,2}         | {1,2}        | {1}                  | {1}                | {}                 | {}               | {2}                          | {2}                        | f          | f        | t          | t
+ {1}      | {2,3}    | {3,1,2}       | {1,2,3}      | {}                   | {}                 | {1}                | {1}              | {3,2,1}                      | {1,2,3}                    | f          | f        | t          | t
+ {1,NULL} |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {1,NULL} | {}       | {1,NULL}      | {1,NULL}     | {}                   | {}                 | {1,NULL}           | {1,NULL}         | {1,NULL}                     | {1,NULL}                   | f          | f        | t          | t
+ {1,NULL} | {NULL}   | {1,NULL}      | {1,NULL}     | {NULL}               | {NULL}             | {1}                | {1}              | {1}                          | {1}                        | f          | f        | t          | t
+ {1,NULL} | {1}      | {1,NULL}      | {1,NULL}     | {1}                  | {1}                | {NULL}             | {NULL}           | {NULL}                       | {NULL}                     | f          | f        | t          | t
+ {1,NULL} | {1,NULL} | {1,NULL}      | {1,NULL}     | {1,NULL}             | {1,NULL}           | {}                 | {}               | {}                           | {}                         | t          | t        | f          | f
+ {1,NULL} | {2}      | {1,2,NULL}    | {1,2,NULL}   | {}                   | {}                 | {1,NULL}           | {1,NULL}         | {1,2,NULL}                   | {1,2,NULL}                 | f          | f        | t          | t
+ {1,NULL} | {1,2}    | {1,2,NULL}    | {1,2,NULL}   | {1}                  | {1}                | {NULL}             | {NULL}           | {2,NULL}                     | {2,NULL}                   | f          | f        | t          | t
+ {1,NULL} | {2,3}    | {3,1,2,NULL}  | {1,2,3,NULL} | {}                   | {}                 | {1,NULL}           | {1,NULL}         | {3,2,1,NULL}                 | {1,2,3,NULL}               | f          | f        | t          | t
+ {2}      |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {2}      | {}       | {2}           | {2}          | {}                   | {}                 | {2}                | {2}              | {2}                          | {2}                        | f          | f        | t          | t
+ {2}      | {NULL}   | {2,NULL}      | {2,NULL}     | {}                   | {}                 | {2}                | {2}              | {2,NULL}                     | {2,NULL}                   | f          | f        | t          | t
+ {2}      | {1}      | {2,1}         | {1,2}        | {}                   | {}                 | {2}                | {2}              | {2,1}                        | {1,2}                      | f          | f        | t          | t
+ {2}      | {1,NULL} | {2,1,NULL}    | {1,2,NULL}   | {}                   | {}                 | {2}                | {2}              | {2,1,NULL}                   | {1,2,NULL}                 | f          | f        | t          | t
+ {2}      | {2}      | {2}           | {2}          | {2}                  | {2}                | {}                 | {}               | {}                           | {}                         | t          | t        | f          | f
+ {2}      | {1,2}    | {2,1}         | {1,2}        | {2}                  | {2}                | {}                 | {}               | {1}                          | {1}                        | f          | f        | t          | t
+ {2}      | {2,3}    | {2,3}         | {2,3}        | {2}                  | {2}                | {}                 | {}               | {3}                          | {3}                        | f          | f        | t          | t
+ {1,2}    |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {1,2}    | {}       | {1,2}         | {1,2}        | {}                   | {}                 | {1,2}              | {1,2}            | {1,2}                        | {1,2}                      | f          | f        | t          | t
+ {1,2}    | {NULL}   | {1,2,NULL}    | {1,2,NULL}   | {}                   | {}                 | {1,2}              | {1,2}            | {1,2,NULL}                   | {1,2,NULL}                 | f          | f        | t          | t
+ {1,2}    | {1}      | {1,2}         | {1,2}        | {1}                  | {1}                | {2}                | {2}              | {2}                          | {2}                        | f          | f        | t          | t
+ {1,2}    | {1,NULL} | {1,2,NULL}    | {1,2,NULL}   | {1}                  | {1}                | {2}                | {2}              | {2,NULL}                     | {2,NULL}                   | f          | f        | t          | t
+ {1,2}    | {2}      | {1,2}         | {1,2}        | {2}                  | {2}                | {1}                | {1}              | {1}                          | {1}                        | f          | f        | t          | t
+ {1,2}    | {1,2}    | {1,2}         | {1,2}        | {1,2}                | {1,2}              | {}                 | {}               | {}                           | {}                         | t          | t        | f          | f
+ {1,2}    | {2,3}    | {3,1,2}       | {1,2,3}      | {2}                  | {2}                | {1}                | {1}              | {1,3}                        | {1,3}                      | f          | f        | t          | t
+ {2,3}    |          |               |              |                      |                    |                    |                  |                              |                            |            |          |            | 
+ {2,3}    | {}       | {2,3}         | {2,3}        | {}                   | {}                 | {2,3}              | {2,3}            | {2,3}                        | {2,3}                      | f          | f        | t          | t
+ {2,3}    | {NULL}   | {2,3,NULL}    | {2,3,NULL}   | {}                   | {}                 | {2,3}              | {2,3}            | {2,3,NULL}                   | {2,3,NULL}                 | f          | f        | t          | t
+ {2,3}    | {1}      | {1,2,3}       | {1,2,3}      | {}                   | {}                 | {2,3}              | {2,3}            | {3,2,1}                      | {1,2,3}                    | f          | f        | t          | t
+ {2,3}    | {1,NULL} | {1,2,3,NULL}  | {1,2,3,NULL} | {}                   | {}                 | {2,3}              | {2,3}            | {3,2,1,NULL}                 | {1,2,3,NULL}               | f          | f        | t          | t
+ {2,3}    | {2}      | {2,3}         | {2,3}        | {2}                  | {2}                | {3}                | {3}              | {3}                          | {3}                        | f          | f        | t          | t
+ {2,3}    | {1,2}    | {1,2,3}       | {1,2,3}      | {2}                  | {2}                | {3}                | {3}              | {1,3}                        | {1,3}                      | f          | f        | t          | t
+ {2,3}    | {2,3}    | {2,3}         | {2,3}        | {2,3}                | {2,3}              | {}                 | {}               | {}                           | {}                         | t          | t        | f          | f
+(64 rows)
+
+SELECT * FROM hashset_test_results_3;
+  arg1  | hashset_cardinality | cardinality 
+--------+---------------------+-------------
+        |                     |            
+ {}     |                   0 |           0
+ {NULL} |                   1 |           1
+ {1}    |                   1 |           1
+ {2}    |                   1 |           1
+ {1,2}  |                   2 |           2
+ {2,3}  |                   2 |           2
+(7 rows)
+
+/*
+ * The queries below should not return any rows since the hashset
+ * semantics should be identical to array semantics, given the array elements
+ * are distinct and both are compared as sorted arrays.
+ */
+\echo *** Testing: hashset_add()
+*** Testing: hashset_add()
+SELECT * FROM hashset_test_results_1
+WHERE
+    hashset_to_sorted_array(hashset_add)
+IS DISTINCT FROM
+    array_sort_distinct(array_append);
+ arg1 | arg2 | hashset_add | array_append | hashset_contains | = ANY(...) 
+------+------+-------------+--------------+------------------+------------
+(0 rows)
+
+\echo *** Testing: hashset_contains()
+*** Testing: hashset_contains()
+SELECT * FROM hashset_test_results_1
+WHERE
+    hashset_contains
+IS DISTINCT FROM
+    "= ANY(...)";
+ arg1 | arg2 | hashset_add | array_append | hashset_contains | = ANY(...) 
+------+------+-------------+--------------+------------------+------------
+(0 rows)
+
+\echo *** Testing: hashset_union()
+*** Testing: hashset_union()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_union)
+IS DISTINCT FROM
+    array_sort_distinct(array_union);
+ arg1 | arg2 | hashset_union | array_union | hashset_intersection | array_intersection | hashset_difference | array_difference | hashset_symmetric_difference | array_symmetric_difference | hashset_eq | array_eq | hashset_ne | array_ne 
+------+------+---------------+-------------+----------------------+--------------------+--------------------+------------------+------------------------------+----------------------------+------------+----------+------------+----------
+(0 rows)
+
+\echo *** Testing: hashset_intersection()
+*** Testing: hashset_intersection()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_intersection)
+IS DISTINCT FROM
+    array_sort_distinct(array_intersection);
+ arg1 | arg2 | hashset_union | array_union | hashset_intersection | array_intersection | hashset_difference | array_difference | hashset_symmetric_difference | array_symmetric_difference | hashset_eq | array_eq | hashset_ne | array_ne 
+------+------+---------------+-------------+----------------------+--------------------+--------------------+------------------+------------------------------+----------------------------+------------+----------+------------+----------
+(0 rows)
+
+\echo *** Testing: hashset_difference()
+*** Testing: hashset_difference()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_difference)
+IS DISTINCT FROM
+    array_sort_distinct(array_difference);
+ arg1 | arg2 | hashset_union | array_union | hashset_intersection | array_intersection | hashset_difference | array_difference | hashset_symmetric_difference | array_symmetric_difference | hashset_eq | array_eq | hashset_ne | array_ne 
+------+------+---------------+-------------+----------------------+--------------------+--------------------+------------------+------------------------------+----------------------------+------------+----------+------------+----------
+(0 rows)
+
+\echo *** Testing: hashset_symmetric_difference()
+*** Testing: hashset_symmetric_difference()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_symmetric_difference)
+IS DISTINCT FROM
+    array_sort_distinct(array_symmetric_difference);
+ arg1 | arg2 | hashset_union | array_union | hashset_intersection | array_intersection | hashset_difference | array_difference | hashset_symmetric_difference | array_symmetric_difference | hashset_eq | array_eq | hashset_ne | array_ne 
+------+------+---------------+-------------+----------------------+--------------------+--------------------+------------------+------------------------------+----------------------------+------------+----------+------------+----------
+(0 rows)
+
+\echo *** Testing: hashset_eq()
+*** Testing: hashset_eq()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_eq
+IS DISTINCT FROM
+    array_eq;
+ arg1 | arg2 | hashset_union | array_union | hashset_intersection | array_intersection | hashset_difference | array_difference | hashset_symmetric_difference | array_symmetric_difference | hashset_eq | array_eq | hashset_ne | array_ne 
+------+------+---------------+-------------+----------------------+--------------------+--------------------+------------------+------------------------------+----------------------------+------------+----------+------------+----------
+(0 rows)
+
+\echo *** Testing: hashset_ne()
+*** Testing: hashset_ne()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_ne
+IS DISTINCT FROM
+    array_ne;
+ arg1 | arg2 | hashset_union | array_union | hashset_intersection | array_intersection | hashset_difference | array_difference | hashset_symmetric_difference | array_symmetric_difference | hashset_eq | array_eq | hashset_ne | array_ne 
+------+------+---------------+-------------+----------------------+--------------------+--------------------+------------------+------------------------------+----------------------------+------------+----------+------------+----------
+(0 rows)
+
+\echo *** Testing: hashset_cardinality()
+*** Testing: hashset_cardinality()
+SELECT * FROM hashset_test_results_3
+WHERE
+    hashset_cardinality
+IS DISTINCT FROM
+    cardinality;
+ arg1 | hashset_cardinality | cardinality 
+------+---------------------+-------------
+(0 rows)
+
diff --git a/test/expected/basic.out b/test/expected/basic.out
index b5326f2..79c3230 100644
--- a/test/expected/basic.out
+++ b/test/expected/basic.out
@@ -71,8 +71,8 @@ SELECT hashset_contains('{123,456}'::int4hashset, 789); -- false
  f
 (1 row)
 
-SELECT hashset_merge('{1,2}'::int4hashset, '{2,3}'::int4hashset);
- hashset_merge 
+SELECT hashset_union('{1,2}'::int4hashset, '{2,3}'::int4hashset);
+ hashset_union 
 ---------------
  {3,1,2}
 (1 row)
@@ -83,10 +83,10 @@ SELECT hashset_to_array('{1,2,3}'::int4hashset);
  {3,2,1}
 (1 row)
 
-SELECT hashset_count('{1,2,3}'::int4hashset); -- 3
- hashset_count 
----------------
-             3
+SELECT hashset_cardinality('{1,2,3}'::int4hashset); -- 3
+ hashset_cardinality 
+---------------------
+                   3
 (1 row)
 
 SELECT hashset_capacity(int4hashset(capacity := 10)); -- 10
diff --git a/test/expected/reported_bugs.out b/test/expected/reported_bugs.out
index b356b64..03cc7c3 100644
--- a/test/expected/reported_bugs.out
+++ b/test/expected/reported_bugs.out
@@ -1,7 +1,7 @@
 /*
- * Bug in hashset_add() and hashset_merge() functions altering original hashset.
+ * Bug in hashset_add() and hashset_union() functions altering original hashset.
  *
- * Previously, the hashset_add() and hashset_merge() functions were modifying the
+ * Previously, the hashset_add() and hashset_union() functions were modifying the
  * original hashset in-place, leading to unexpected results as the original data
  * within the hashset was being altered.
  *
@@ -10,7 +10,7 @@
  * a copy of the hashset is created and subsequently modified, thereby preserving
  * the integrity of the original hashset.
  *
- * As a result of this fix, hashset_add() and hashset_merge() now operate on
+ * As a result of this fix, hashset_add() and hashset_union() now operate on
  * a copied hashset, ensuring that the original data remains unaltered, and
  * the query executes correctly.
  */
diff --git a/test/expected/strict.out b/test/expected/strict.out
deleted file mode 100644
index 4a9d904..0000000
--- a/test/expected/strict.out
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Test to verify all relevant functions return NULL if any of
- * the input parameters are NULL, i.e. testing that they are declared as STRICT
- */
-SELECT hashset_add(int4hashset(), NULL::int);
- hashset_add 
--------------
- 
-(1 row)
-
-SELECT hashset_add(NULL::int4hashset, 123::int);
- hashset_add 
--------------
- 
-(1 row)
-
-SELECT hashset_contains('{123,456}'::int4hashset, NULL::int);
- hashset_contains 
-------------------
- 
-(1 row)
-
-SELECT hashset_contains(NULL::int4hashset, 456::int);
- hashset_contains 
-------------------
- 
-(1 row)
-
-SELECT hashset_merge('{1,2}'::int4hashset, NULL::int4hashset);
- hashset_merge 
----------------
- 
-(1 row)
-
-SELECT hashset_merge(NULL::int4hashset, '{2,3}'::int4hashset);
- hashset_merge 
----------------
- 
-(1 row)
-
-SELECT hashset_to_array(NULL::int4hashset);
- hashset_to_array 
-------------------
- 
-(1 row)
-
-SELECT hashset_count(NULL::int4hashset);
- hashset_count 
----------------
-              
-(1 row)
-
-SELECT hashset_capacity(NULL::int4hashset);
- hashset_capacity 
-------------------
-                 
-(1 row)
-
-SELECT hashset_intersection('{1,2}'::int4hashset,NULL::int4hashset);
- hashset_intersection 
-----------------------
- 
-(1 row)
-
-SELECT hashset_intersection(NULL::int4hashset,'{2,3}'::int4hashset);
- hashset_intersection 
-----------------------
- 
-(1 row)
-
-SELECT hashset_difference('{1,2}'::int4hashset,NULL::int4hashset);
- hashset_difference 
---------------------
- 
-(1 row)
-
-SELECT hashset_difference(NULL::int4hashset,'{2,3}'::int4hashset);
- hashset_difference 
---------------------
- 
-(1 row)
-
-SELECT hashset_symmetric_difference('{1,2}'::int4hashset,NULL::int4hashset);
- hashset_symmetric_difference 
-------------------------------
- 
-(1 row)
-
-SELECT hashset_symmetric_difference(NULL::int4hashset,'{2,3}'::int4hashset);
- hashset_symmetric_difference 
-------------------------------
- 
-(1 row)
-
-/*
- * For convenience, hashset_agg() is not STRICT and just ignore NULL values
- */
-SELECT hashset_agg(i) FROM (VALUES (NULL::int),(1::int),(2::int)) q(i);
- hashset_agg 
--------------
- {1,2}
-(1 row)
-
-SELECT hashset_agg(h) FROM
-(
-    SELECT NULL::int4hashset AS h
-    UNION ALL
-    SELECT hashset_agg(j) AS h FROM generate_series(6,10) AS j
-) q;
- hashset_agg  
---------------
- {6,7,8,9,10}
-(1 row)
-
diff --git a/test/expected/table.out b/test/expected/table.out
index 9793a49..f59494e 100644
--- a/test/expected/table.out
+++ b/test/expected/table.out
@@ -11,10 +11,10 @@ SELECT hashset_contains(user_likes, 101) FROM users WHERE user_id = 1;
  t
 (1 row)
 
-SELECT hashset_count(user_likes) FROM users WHERE user_id = 1;
- hashset_count 
----------------
-             2
+SELECT hashset_cardinality(user_likes) FROM users WHERE user_id = 1;
+ hashset_cardinality 
+---------------------
+                   2
 (1 row)
 
 SELECT hashset_sorted(user_likes) FROM users WHERE user_id = 1;
diff --git a/test/sql/array-and-multiset-semantics.sql b/test/sql/array-and-multiset-semantics.sql
new file mode 100644
index 0000000..0db7065
--- /dev/null
+++ b/test/sql/array-and-multiset-semantics.sql
@@ -0,0 +1,232 @@
+CREATE OR REPLACE FUNCTION array_union(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT unnest($1)
+                UNION
+                SELECT unnest($2)
+            ) q
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+
+CREATE OR REPLACE FUNCTION array_intersection(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT unnest($1)
+                INTERSECT
+                SELECT unnest($2)
+            ) q
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+
+CREATE OR REPLACE FUNCTION array_difference(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT unnest($1)
+                EXCEPT
+                SELECT unnest($2)
+            ) q
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+
+CREATE OR REPLACE FUNCTION array_symmetric_difference(int4[], int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            $1 IS NULL OR $2 IS NULL
+        THEN
+            NULL
+        ELSE
+        COALESCE((
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM
+            (
+                SELECT
+                    *
+                FROM
+                (
+                    SELECT unnest($1)
+                    UNION
+                    SELECT unnest($2)
+                ) AS q1
+                EXCEPT
+                SELECT
+                    *
+                FROM
+                (
+                    SELECT unnest($1)
+                    INTERSECT
+                    SELECT unnest($2)
+                ) AS q2
+            ) AS q3
+        ),'{}'::int4[])
+    END
+$$ LANGUAGE sql;
+
+CREATE OR REPLACE FUNCTION array_sort_distinct(int4[])
+RETURNS int4[]
+AS
+$$
+SELECT
+    CASE
+        WHEN
+            cardinality($1) = 0
+        THEN
+            '{}'::int4[]
+        ELSE
+        (
+            SELECT array_agg(DISTINCT unnest ORDER BY unnest) FROM unnest($1)
+        )
+    END
+$$ LANGUAGE sql;
+
+DROP TABLE IF EXISTS hashset_test_results_1;
+CREATE TABLE hashset_test_results_1 AS
+SELECT
+    arg1,
+    arg2,
+    hashset_add(arg1::int4hashset, arg2),
+    array_append(arg1::int4[], arg2),
+    hashset_contains(arg1::int4hashset, arg2),
+    arg2 = ANY(arg1::int4[]) AS "= ANY(...)"
+FROM (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS a(arg1)
+CROSS JOIN (VALUES (NULL::int4), (1::int4), (4::int4)) AS b(arg2);
+
+
+DROP TABLE IF EXISTS hashset_test_results_2;
+CREATE TABLE hashset_test_results_2 AS
+SELECT
+    arg1,
+    arg2,
+    hashset_union(arg1::int4hashset, arg2::int4hashset),
+    array_union(arg1::int4[], arg2::int4[]),
+    hashset_intersection(arg1::int4hashset, arg2::int4hashset),
+    array_intersection(arg1::int4[], arg2::int4[]),
+    hashset_difference(arg1::int4hashset, arg2::int4hashset),
+    array_difference(arg1::int4[], arg2::int4[]),
+    hashset_symmetric_difference(arg1::int4hashset, arg2::int4hashset),
+    array_symmetric_difference(arg1::int4[], arg2::int4[]),
+    hashset_eq(arg1::int4hashset, arg2::int4hashset),
+    array_eq(arg1::int4[], arg2::int4[]),
+    hashset_ne(arg1::int4hashset, arg2::int4hashset),
+    array_ne(arg1::int4[], arg2::int4[])
+FROM (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{1,NULL}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS a(arg1)
+CROSS JOIN (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{1,NULL}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS b(arg2);
+
+DROP TABLE IF EXISTS hashset_test_results_3;
+CREATE TABLE hashset_test_results_3 AS
+SELECT
+    arg1,
+    hashset_cardinality(arg1::int4hashset),
+    cardinality(arg1::int4[])
+FROM (VALUES (NULL), ('{}'), ('{NULL}'), ('{1}'), ('{2}'), ('{1,2}'), ('{2,3}')) AS a(arg1);
+
+SELECT * FROM hashset_test_results_1;
+SELECT * FROM hashset_test_results_2;
+SELECT * FROM hashset_test_results_3;
+
+/*
+ * The queries below should not return any rows since the hashset
+ * semantics should be identical to array semantics, given the array elements
+ * are distinct and both are compared as sorted arrays.
+ */
+
+\echo *** Testing: hashset_add()
+SELECT * FROM hashset_test_results_1
+WHERE
+    hashset_to_sorted_array(hashset_add)
+IS DISTINCT FROM
+    array_sort_distinct(array_append);
+
+\echo *** Testing: hashset_contains()
+SELECT * FROM hashset_test_results_1
+WHERE
+    hashset_contains
+IS DISTINCT FROM
+    "= ANY(...)";
+
+\echo *** Testing: hashset_union()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_union)
+IS DISTINCT FROM
+    array_sort_distinct(array_union);
+
+\echo *** Testing: hashset_intersection()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_intersection)
+IS DISTINCT FROM
+    array_sort_distinct(array_intersection);
+
+\echo *** Testing: hashset_difference()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_difference)
+IS DISTINCT FROM
+    array_sort_distinct(array_difference);
+
+\echo *** Testing: hashset_symmetric_difference()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_to_sorted_array(hashset_symmetric_difference)
+IS DISTINCT FROM
+    array_sort_distinct(array_symmetric_difference);
+
+\echo *** Testing: hashset_eq()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_eq
+IS DISTINCT FROM
+    array_eq;
+
+\echo *** Testing: hashset_ne()
+SELECT * FROM hashset_test_results_2
+WHERE
+    hashset_ne
+IS DISTINCT FROM
+    array_ne;
+
+\echo *** Testing: hashset_cardinality()
+SELECT * FROM hashset_test_results_3
+WHERE
+    hashset_cardinality
+IS DISTINCT FROM
+    cardinality;
diff --git a/test/sql/basic.sql b/test/sql/basic.sql
index 061794c..2bf5893 100644
--- a/test/sql/basic.sql
+++ b/test/sql/basic.sql
@@ -23,9 +23,9 @@ SELECT hashset_add(int4hashset(), 123);
 SELECT hashset_add('{123}'::int4hashset, 456);
 SELECT hashset_contains('{123,456}'::int4hashset, 456); -- true
 SELECT hashset_contains('{123,456}'::int4hashset, 789); -- false
-SELECT hashset_merge('{1,2}'::int4hashset, '{2,3}'::int4hashset);
+SELECT hashset_union('{1,2}'::int4hashset, '{2,3}'::int4hashset);
 SELECT hashset_to_array('{1,2,3}'::int4hashset);
-SELECT hashset_count('{1,2,3}'::int4hashset); -- 3
+SELECT hashset_cardinality('{1,2,3}'::int4hashset); -- 3
 SELECT hashset_capacity(int4hashset(capacity := 10)); -- 10
 SELECT hashset_intersection('{1,2}'::int4hashset,'{2,3}'::int4hashset);
 SELECT hashset_difference('{1,2}'::int4hashset,'{2,3}'::int4hashset);
diff --git a/test/sql/benchmark.sql b/test/sql/benchmark.sql
index 1535c22..e7a53f1 100644
--- a/test/sql/benchmark.sql
+++ b/test/sql/benchmark.sql
@@ -65,7 +65,7 @@ SELECT hashset_agg(rnd) FROM benchmark_input_10M;
 SELECT cardinality(array_agg) FROM benchmark_array_agg ORDER BY 1;
 
 SELECT
-    hashset_count(hashset_agg),
+    hashset_cardinality(hashset_agg),
     hashset_capacity(hashset_agg),
     hashset_collisions(hashset_agg),
     hashset_max_collisions(hashset_agg)
@@ -88,7 +88,7 @@ BEGIN
     FOR i IN 1..100000 LOOP
         h := hashset_add(h, i);
     END LOOP;
-    RAISE NOTICE 'hashset_count: %', hashset_count(h);
+    RAISE NOTICE 'hashset_cardinality: %', hashset_cardinality(h);
     RAISE NOTICE 'hashset_capacity: %', hashset_capacity(h);
     RAISE NOTICE 'hashset_collisions: %', hashset_collisions(h);
     RAISE NOTICE 'hashset_max_collisions: %', hashset_max_collisions(h);
@@ -106,7 +106,7 @@ BEGIN
     FOR i IN 1..100000 LOOP
         h := hashset_add(h, i);
     END LOOP;
-    RAISE NOTICE 'hashset_count: %', hashset_count(h);
+    RAISE NOTICE 'hashset_cardinality: %', hashset_cardinality(h);
     RAISE NOTICE 'hashset_capacity: %', hashset_capacity(h);
     RAISE NOTICE 'hashset_collisions: %', hashset_collisions(h);
     RAISE NOTICE 'hashset_max_collisions: %', hashset_max_collisions(h);
@@ -124,7 +124,7 @@ BEGIN
     FOR i IN 1..100000 LOOP
         h := hashset_add(h, i);
     END LOOP;
-    RAISE NOTICE 'hashset_count: %', hashset_count(h);
+    RAISE NOTICE 'hashset_cardinality: %', hashset_cardinality(h);
     RAISE NOTICE 'hashset_capacity: %', hashset_capacity(h);
     RAISE NOTICE 'hashset_collisions: %', hashset_collisions(h);
     RAISE NOTICE 'hashset_max_collisions: %', hashset_max_collisions(h);
@@ -145,7 +145,7 @@ BEGIN
     FOR i IN 1..100000 LOOP
         h := hashset_add(h, (floor(4294967296 * random()) - 2147483648)::int);
     END LOOP;
-    RAISE NOTICE 'hashset_count: %', hashset_count(h);
+    RAISE NOTICE 'hashset_cardinality: %', hashset_cardinality(h);
     RAISE NOTICE 'hashset_capacity: %', hashset_capacity(h);
     RAISE NOTICE 'hashset_collisions: %', hashset_collisions(h);
     RAISE NOTICE 'hashset_max_collisions: %', hashset_max_collisions(h);
@@ -164,7 +164,7 @@ BEGIN
     FOR i IN 1..100000 LOOP
         h := hashset_add(h, (floor(4294967296 * random()) - 2147483648)::int);
     END LOOP;
-    RAISE NOTICE 'hashset_count: %', hashset_count(h);
+    RAISE NOTICE 'hashset_cardinality: %', hashset_cardinality(h);
     RAISE NOTICE 'hashset_capacity: %', hashset_capacity(h);
     RAISE NOTICE 'hashset_collisions: %', hashset_collisions(h);
     RAISE NOTICE 'hashset_max_collisions: %', hashset_max_collisions(h);
@@ -183,7 +183,7 @@ BEGIN
     FOR i IN 1..100000 LOOP
         h := hashset_add(h, (floor(4294967296 * random()) - 2147483648)::int);
     END LOOP;
-    RAISE NOTICE 'hashset_count: %', hashset_count(h);
+    RAISE NOTICE 'hashset_cardinality: %', hashset_cardinality(h);
     RAISE NOTICE 'hashset_capacity: %', hashset_capacity(h);
     RAISE NOTICE 'hashset_collisions: %', hashset_collisions(h);
     RAISE NOTICE 'hashset_max_collisions: %', hashset_max_collisions(h);
diff --git a/test/sql/reported_bugs.sql b/test/sql/reported_bugs.sql
index 9166f5d..9e6b617 100644
--- a/test/sql/reported_bugs.sql
+++ b/test/sql/reported_bugs.sql
@@ -1,7 +1,7 @@
 /*
- * Bug in hashset_add() and hashset_merge() functions altering original hashset.
+ * Bug in hashset_add() and hashset_union() functions altering original hashset.
  *
- * Previously, the hashset_add() and hashset_merge() functions were modifying the
+ * Previously, the hashset_add() and hashset_union() functions were modifying the
  * original hashset in-place, leading to unexpected results as the original data
  * within the hashset was being altered.
  *
@@ -10,7 +10,7 @@
  * a copy of the hashset is created and subsequently modified, thereby preserving
  * the integrity of the original hashset.
  *
- * As a result of this fix, hashset_add() and hashset_merge() now operate on
+ * As a result of this fix, hashset_add() and hashset_union() now operate on
  * a copied hashset, ensuring that the original data remains unaltered, and
  * the query executes correctly.
  */
diff --git a/test/sql/strict.sql b/test/sql/strict.sql
deleted file mode 100644
index d0f33bd..0000000
--- a/test/sql/strict.sql
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Test to verify all relevant functions return NULL if any of
- * the input parameters are NULL, i.e. testing that they are declared as STRICT
- */
-
-SELECT hashset_add(int4hashset(), NULL::int);
-SELECT hashset_add(NULL::int4hashset, 123::int);
-SELECT hashset_contains('{123,456}'::int4hashset, NULL::int);
-SELECT hashset_contains(NULL::int4hashset, 456::int);
-SELECT hashset_merge('{1,2}'::int4hashset, NULL::int4hashset);
-SELECT hashset_merge(NULL::int4hashset, '{2,3}'::int4hashset);
-SELECT hashset_to_array(NULL::int4hashset);
-SELECT hashset_count(NULL::int4hashset);
-SELECT hashset_capacity(NULL::int4hashset);
-SELECT hashset_intersection('{1,2}'::int4hashset,NULL::int4hashset);
-SELECT hashset_intersection(NULL::int4hashset,'{2,3}'::int4hashset);
-SELECT hashset_difference('{1,2}'::int4hashset,NULL::int4hashset);
-SELECT hashset_difference(NULL::int4hashset,'{2,3}'::int4hashset);
-SELECT hashset_symmetric_difference('{1,2}'::int4hashset,NULL::int4hashset);
-SELECT hashset_symmetric_difference(NULL::int4hashset,'{2,3}'::int4hashset);
-
-/*
- * For convenience, hashset_agg() is not STRICT and just ignore NULL values
- */
-SELECT hashset_agg(i) FROM (VALUES (NULL::int),(1::int),(2::int)) q(i);
-
-SELECT hashset_agg(h) FROM
-(
-    SELECT NULL::int4hashset AS h
-    UNION ALL
-    SELECT hashset_agg(j) AS h FROM generate_series(6,10) AS j
-) q;
diff --git a/test/sql/table.sql b/test/sql/table.sql
index 0472352..bf05ffa 100644
--- a/test/sql/table.sql
+++ b/test/sql/table.sql
@@ -6,5 +6,5 @@ INSERT INTO users (user_id) VALUES (1);
 UPDATE users SET user_likes = hashset_add(user_likes, 101) WHERE user_id = 1;
 UPDATE users SET user_likes = hashset_add(user_likes, 202) WHERE user_id = 1;
 SELECT hashset_contains(user_likes, 101) FROM users WHERE user_id = 1;
-SELECT hashset_count(user_likes) FROM users WHERE user_id = 1;
+SELECT hashset_cardinality(user_likes) FROM users WHERE user_id = 1;
 SELECT hashset_sorted(user_likes) FROM users WHERE user_id = 1;
