#!/bin/sh
#
# Allows safe in-place replacement of a NoSQL table.
#

RCS_ID='$Id: nsq-tee,v 1.1 1998/05/29 20:34:57 carlos Exp $'

my_name=$(basename $0)

while [ $# -ge 1 ] ; do
  case $1 in
    -h*) cat <<_EOH_

        NoSQL operator: ${my_name}

Usage:  ${my_name}  [options]  rdbtable

Options:
    -b      Take a preventive backup copy of a pre-existing
            "rdbtable" with the same name.
    -s      Suppress writing the table to STDOUT.
    -R[CS]  Use RCS on the output table.
    -h      Print this help info.
    -N      Do not lock output table (use with caution).
    -S      Split output table into separate header and body files.
            The two file names will be rdbtable.H and rdbtable.B
            respectively.
    -c N    If 'S' was specifiead, split the body into chunks of
            size 'N' lines each at most, with N >= 1.
    -U      Force unlocking upon exiting, even if '-N' was
            specified (also to be used with caution).

It can be safely used in constructs like :

    nsq-compute ... < rdbtable | nsq-tee rdbtable | ...

without worring that the original input rdbtable be destroyed
before the pipeline has completed.

This operator reads an rdbtable via STDIN and produces the same
rdbtable on STDOUT, [over]writing the rdbtable "output_table"
given as a command line argument. It's function is similar to 
that of the UNIX utility 'tee'.

$RCS_ID

            ----------------------
NoSQL RDBMS, Copyright (C) 1998 Carlo Strozzi.
This program comes with ABSOLUTELY NO WARRANTY; for details
refer to the GNU General Public License.

You should have received a copy of the GNU General Public License
along with this program;  if not, write to the Free Software
Foundation, Inc., 59 Temple Place Suite 330, Boston, MA 02111-1307
USA.
            ----------------------

_EOH_
        exit 0
        ;;
    -b)    shift; do_backup=1          ;;
    -R*)   shift; use_rcs=1            ;;
    -s)    shift; no_stdout=1          ;;
    -c)    shift; chunk_size=$1; shift ;;
    -N)    shift; no_lock=1            ;;
    -S)    shift; split_tbl=1          ;;
    -U)    shift; unlock=1             ;;
    *)     out_tbl=$1; break           ;;
  esac
done

# Prevent possible clobbering of backup table.

case ${out_tbl} in
  ""|-*)
    echo "Usage: ${my_name} [options] output_table" >&2
    exit 2
    ;;
esac

out_tbl="$(basename $1)"
out_dir="$(dirname $1)"

if [ "${split_tbl}" ]
then
  tbl_hdr=${out_tbl}.H
  tbl_body=${out_tbl}.B
fi

# Everything is relative to the target directory.
cd ${out_dir} || exit 5

[ "${no_lock}" = 1 ] || lock_list="${out_tbl}.LCK"

if [ "${do_backup}" ]
then
    lock_list="${lock_list} ,${out_tbl}.LCK"
fi

trap_list="${lock_list}"

tmp_file=${out_tbl}.t.$$

trap_list="${trap_list} ${tmp_file}"

# Call external table-locking program. 
if [ "${lock_list}" ]
then
    ${NSQLOCKER:-nsq-lock} ${lock_list} || exit 4
fi

# Trapping MUST be done AFTER locking, not to remove
# someone else's lock on exit. The latter can be removed
# only if '-U' was specified.

[ "${unlock}" = 1 ] && trap_list="${trap_list} ${out_tbl}.LCK"

trap  "rm -f ${trap_list}" 0 1 2 3 11 13 15

[ "${do_backup}" ] && [ -f ${out_tbl} ] && cp ${out_tbl} ,${out_tbl}

cat > ${tmp_file}

# Do not overwrite the table stright away, as we may be using
# it as an input to the pipeline. Furthermore, the input stream may
# be empty.

if [ -s ${tmp_file} ]
then
  if [ "${use_rcs}" ]
  then
	if [ "${do_backup}" ]
	then
	  # Back-up the previous RCS file before modifying it.
	  chmod u+w ,${out_tbl},v RCS/,${out_tbl},v
	  if cp -p ${out_tbl},v ,${out_tbl},v
	  then
		:
	  else
		cp -p RCS/${out_tbl},v RCS/,${out_tbl},v
	  fi
	fi
    # Handle RCS versioning on output table.
    co -q -l ${out_tbl}
  fi

  # Use 'mv' to make the operation faster.
  mv ${tmp_file} ${out_tbl} 

  if [ "${use_rcs}" ]
  then
    # Handle RCS versioning on output table.
    echo "." | ci -q -u -f ${out_tbl}
  fi

  [ -z "${no_stdout}" ] && cat ${out_tbl}

  if [ "${split_tbl}" ]
  then
	# Backup any previous copies of the two output files.
	cp -p ${out_tbl}.H ,${out_tbl}.H
	cp -p ${out_tbl}.B ,${out_tbl}.B

    # Add main table to cleanup list.
    trap_list="${trap_list} ${out_tbl}"
    trap  "rm -f ${trap_list}" 0 1 2 3 11 13 15

    awk 'BEGIN { NULL=""; FS="\t"; OFS=FS; }
    # Table comments.
    r==0 && $0 ~ /^ *#/ { print > "'"${tbl_hdr}"'"; next; }
	# Column names and defs.
	r < 2 { print > "'"${tbl_hdr}"'"; r++; next; }
	# Actual table body.
	{ print > "'"${tbl_body}"'" }' ${out_tbl}
  fi
 
  if [ ${chunk_size:-0} -gt 0 ]
  then
	split -l ${chunk_size} ${tbl_body} "${tbl_body}-"
	trap_list="${trap_list} ${tbl_body}"
    trap  "rm -f ${trap_list}" 0 1 2 3 11 13 15
  fi
fi

exit 0

