#!/bin/bash

RESULTS=$(mktemp)

# connection options to unpatched server
dbcnx1="-h /tmp -p 5401 -d postgres"

# connection options to patched server
dbcnx2="-h /tmp -p 5410 -d postgres"

# unpatched psql
psql1="/usr/local/pghead/bin/psql"

# patched psql
psql2="/usr/local/pgsql/bin/psql"

function test_copy
{
    local psql="$1 -vON_ERROR_STOP=1 -Atq"
    local datafile="$2"
    local expected_output="$3"
    local copy_kind="$4"
    local output_file=$(mktemp)
    local copy_format

    if [[ $datafile =~ \.csv$ ]]; then
	copy_format="csv"
    elif [[ $datafile =~ \.txt$ ]]; then
	copy_format="text"
    else
	echo 1>&2 "copy format not guessed from the data file extension. Use .txt or .csv"
	exit 1
    fi
    case "$copy_kind" in
	"copy"|"\copy")
	$psql  <<EOF >"$output_file"
create temp table copytest(lineno serial, t text);
$copy_kind copytest(t) from '$datafile' (format $copy_format) ;
select * from copytest order by lineno;
EOF
	res=$?
	;;

	"pstdin")
	    cmdfile=$(mktemp)
	    cat >"$cmdfile" <<EOF
create temp table copytest(lineno serial, t text);
\copy copytest(t) from pstdin (format $copy_format)
select * from copytest order by lineno;
EOF
	    $psql -f "$cmdfile" < "$datafile" >"$output_file"
	    res=$?
	    rm "$cmdfile"
	    ;;

	"embedded")
	    cmdfile=$(mktemp)
	    cat >"$cmdfile" <<EOF
create temp table copytest(lineno serial, t text);
copy copytest(t) from stdin (format $copy_format);
`cat $datafile`
\.
select * from copytest order by lineno;
EOF
	    $psql -f "$cmdfile" >"$output_file"
	    res=$?
	    rm "$cmdfile"
	    ;;
    esac

    if [ $res = "0" ]; then
	cmp -s "$expected_output" "$output_file"
	res=$?
    fi
    rm "$output_file"
    return $res
}

function output_result
{
    echo "$1,$2,$3,$4,$5" >> "$RESULTS"
}

function run_tests
{
    local csvfile=$(mktemp --suffix=.csv)
    local txtfile=$(mktemp --suffix=.txt)
    local expected=$(mktemp)
    local dbcnx;
    local psql

    if [ "$1" = "unpatched-server" ]; then
	dbcnx="$dbcnx1"
    elif [ "$1" = "patched-server" ]; then
	dbcnx="$dbcnx2"
    else
	echo 1>&2 "Unrecognized argument: $1"
	exit 1
    fi

    if [ "$2" = "unpatched-psql" ]; then
	psql="$psql1"
    elif [ "$2" = "patched-psql" ]; then
	psql="$psql2"
    else
	echo 2>&1 "Unrecognized argument: $2"
	exit 1
    fi

    ##
    # Case A. quoted backslash-dot sequence in CSV
    ##
    cat >"$csvfile" <<EOF
ab
"
\.
"
cd
EOF

    cat >"$expected" <<EOF
1|ab
2|
\.

3|cd
EOF

    for method in "\copy" "copy" "pstdin" "embedded"
    do
      test_copy "$psql $dbcnx" "$csvfile" "$expected" "$method"
      output_result A $1 $2 "$method" $?
    done

    ##
    # Case B. unquoted backslash-dot sequence in CSV
    ##

    cat >"$csvfile" <<EOF
ab
\.
cd
EOF

    cat >"$expected" <<EOF
1|ab
2|\.
3|cd
EOF

    for method in "\copy" "copy" "pstdin" "embedded"
    do
      test_copy "$psql $dbcnx" "$csvfile" "$expected" "$method"
      output_result B $1 $2 "$method" $?
    done

    ##
    # Case C. CSV without backslash-dot
    ##
    cat >"$csvfile" <<EOF
ab
cd
EOF

    cat >"$expected" <<EOF
1|ab
2|cd
EOF
    for method in "\copy" "copy" "pstdin" "embedded"
    do
      test_copy "$psql $dbcnx" "$csvfile" "$expected" "$method"
      output_result C $1 $2 "$method" $?
    done

    ##
    # Case D. Normal text mode (not csv) with backslash-dot sequence at the end.
    # First check "embedded" without the backslash-dot sequence
    # in the data, as it's added automatically by the test,
    # then add the backslash-dot to the data and do the other tests
    ##
    
    cat >"$txtfile" <<EOF
ab
cd
EOF

    cat >"$expected" <<EOF
1|ab
2|cd
EOF
    test_copy "$psql $dbcnx" "$txtfile" "$expected" "embedded"
    output_result D $1 $2 "embedded" $?

    echo "\." >> $txtfile

    for method in "\copy" "copy" "pstdin"
    do
      test_copy "$psql $dbcnx" "$txtfile" "$expected" "$method"
      output_result D $1 $2 "$method" $?
    done

    ##
    # Case E. Normal text mode (not csv) without backslash-dot sequence at the end.
    ##
    
    cat >"$txtfile" <<EOF
ab
cd
EOF

    cat >"$expected" <<EOF
1|ab
2|cd
EOF

    for method in "\copy" "copy" "pstdin" "embedded"
    do
      test_copy "$psql $dbcnx" "$txtfile" "$expected" "$method"
      output_result E $1 $2 "$method" $?
    done

    rm "$txtfile" "$csvfile" "$expected"
}

# Import the CSV file with results into a table
function import_results
{
  
  $psql2 -q $dbcnx2 << EOF
\set ON_ERROR_STOP 1
CREATE TABLE IF NOT EXISTS copytest_results (
 case_no text,
 server text,
 psql text,
 method text,
 result integer
);
truncate table copytest_results;
\copy copytest_results from '$1' csv
EOF
}

function display_results
{
for case_no in A B C D E
do
    echo "Case $case_no"
    
$psql2 -q $dbcnx2 <<EOF
\pset footer off
\pset border 2

select method,server||chr(10)||psql,
  case result
    when 0 then 'OK'
    when 1 then 'Data mismatch'
    when 3 then 'Failed'
   end
 from copytest_results
where case_no='$case_no'
 order by method
\crosstabview

EOF
done
}


run_tests "patched-server" "patched-psql"
run_tests "patched-server" "unpatched-psql"
run_tests "unpatched-server" "patched-psql"
run_tests "unpatched-server" "unpatched-psql"


import_results "$RESULTS"
display_results
rm "$RESULTS"
