#****************************************************************************
#  ##   ##         #####   #####  ##     **       NoSQL RDBMS - column      *
#  ###  ##        ####### ####### ##     **        $Revision: 2.1 $			*
#  #### ##        ###     ##   ## ##     ************************************
#  #######  ####  #####   ##   ## ##     **      Carlo Strozzi (c) 1998     *
#  ####### ######   ##### ## # ## ##     ************************************
#  ## #### ##  ##     ### ##  ### ##     **           Written by            *
#  ##  ### ###### ####### ######  ###### **          Carlo Strozzi          *
#  ##   ##  ####   #####   #### # ###### **     e-mail: carlos@linux.it     *
#****************************************************************************
#   NoSQL RDBMS, Copyright (C) 1998 Carlo Strozzi.                          *
#   This program comes with ABSOLUTELY NO WARRANTY; for details             *
#   refer to the GNU General Public License.                                *
#****************************************************************************
#
#  Checks whether fields are null.
#
#  Takes a NoSQL table on STDIN and checks the specified fields for null
#  values. Returns 0 if the match is succesful, or 255 otherwise.
#
#  Usage:  nosql null [options] column [column ...] < table
#
#  Options:
#    -b|--also-blank    Treat blanks as nulls.
#    -a|--all           Return 0 if all of the specified columns are NULL
#                       (default).
#    -A|--any           Return 0 if any of the specified columns are NULL.
#    -v|--verbose       Report null fields verbosely to STDERR.
#
#  For multi-record tables, a field is considered to be NULL if it is NULL
#  in at least one of the input records.
#
#  This NoSQL operator reads a table from STDIN and returns the
#  appropriate exit code to the calling program.
#
########################################################################

########################################################################
# BEGIN block
########################################################################

BEGIN \
{
  NULL = ""; FS = OFS = "\t"; all = 1;

  split( __nosql_args, args, " " )

  while ( args[++i] != NULL )
  {
	# Separate options from column names.
	if ( args[i] !~ /^-/ )
	{
	  cols[++j] = args[i]
	  continue
	}

	if ( args[i] == "-b" || args[i] == "--also-blank" ) blanks = 1
	else if ( args[i] == "-a" || args[i] == "--all" ) all = 1
    else if ( args[i] == "-A" || args[i] == "--any" ) all = 0
    else if ( args[i] == "-v" || args[i] == "--verbose" ) verbose = 1
  }

  # Exit 255 if no columns were specified.

  if ( j > 0 ) cols[0] = j
  else exit 255
}

########################################################################
# Main loop
########################################################################

NR == 1 \
{
  # Load the column position array.
  while ( ++p <= NF )
  {
    # Make sure we pick the first occurrence of duplicated column
    # names (it may happen after a join).

    if ( P[$p] == NULL ) { P[$p] = p; N[p] = $p }
  }
}

NR > 2 \
{
  # Now test each input field in turn.
  for ( i = 1; i <= NF; i++ )
  {
	# Skip duplicated columns.
	if ( N[i] != NULL )
	{
      if ( blanks )
      {
        if ( $i !~ /^ *$/ ) { S[ N[i] ] = 1 }
      }
      else
      {
        if ( $i != NULL ) { S[ N[i] ] = 1 }
      }
	}
  }
}

END \
{
  for ( i = 1; i <= cols[0]; i++ )
  {
	# Case '--any'.
	if ( ! S[ cols[i] ] )
	{
	  nullfields++
	  if ( verbose )
		print "nosql null: column '" cols[i] "' is NULL" > "/dev/stderr"

	  if ( !all && nullfields ) exit 0
	}
  }

  # Case '--all'.
  if ( nullfields == cols[0] ) exit 0

  exit 255
}

