1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-11 00:52:44 +03:00
mal/plsql/wrap.sh
2016-05-22 00:18:25 -06:00

123 lines
3.4 KiB
Bash
Executable File

#!/bin/bash
RL_HISTORY_FILE=${HOME}/.mal-history
SKIP_INIT="${SKIP_INIT:-}"
ORACLE_LOGON=${ORACLE_LOGON:-system/oracle}
SQLPLUS="sqlplus -S ${ORACLE_LOGON}"
FILE_PID=
cleanup() {
trap - TERM QUIT INT EXIT
#echo cleanup: ${FILE_PID}
[ "${FILE_PID}" ] && kill ${FILE_PID}
}
trap "cleanup" TERM QUIT INT EXIT
# Load the SQL code
if [ -z "${SKIP_INIT}" ]; then
out=$(echo "" | ${SQLPLUS} @$1)
if echo "${out}" | grep -vs "^No errors.$" \
| grep -si error >/dev/null; then
#if echo "${out}" | grep -si error >/dev/null; then
echo "${out}"
exit 1
fi
fi
# open I/O streams
echo -e "BEGIN io.open(0); io.open(1); END;\n/" \
| ${SQLPLUS} >/dev/null
# Stream from table to stdout
(
while true; do
out="$(echo "SELECT io.read(1) FROM dual;" \
| ${SQLPLUS} 2>/dev/null)" || break
#echo "out: [${out}] (${#out})"
echo "${out}"
done
) &
STDOUT_PID=$!
# Perform readline input into stream table when requested
(
[ -r ${RL_HISTORY_FILE} ] && history -r ${RL_HISTORY_FILE}
while true; do
prompt=$(echo "SELECT io.wait_rl_prompt(0) FROM dual;" \
| ${SQLPLUS} 2>/dev/null) || break
# Prompt is returned single-quoted because sqlplus trims trailing
# whitespace. Remove the single quotes from the beginning and end:
prompt=${prompt%\'}
prompt=${prompt#\'}
#echo "prompt: [${prompt}]"
IFS= read -u 0 -r -e -p "${prompt}" line || break
if [ "${line}" ]; then
history -s -- "${line}" # add to history
history -a ${RL_HISTORY_FILE} # save history to file
fi
# Escape (double) single quotes per SQL norm
line=${line//\'/\'\'}
#echo "line: [${line}]"
( echo -n "BEGIN io.writeline('${line}', 0); END;";
echo -en "\n/" ) \
| ${SQLPLUS} >/dev/null || break
done
echo -e "BEGIN io.close(0); END;\n/" \
| ${SQLPLUS} > /dev/null
) <&0 >&1 &
# File read if requested
(
while true; do
files="$(echo "SELECT path FROM file_io WHERE in_or_out = 'in';" \
| ${SQLPLUS} 2>/dev/null \
| grep -v "^no rows selected")" || break
for f in ${files}; do
if [ ! -r ${f} ]; then
echo "UPDATE file_io SET error = 'Cannot read ''${f}''' WHERE path = '${f}' AND in_or_out = 'in';" \
| ${SQLPLUS} >/dev/null
continue;
fi
IFS= read -rd '' content < "${f}"
# sqlplus limits lines to 2499 characters so split the update
# into chunks of the file ORed together over multiple lines
query="UPDATE file_io SET data = TO_CLOB('')"
while [ -n "${content}" ]; do
chunk="${content:0:2000}"
content="${content:${#chunk}}"
chunk="${chunk//\'/\'\'}"
chunk="${chunk//$'\n'/\\n}"
query="${query}"$'\n'" || TO_CLOB('${chunk}')"
done
query="${query}"$'\n'" WHERE path = '${f}' AND in_or_out = 'in';"
echo "${query}" | ${SQLPLUS} > /dev/null
#echo "file read: ${f}: ${?}"
done
sleep 1
done
) &
FILE_PID=$!
res=0
shift
if [ $# -gt 0 ]; then
# If there are command line arguments then run a command and exit
args=$(for a in "$@"; do echo -n "\"$a\" "; done)
echo -e "SELECT mal.MAIN('(${args})') FROM dual;" \
| ${SQLPLUS} > /dev/null
res=$?
else
# Start main loop in the background
echo "SELECT mal.MAIN() FROM dual;" \
| ${SQLPLUS} > /dev/null
res=$?
fi
# Wait for output to flush
wait ${STDOUT_PID}
exit ${res}