2016-01-26 11:42 GMT+01:00 Marko Tiikkaja <ma...@joh.to>:

> On 25/01/16 19:57, Pavel Stehule wrote:
>
>> Marco is a author of this patch, so - Marco, please, send final version of
>> this patch
>>
>
> I don't really care about the tests.  Can we not use the v5 patch already
> in the thread?  As far as I could tell there were no reviewer's comments on
> it anymore.
>

It was not my request, but I counted Jim as second reviewer.

So, I'll return back original regress tests. If I remember well, there are
no any other objection, so I'll mark this version as ready for commiter.

1. the patch is rebased against master
2. now warning or errors due compilation
3. all tests are passed
4. the code is simple without side effects and possible negative
performance impacts
6. there was not objections against the design
7. the iteration over null bitmap is used more times in our code, but this
is new special case. We don't need iterate over array elements, so we
should not to use existing array iterators.

I'll mark this patch as ready for commiter

Regards

Pavel


>
> .m
>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
new file mode 100644
index 9c143b2..23c933f
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 182,188 ****
    </sect1>
  
    <sect1 id="functions-comparison">
!    <title>Comparison Operators</title>
  
     <indexterm zone="functions-comparison">
      <primary>comparison</primary>
--- 182,188 ----
    </sect1>
  
    <sect1 id="functions-comparison">
!    <title>Comparison Functions and Operators</title>
  
     <indexterm zone="functions-comparison">
      <primary>comparison</primary>
***************
*** 191,200 ****
  
     <para>
      The usual comparison operators are available, shown in <xref
!     linkend="functions-comparison-table">.
     </para>
  
!    <table id="functions-comparison-table">
      <title>Comparison Operators</title>
      <tgroup cols="2">
       <thead>
--- 191,200 ----
  
     <para>
      The usual comparison operators are available, shown in <xref
!     linkend="functions-comparison-op-table">.
     </para>
  
!    <table id="functions-comparison-op-table">
      <title>Comparison Operators</title>
      <tgroup cols="2">
       <thead>
***************
*** 437,442 ****
--- 437,479 ----
     </para>
  -->
  
+   <table id="functions-comparison-table">
+     <title>Comparison Functions</title>
+     <tgroup cols="4">
+      <thead>
+       <row>
+        <entry>Function</entry>
+        <entry>Description</entry>
+        <entry>Example</entry>
+        <entry>Example Result</entry>
+       </row>
+      </thead>
+      <tbody>
+       <row>
+        <entry>
+          <indexterm>
+           <primary>num_notnulls</primary>
+          </indexterm>
+          <literal>num_notnulls(VARIADIC "any")</literal>
+        </entry>
+        <entry>Returns the number of not NULL input arguments</entry>
+        <entry><literal>num_nulls(1, NULL, 2)</literal></entry>
+        <entry><literal>2</literal></entry>
+       </row>
+       <row>
+        <entry>
+          <indexterm>
+           <primary>num_nulls</primary>
+          </indexterm>
+          <literal>num_nulls(VARIADIC "any")</literal>
+        </entry>
+        <entry>Returns the number of NULL input arguments</entry>
+        <entry><literal>num_nulls(1, NULL, 2)</literal></entry>
+        <entry><literal>1</literal></entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
    </sect1>
  
    <sect1 id="functions-math">
*************** table2-mapping
*** 10389,10395 ****
    </note>
    <para>
     The standard comparison operators shown in  <xref
!    linkend="functions-comparison-table"> are available for
     <type>jsonb</type>, but not for <type>json</type>. They follow the
     ordering rules for B-tree operations outlined at <xref
     linkend="json-indexing">.
--- 10426,10432 ----
    </note>
    <para>
     The standard comparison operators shown in  <xref
!    linkend="functions-comparison-op-table"> are available for
     <type>jsonb</type>, but not for <type>json</type>. They follow the
     ordering rules for B-tree operations outlined at <xref
     linkend="json-indexing">.
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
new file mode 100644
index 6a306f3..35810d1
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
***************
*** 43,48 ****
--- 43,160 ----
  
  #define atooid(x)  ((Oid) strtoul((x), NULL, 10))
  
+ /*
+  * Collect info about NULL arguments. Returns true when result values
+  * are valid.
+  */
+ static bool
+ count_nulls(FunctionCallInfo fcinfo,
+ 				    int32 *nargs, int32 *nulls)
+ {
+ 	int32 count = 0;
+ 	int i;
+ 
+ 	if (get_fn_expr_variadic(fcinfo->flinfo))
+ 	{
+ 		ArrayType  *arr;
+ 		int ndims, nitems, *dims;
+ 		bits8 *bitmap;
+ 		int bitmask;
+ 
+ 		/*
+ 		 * When parameter with packed variadic arguments is NULL, we
+ 		 * cannot to identify number of variadic argumens (NULL
+ 		 * or not NULL), then the correct result is NULL. This behave
+ 		 * is consistent with other variadic functions - see concat_internal.
+ 		 */
+ 		if (PG_ARGISNULL(0))
+ 			return false;
+ 
+ 		/*
+ 		 * Non-null argument had better be an array.  We assume that any call
+ 		 * context that could let get_fn_expr_variadic return true will have
+ 		 * checked that a VARIADIC-labeled parameter actually is an array.  So
+ 		 * it should be okay to just Assert that it's an array rather than
+ 		 * doing a full-fledged error check.
+ 		 */
+ 		Assert(OidIsValid(get_base_element_type(get_fn_expr_argtype(fcinfo->flinfo, 0))));
+ 
+ 		/* OK, safe to fetch the array value */
+ 		arr = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 		ndims = ARR_NDIM(arr);
+ 		dims = ARR_DIMS(arr);
+ 		nitems = ArrayGetNItems(ndims, dims);
+ 
+ 		bitmap = ARR_NULLBITMAP(arr);
+ 		if (bitmap)
+ 		{
+ 			bitmask = 1;
+ 
+ 			for (i = 0; i < nitems; i++)
+ 			{
+ 				if ((*bitmap & bitmask) == 0)
+ 					count++;
+ 
+ 				bitmask <<= 1;
+ 				if (bitmask == 0x100)
+ 				{
+ 					bitmap++;
+ 					bitmask = 1;
+ 				}
+ 			}
+ 		}
+ 
+ 		*nargs = nitems;
+ 		*nulls = count;
+ 	}
+ 	else
+ 	{
+ 		for (i = 0; i < PG_NARGS(); i++)
+ 		{
+ 			if (PG_ARGISNULL(i))
+ 				count++;
+ 		}
+ 
+ 		*nargs = PG_NARGS();
+ 		*nulls = count;
+ 	}
+ 
+ 	return true;
+ }
+ 
+ /*
+  * num_nulls()
+  *  Count the number of NULL input arguments
+  */
+ Datum
+ pg_num_nulls(PG_FUNCTION_ARGS)
+ {
+ 	int32 nargs,
+ 		    nulls;
+ 
+ 	if (!count_nulls(fcinfo, &nargs, &nulls))
+ 		PG_RETURN_NULL();
+ 
+ 	PG_RETURN_INT32(nulls);
+ }
+ 
+ /*
+  * num_notnulls()
+  *  Count the number of not NULL input arguments
+  */
+ Datum
+ pg_num_notnulls(PG_FUNCTION_ARGS)
+ {
+ 	int32 nargs,
+ 		    nulls;
+ 
+ 	if (!count_nulls(fcinfo, &nargs, &nulls))
+ 		PG_RETURN_NULL();
+ 
+ 	PG_RETURN_INT32(nargs - nulls);
+ }
+ 
  
  /*
   * current_database()
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index 79e92ff..3803763
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("adjust time with time zone precis
*** 2884,2889 ****
--- 2884,2893 ----
  
  DATA(insert OID = 2003 (  textanycat	   PGNSP PGUID 14 1 0 0 0 f f f f t f s s 2 0 25 "25 2776" _null_ _null_ _null_ _null_ _null_ "select $1 || $2::pg_catalog.text" _null_ _null_ _null_ ));
  DATA(insert OID = 2004 (  anytextcat	   PGNSP PGUID 14 1 0 0 0 f f f f t f s s 2 0 25 "2776 25" _null_ _null_ _null_ _null_ _null_ "select $1::pg_catalog.text || $2" _null_ _null_ _null_ ));
+ DATA(insert OID = 4400 (  num_nulls        PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_    pg_num_nulls _null_ _null_ _null_ ));
+ DESCR("count the number of NULL input arguments");
+ DATA(insert OID = 4401 (  num_notnulls        PGNSP PGUID 12 1 0 2276 0 f f f f f f i s 1 0 23 "2276" "{2276}" "{v}" _null_ _null_ _null_    pg_num_notnulls _null_ _null_ _null_ ));
+ DESCR("count the number of not NULL input arguments");
  
  DATA(insert OID = 2005 (  bytealike		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ bytealike _null_ _null_ _null_ ));
  DATA(insert OID = 2006 (  byteanlike	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "17 17" _null_ _null_ _null_ _null_ _null_ byteanlike _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index c2e529f..b31b6a3
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern Datum pg_ls_dir(PG_FUNCTION_ARGS)
*** 489,494 ****
--- 489,496 ----
  extern Datum pg_ls_dir_1arg(PG_FUNCTION_ARGS);
  
  /* misc.c */
+ extern Datum pg_num_notnulls(PG_FUNCTION_ARGS);
+ extern Datum pg_num_nulls(PG_FUNCTION_ARGS);
  extern Datum current_database(PG_FUNCTION_ARGS);
  extern Datum current_query(PG_FUNCTION_ARGS);
  extern Datum pg_cancel_backend(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out
new file mode 100644
index ...e3652bb
*** a/src/test/regress/expected/misc_functions.out
--- b/src/test/regress/expected/misc_functions.out
***************
*** 0 ****
--- 1,135 ----
+ --
+ -- num_nulls()
+ --
+ SELECT num_notnulls(NULL);
+  num_notnulls 
+ --------------
+             0
+ (1 row)
+ 
+ SELECT num_notnulls('1');
+  num_notnulls 
+ --------------
+             1
+ (1 row)
+ 
+ SELECT num_notnulls(NULL::text);
+  num_notnulls 
+ --------------
+             0
+ (1 row)
+ 
+ SELECT num_notnulls(NULL::text, NULL::int);
+  num_notnulls 
+ --------------
+             0
+ (1 row)
+ 
+ SELECT num_notnulls(1, 2, NULL::text, NULL::point, '', int8 '9', 1.0 / NULL);
+  num_notnulls 
+ --------------
+             4
+ (1 row)
+ 
+ SELECT num_notnulls(VARIADIC '{1,2,NULL,3}'::int[]);
+  num_notnulls 
+ --------------
+             3
+ (1 row)
+ 
+ SELECT num_notnulls(VARIADIC '{"1","2","3","4"}'::text[]);
+  num_notnulls 
+ --------------
+             4
+ (1 row)
+ 
+ SELECT num_notnulls(VARIADIC ARRAY(SELECT CASE WHEN i <> 40 THEN i END FROM generate_series(1, 100) i));
+  num_notnulls 
+ --------------
+            99
+ (1 row)
+ 
+ SELECT num_nulls(NULL);
+  num_nulls 
+ -----------
+          1
+ (1 row)
+ 
+ SELECT num_nulls('1');
+  num_nulls 
+ -----------
+          0
+ (1 row)
+ 
+ SELECT num_nulls(NULL::text);
+  num_nulls 
+ -----------
+          1
+ (1 row)
+ 
+ SELECT num_nulls(NULL::text, NULL::int);
+  num_nulls 
+ -----------
+          2
+ (1 row)
+ 
+ SELECT num_nulls(1, 2, NULL::text, NULL::point, '', int8 '9', 1.0 / NULL);
+  num_nulls 
+ -----------
+          3
+ (1 row)
+ 
+ SELECT num_nulls(VARIADIC '{1,2,NULL,3}'::int[]);
+  num_nulls 
+ -----------
+          1
+ (1 row)
+ 
+ SELECT num_nulls(VARIADIC '{"1","2","3","4"}'::text[]);
+  num_nulls 
+ -----------
+          0
+ (1 row)
+ 
+ SELECT num_nulls(VARIADIC ARRAY(SELECT CASE WHEN i <> 40 THEN i END FROM generate_series(1, 100) i));
+  num_nulls 
+ -----------
+          1
+ (1 row)
+ 
+ -- special cases
+ SELECT num_notnulls(VARIADIC NULL::text[]);
+  num_notnulls 
+ --------------
+              
+ (1 row)
+ 
+ SELECT num_notnulls(VARIADIC '{}'::int[]);
+  num_notnulls 
+ --------------
+             0
+ (1 row)
+ 
+ SELECT num_nulls(VARIADIC NULL::text[]);
+  num_nulls 
+ -----------
+           
+ (1 row)
+ 
+ SELECT num_nulls(VARIADIC '{}'::int[]);
+  num_nulls 
+ -----------
+          0
+ (1 row)
+ 
+ -- should fail, one or more arguments is required
+ SELECT num_notnulls();
+ ERROR:  function num_notnulls() does not exist
+ LINE 1: SELECT num_notnulls();
+                ^
+ HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+ SELECT num_nulls();
+ ERROR:  function num_nulls() does not exist
+ LINE 1: SELECT num_nulls();
+                ^
+ HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
new file mode 100644
index b1bc7c7..bec0316
*** a/src/test/regress/parallel_schedule
--- b/src/test/regress/parallel_schedule
*************** test: brin gin gist spgist privileges se
*** 89,95 ****
  # ----------
  # Another group of parallel tests
  # ----------
! test: alter_generic alter_operator misc psql async dbsize
  
  # rules cannot run concurrently with any test that creates a view
  test: rules
--- 89,95 ----
  # ----------
  # Another group of parallel tests
  # ----------
! test: alter_generic alter_operator misc psql async dbsize misc_functions
  
  # rules cannot run concurrently with any test that creates a view
  test: rules
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
new file mode 100644
index ade9ef1..7e9b319
*** a/src/test/regress/serial_schedule
--- b/src/test/regress/serial_schedule
*************** test: misc
*** 119,124 ****
--- 119,125 ----
  test: psql
  test: async
  test: dbsize
+ test: misc_functions
  test: rules
  test: select_views
  test: portals_p2
diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql
new file mode 100644
index ...bc3a185
*** a/src/test/regress/sql/misc_functions.sql
--- b/src/test/regress/sql/misc_functions.sql
***************
*** 0 ****
--- 1,31 ----
+ --
+ -- num_nulls()
+ --
+ 
+ SELECT num_notnulls(NULL);
+ SELECT num_notnulls('1');
+ SELECT num_notnulls(NULL::text);
+ SELECT num_notnulls(NULL::text, NULL::int);
+ SELECT num_notnulls(1, 2, NULL::text, NULL::point, '', int8 '9', 1.0 / NULL);
+ SELECT num_notnulls(VARIADIC '{1,2,NULL,3}'::int[]);
+ SELECT num_notnulls(VARIADIC '{"1","2","3","4"}'::text[]);
+ SELECT num_notnulls(VARIADIC ARRAY(SELECT CASE WHEN i <> 40 THEN i END FROM generate_series(1, 100) i));
+ 
+ SELECT num_nulls(NULL);
+ SELECT num_nulls('1');
+ SELECT num_nulls(NULL::text);
+ SELECT num_nulls(NULL::text, NULL::int);
+ SELECT num_nulls(1, 2, NULL::text, NULL::point, '', int8 '9', 1.0 / NULL);
+ SELECT num_nulls(VARIADIC '{1,2,NULL,3}'::int[]);
+ SELECT num_nulls(VARIADIC '{"1","2","3","4"}'::text[]);
+ SELECT num_nulls(VARIADIC ARRAY(SELECT CASE WHEN i <> 40 THEN i END FROM generate_series(1, 100) i));
+ 
+ -- special cases
+ SELECT num_notnulls(VARIADIC NULL::text[]);
+ SELECT num_notnulls(VARIADIC '{}'::int[]);
+ SELECT num_nulls(VARIADIC NULL::text[]);
+ SELECT num_nulls(VARIADIC '{}'::int[]);
+ 
+ -- should fail, one or more arguments is required
+ SELECT num_notnulls();
+ SELECT num_nulls();
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to