*** ./command.c.orig 2009-12-18 09:18:14.000000000 +0100
--- ./command.c 2009-12-30 20:02:04.002183749 +0100
***************
*** 48,53 ****
--- 48,54 ----
#include "mainloop.h"
#include "print.h"
#include "psqlscan.h"
+ #include "psqlscript.h"
#include "settings.h"
#include "variables.h"
***************
*** 63,68 ****
--- 64,72 ----
static bool lookup_function_oid(PGconn *conn, const char *desc, Oid *foid);
static bool get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf);
static void minimal_error_message(PGresult *res);
+ static PGresult *fetch_next(char *cursor_name);
+ static bool exec_boolean_expr(char *expr, bool *success);
+
static void printSSLInfo(void);
***************
*** 70,77 ****
static void checkWin32Codepage(void);
#endif
-
-
/*----------
* HandleSlashCmds:
*
--- 74,79 ----
***************
*** 102,110 ****
/* Parse off the command name */
cmd = psql_scan_slash_command(scan_state);
!
! /* And try to execute it */
! status = exec_command(cmd, scan_state, query_buf);
if (status == PSQL_CMD_UNKNOWN)
{
--- 104,125 ----
/* Parse off the command name */
cmd = psql_scan_slash_command(scan_state);
!
! if (!pset.skip_mode
! || strcmp(cmd, "endif") == 0
! || strcmp(cmd, "else") == 0
! || strcmp(cmd, "elseif") == 0
! || strcmp(cmd, "endforc") == 0
! || strcmp(cmd, "if") == 0
! || strcmp(cmd, "forc") == 0
! || strcmp(cmd, "ifdef") == 0
! || strcmp(cmd, "endifdef") == 0
! || strcmp(cmd, "newcommand") == 0
! || strcmp(cmd, "endnewcommand") == 0)
! {
! /* And try to execute it */
! status = exec_command(cmd, scan_state, query_buf);
! }
if (status == PSQL_CMD_UNKNOWN)
{
***************
*** 115,121 ****
status = PSQL_CMD_ERROR;
}
! if (status != PSQL_CMD_ERROR)
{
/* eat any remaining arguments after a valid command */
/* note we suppress evaluation of backticks here */
--- 130,136 ----
status = PSQL_CMD_ERROR;
}
! if (status != PSQL_CMD_ERROR && !pset.skip_mode)
{
/* eat any remaining arguments after a valid command */
/* note we suppress evaluation of backticks here */
***************
*** 619,624 ****
--- 634,868 ----
}
}
+ else if (strcmp(cmd, "else") == 0)
+ {
+ /* check current_stmt, should be PSQL_IF or PSQL_IFDEF */
+ if (pset.current_stmt->typ != PSQL_IF && pset.current_stmt->typ != PSQL_IFDEF)
+ {
+ psql_error("\\%s: without \\if or \\ifdef\n", cmd);
+ success = false;
+ }
+ else
+ {
+ psqlNestedIf *nestedif = (psqlNestedIf *) pset.current_stmt;
+
+ if (!nestedif->outer_skip_mode)
+ {
+ if (!nestedif->successful)
+ {
+ pset.skip_mode = false;
+ nestedif->successful = true;
+ }
+ else
+ pset.skip_mode = true;
+ }
+ }
+ }
+
+ else if (strcmp(cmd, "endif") == 0)
+ {
+ pset.current_stmt = remove_stmt(pset.current_stmt, PSQL_IF, cmd, &status, &pset.skip_mode);
+ }
+
+ else if (strcmp(cmd, "endifdef") == 0)
+ {
+ pset.current_stmt = remove_stmt(pset.current_stmt, PSQL_IFDEF, cmd, &status, &pset.skip_mode);
+ }
+
+ else if (strcmp(cmd, "endforc") == 0)
+ {
+ /*
+ * fetch record from cursor,
+ * if not NULL, then pop stacked lines, and repeat processing
+ */
+ if (!pset.current_loop || pset.current_loop->typ != PSQL_FORC)
+ {
+ psql_error("\\endforc without forc\n");
+ /* error already reported */
+ status = PSQL_CMD_ERROR;
+ }
+ else
+ {
+ char *cursor_name;
+ PGresult *res;
+
+ psql_assert(pset.current_loop);
+ psql_assert(pset.current_loop->typ == PSQL_FORC);
+
+ cursor_name = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, true);
+
+ if (cursor_name && strcmp(cursor_name, pset.current_loop->params.cursor_name) != 0)
+ {
+ psql_error("unmatched cursor name: %s is different than %s\n",
+ cursor_name,
+ pset.current_loop->params.cursor_name);
+ status = PSQL_CMD_ERROR;
+ }
+ else if (pset.skip_mode || pset.current_loop->lines->len == 0)
+ {
+ /*
+ * Process statement, but doesn't activate anything.
+ * because cycle is blocked in this moment, we can
+ * remove this cycle.
+ */
+ pset.current_loop = remove_loop(pset.current_loop,
+ PSQL_FORC,
+ cmd,
+ &status,
+ &pset.skip_mode);
+ pset.current_stmt = remove_stmt(pset.current_stmt,
+ PSQL_FORC,
+ cmd,
+ &status,
+ &pset.skip_mode);
+ }
+ else
+ {
+ res = fetch_next(pset.current_loop->params.cursor_name);
+
+ if (!res)
+ {
+ /* ToDo: free cur_nested_block */
+ success = false;
+ }
+ else
+ {
+ if (PQntuples(res) > 0)
+ {
+ int i;
+
+ psql_assert(PQntuples(res) == 1);
+ psql_assert(pset.current_loop->lines->len > 0);
+
+ /* refresh cursor variables */
+ for (i = 0; i < PQnfields(res); i++)
+ SetVariable(pset.vars, PQfname(res,i),
+ PQgetvalue(res, 0, i));
+
+ /* lock buffer - repeat same code */
+ pset.current_loop->writeable = false;
+ /* copy stacked code to readable buffer */
+ if (pset.current_loop->restored_lines == NULL)
+ pset.current_loop->restored_lines = pg_malloc(pset.current_loop->lines->len);
+
+ memcpy(pset.current_loop->restored_lines, pset.current_loop->lines->data,
+ pset.current_loop->lines->len);
+ pset.current_loop->reader_pos = pset.current_loop->restored_lines;
+ }
+ else
+ {
+ /* it was last cycle */
+
+ /*
+ * because psql variables are not stacked, we don't remove
+ * cursors variables on the end.
+ */
+ pset.current_loop = remove_loop(pset.current_loop,
+ PSQL_FORC,
+ cmd,
+ &status,
+ &pset.skip_mode);
+ pset.current_stmt = remove_stmt(pset.current_stmt,
+ PSQL_FORC,
+ cmd,
+ &status,
+ &pset.skip_mode);
+ }
+ }
+
+ PQclear(res);
+ }
+
+ if (cursor_name)
+ free(cursor_name);
+ }
+ }
+
+ /* \endnewcommand */
+ else if (strcmp(cmd, "endnewcommand") == 0)
+ {
+ if (pset.custom_statements == NULL || pset.custom_statements->writer == NULL)
+ {
+ psql_error("\\endnewcommand without newcommand\n");
+ status = PSQL_CMD_ERROR;
+ }
+ else
+ {
+ char *name = pset.custom_statements->name;
+ psqlCustomStatement *next = pset.custom_statements->next;
+ psqlCustomStatement *current = pset.custom_statements;
+
+ /* remove stmt from stack */
+ pset.current_stmt = remove_stmt(pset.current_stmt,
+ PSQL_NEWCOMMAND,
+ cmd,
+ &status,
+ &pset.skip_mode);
+
+ /* when outer skip_mode is enabled, then this definition is fake */
+ if (pset.skip_mode)
+ {
+ destroyPQExpBuffer(current->writer);
+ pset.custom_statements = next;
+ free(current);
+ }
+ else
+ {
+ /*
+ * Safe src of currently defined command. We have to remove
+ * last two lines (last line have to be empty).
+ */
+ int len = current->writer->len - 1;
+ char *rightptr = current->writer->data + current->writer->len - 2; /* \n\0 */
+
+ while (len > 0 && *rightptr != '\n')
+ {
+ len -= 1;
+ rightptr--;
+ }
+
+ psql_assert(strcmp(rightptr+1,"\\endnewcommand\n") == 0);
+ *rightptr = '\0';
+
+ /* drop older definition of command if exists */
+ while (next != NULL)
+ {
+ if (strcmp(name, next->name) == 0)
+ {
+ /* find command to overwrite */
+ current->next = next->next;
+ free(next->name);
+ free(next->src);
+ free(next);
+
+ break;
+ }
+
+ current = next;
+ next = next->next;
+ }
+
+ if (len > 0)
+ {
+ /* store src */
+ pset.custom_statements->src = pg_strdup(pset.custom_statements->writer->data);
+ destroyPQExpBuffer(pset.custom_statements->writer);
+ pset.custom_statements->writer = NULL;
+ }
+ else
+ {
+ /* don't store empty command */
+ next = pset.custom_statements->next;
+ free(pset.custom_statements->name);
+ destroyPQExpBuffer(pset.custom_statements->writer);
+ free(pset.custom_statements);
+ pset.custom_statements = next;
+ }
+ }
+ }
+ }
+
/* \f -- change field separator */
else if (strcmp(cmd, "f") == 0)
{
***************
*** 629,634 ****
--- 873,936 ----
free(fname);
}
+ else if (strcmp(cmd, "forc") == 0)
+ {
+ char *cursor_name;
+
+ cursor_name = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, true);
+ if (!cursor_name)
+ {
+ psql_error("\\for: missing cursor name\n");
+ /* error already reported */
+ status = PSQL_CMD_ERROR;
+ }
+ else if (pset.skip_mode)
+ {
+ /* do fake */
+ pset.current_loop = new_for_cursor(cursor_name, pset.current_loop, pset.skip_mode);
+ pset.current_stmt = new_loop(pset.current_stmt, PSQL_FORC, pset.skip_mode);
+ }
+ else
+ {
+ PGresult *res;
+
+ /*
+ * fetch first record from cursor,
+ * process and stack all lines to \endfor
+ */
+ res = fetch_next(cursor_name);
+
+ if (res)
+ {
+ /* create new loop */
+ pset.current_loop = new_for_cursor(cursor_name, pset.current_loop, pset.skip_mode);
+ pset.current_stmt = new_loop(pset.current_stmt, PSQL_FORC, pset.skip_mode);
+
+ if (PQntuples(res) > 0)
+ {
+ int i;
+
+ psql_assert(PQntuples(res) == 1);
+
+ /* create or refresh cursor's variables */
+ for (i = 0; i < PQnfields(res); i++)
+ SetVariable(pset.vars, PQfname(res,i),
+ PQgetvalue(res, 0, i));
+ }
+ else
+ {
+ /* zero loop */
+ pset.skip_mode = true;
+ }
+
+ PQclear(res);
+ }
+ else
+ success = false;
+ }
+ }
+
/* \g means send query */
else if (strcmp(cmd, "g") == 0)
{
***************
*** 685,696 ****
--- 987,1242 ----
}
}
+ /* \if expr */
+ else if (strcmp(cmd, "if") == 0 || strcmp(cmd, "elseif") == 0)
+ {
+ char *expr;
+ char *el;
+
+ el = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, true);
+ expr = pg_strdup(el ? el : "");
+ free(el);
+
+ while ((el = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, false)))
+ {
+ expr = realloc(expr, strlen(expr) + strlen(el) + 2);
+ if (!expr)
+ {
+ psql_error("out of memory\n");
+ exit(EXIT_FAILURE);
+ }
+ strcat(expr, " "); /* don't drop spaces */
+ strcat(expr, el);
+ free(el);
+ }
+
+ if (strcmp(expr,"") == 0)
+ {
+ psql_error("\\%s: missing required argument\n", cmd);
+ success = false;
+ }
+ else if (strcmp(cmd, "elseif") == 0)
+ {
+ /* check current_stmt, should be PSQL_IF */
+ if (pset.current_stmt->typ != PSQL_IF)
+ {
+ psql_error("\\%s: without \\if\n", cmd);
+ success = false;
+ }
+ else
+ {
+ /*
+ * Don't create new nested_stmt for elseif.
+ */
+ psqlNestedIf *nestedif = (psqlNestedIf *) pset.current_stmt;
+ if (!nestedif->successful && !nestedif->outer_skip_mode)
+ {
+ bool result = exec_boolean_expr(expr, &success);
+ if (success)
+ {
+ pset.skip_mode = !result;
+ nestedif->successful = true;
+ }
+ else
+ pset.skip_mode = true;
+ }
+ }
+ }
+ else if (pset.skip_mode)
+ {
+ /* fake statement */
+ pset.current_stmt = new_if(pset.current_stmt, PSQL_IF, pset.skip_mode);
+ ((psqlNestedIf *) pset.current_stmt)->successful = true;
+ }
+ else
+ {
+ bool result;
+
+ pset.current_stmt = new_if(pset.current_stmt, PSQL_IF, pset.skip_mode);
+ result = exec_boolean_expr(expr, &success);
+ if (success)
+ {
+ pset.skip_mode = !result;
+ ((psqlNestedIf *) pset.current_stmt)->successful = true;
+ }
+ else
+ pset.skip_mode = false;
+ free(expr);
+ }
+ }
+
+ /* \ifdef variable */
+ else if (strcmp(cmd, "ifdef") == 0 || strcmp(cmd, "elseifdef") == 0)
+ {
+ char *varname;
+
+ varname = psql_scan_slash_option(scan_state,
+ OT_NORMAL, NULL, true);
+
+ if (!varname)
+ {
+ psql_error("\\%s: missing required argument\n", cmd);
+ success = false;
+ }
+ else if (strcmp(cmd, "elseifdef") == 0)
+ {
+ /* check current_stmt, should be PSQL_IFDEF */
+ if (pset.current_stmt->typ != PSQL_IFDEF)
+ {
+ psql_error("\\%s: without \\if\n", cmd);
+ success = false;
+ }
+ else
+ {
+ /*
+ * Don't create new nested_stmt for elseif.
+ */
+ psqlNestedIf *nestedif = (psqlNestedIf *) pset.current_stmt;
+ if (!nestedif->successful && !nestedif->outer_skip_mode)
+ {
+ const char *value = GetVariable(pset.vars, varname);
+
+ if (value)
+ {
+ pset.skip_mode = false;
+ nestedif->successful = true;
+ }
+ else
+ pset.skip_mode = true;
+ }
+ }
+ }
+ else if (pset.skip_mode)
+ {
+ /* fake statement */
+ pset.current_stmt = new_if(pset.current_stmt, PSQL_IFDEF, pset.skip_mode);
+ ((psqlNestedIf *) pset.current_stmt)->successful = true;
+ }
+ else
+ {
+ const char *value = GetVariable(pset.vars, varname);
+
+ pset.current_stmt = new_if(pset.current_stmt, PSQL_IFDEF, pset.skip_mode);
+ ((psqlNestedIf *) pset.current_stmt)->successful = (value != NULL);
+ pset.skip_mode = (value == NULL);
+
+ free(varname);
+ }
+ }
+
+ /* \newcommand for define new command for psql */
+ else if (strcmp(cmd, "newcommand") == 0)
+ {
+ char *name;
+
+ name = psql_scan_slash_option(scan_state,
+ OT_WHOLE_LINE, NULL, true);
+
+ if (!name)
+ {
+ psql_error("\\newcommand: missing command name\n");
+ /* error already reported */
+ status = PSQL_CMD_ERROR;
+ }
+ else if (pset.skip_mode)
+ {
+ /* do fake */
+ pset.current_stmt = new_newcommand(pset.current_stmt, PSQL_NEWCOMMAND, pset.skip_mode);
+ pset.custom_statements = new_custom_statement("***fake***", pset.custom_statements, &status);
+ }
+ else
+ {
+ pset.current_stmt = new_newcommand(pset.current_stmt, PSQL_NEWCOMMAND, pset.skip_mode);
+ pset.custom_statements = new_custom_statement(name, pset.custom_statements, &status);
+
+ /* inside definition don't execute any statement */
+ pset.skip_mode = true;
+ }
+ }
+
/* \l is list databases */
else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
success = listAllDbs(false);
else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
success = listAllDbs(true);
+ else if (strcmp(cmd, "lf") == 0 || (strcmp(cmd, "lf-") == 0))
+ {
+ char *func;
+ Oid foid = InvalidOid;
+
+ func = psql_scan_slash_option(scan_state,
+ OT_WHOLE_LINE, NULL, true);
+ if (!query_buf)
+ {
+ psql_error("no query buffer\n");
+ status = PSQL_CMD_ERROR;
+ }
+ else
+ {
+ if (!func)
+ {
+ psql_error("missing function name");
+ status = PSQL_CMD_ERROR;
+ }
+ else if (!lookup_function_oid(pset.db, func, &foid))
+ {
+ /* error already reported */
+ status = PSQL_CMD_ERROR;
+ }
+ else if (!get_create_function_cmd(pset.db, foid, query_buf))
+ {
+ /* error already reported */
+ status = PSQL_CMD_ERROR;
+ }
+ else
+ {
+ char *cursor = query_buf->data;
+ char *line = cursor;
+ bool print_line_number = false;
+ int row_number = 1;
+
+ if (strcmp(cmd, "lf-") == 0)
+ fputs(query_buf->data, pset.queryFout);
+ else
+ {
+ /* print source code with line numbers */
+ while (*cursor != '\0')
+ {
+ if (*cursor == '\n')
+ {
+ *cursor = '\0';
+ if (strncmp(line, "AS $function$", 13) == 0)
+ {
+ print_line_number = true;
+ if (strlen(line) == 13)
+ {
+ fprintf(pset.queryFout, "****\t%s\n", line);
+ line = ++cursor;
+ continue;
+ }
+ }
+ else if (strcmp(line, "$function$") ==0)
+ print_line_number = false;
+
+ if (print_line_number)
+ fprintf(pset.queryFout, "%4d\t%s\n", row_number++, line);
+ else
+ fprintf(pset.queryFout, "****\t%s\n", line);
+ line = ++cursor;
+ }
+ else
+ cursor++;
+ }
+ }
+ if (func)
+ free(func);
+ }
+ }
+ }
+
/*
* large object things
*/
***************
*** 1762,1767 ****
--- 2308,2316 ----
size_t vallen = 0;
psql_assert(param);
+
+ if (pset.skip_mode)
+ return true;
if (value)
vallen = strlen(value);
***************
*** 1804,1812 ****
popt->topt.line_style = &pg_asciiformat_old;
else if (pg_strncasecmp("unicode", value, vallen) == 0)
popt->topt.line_style = &pg_utf8format;
else
{
! psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
return false;
}
--- 2353,2373 ----
popt->topt.line_style = &pg_asciiformat_old;
else if (pg_strncasecmp("unicode", value, vallen) == 0)
popt->topt.line_style = &pg_utf8format;
+ else if (pg_strncasecmp("custom-single", value, vallen) == 0)
+ popt->topt.line_style = &pg_utf8_custom_single_format;
+ else if (pg_strncasecmp("custom-double-border", value, vallen) == 0)
+ popt->topt.line_style = &pg_utf8_custom_double_border_format;
+ else if (pg_strncasecmp("custom-double-border-header", value, vallen) == 0)
+ popt->topt.line_style = &pg_utf8_custom_double_border_header_format;
+ else if (pg_strncasecmp("custom-double-border-header-columns", value, vallen) == 0)
+ popt->topt.line_style = &pg_utf8_custom_double_border_header_columns_format;
+ else if (pg_strncasecmp("custom-elegant", value, vallen) == 0)
+ popt->topt.line_style = &pg_utf8_custom_elegant_format;
else
{
! psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode,\n"
! " custom-single, custom-double-border, custom-double-border-header,\n"
! " custom-double-border-header-columns, custom-elegant\n");
return false;
}
***************
*** 1814,1819 ****
--- 2375,2422 ----
printf(_("Line style is %s.\n"),
get_line_style(&popt->topt)->name);
}
+
+ /* set header style */
+ else if (strcmp(param, "headerstyle") == 0)
+ {
+ if (!value)
+ ;
+ else if (pg_strncasecmp("left", value, vallen) == 0)
+ popt->topt.header_style = PRINT_HEADER_LEFT;
+ else if (pg_strncasecmp("center", value, vallen) == 0)
+ popt->topt.header_style = PRINT_HEADER_CENTER;
+ else if (pg_strncasecmp("right", value, vallen) == 0)
+ popt->topt.header_style = PRINT_HEADER_RIGHT;
+ else
+ {
+ psql_error("\\pset: allowed header styles are left, center, right.\n");
+ return false;
+ }
+
+ if (!quiet)
+ printf(_("Header style is %s.\n"),
+ get_header_style(popt->topt.header_style));
+ }
+
+ /* set wrapping style (applied only on text types) */
+ else if (strcmp(param, "textwrapping") == 0)
+ {
+ if (!value)
+ ;
+ else if (pg_strncasecmp("default", value, vallen) == 0)
+ popt->topt.textwrapping = TEXTWRAPPING_DEFAULT;
+ else if (pg_strncasecmp("flush-left", value, vallen) == 0)
+ popt->topt.textwrapping = TEXTWRAPPING_FLUSH_LEFT;
+ else
+ {
+ psql_error("\\pset: allowed textwrapping modes are default, flush-left\n");
+ return false;
+ }
+
+ if (!quiet)
+ printf(_("textwrapping mode is %s \n"),
+ get_textwrapping_mode(popt->topt.textwrapping));
+ }
/* set border style/width */
else if (strcmp(param, "border") == 0)
***************
*** 1837,1842 ****
--- 2440,2458 ----
? _("Expanded display is on.\n")
: _("Expanded display is off.\n"));
}
+
+ /* enable multiline in headers */
+ else if (strcmp(param, "multiline-header") == 0)
+ {
+ if (value)
+ popt->topt.multiline_header = ParseVariableBool(value);
+ else
+ popt->topt.multiline_header = !popt->topt.multiline_header;
+ if (!quiet)
+ printf(popt->topt.multiline_header
+ ? _("Multiline header is enabled.\n")
+ : _("Multiline header is disabled.\n"));
+ }
/* locale-aware numeric output */
else if (strcmp(param, "numericlocale") == 0)
***************
*** 2157,2159 ****
--- 2773,2824 ----
destroyPQExpBuffer(msg);
}
+
+ /*
+ * fetch tuple from cursor
+ */
+ static PGresult *
+ fetch_next(char *cursor_name)
+ {
+ PQExpBufferData fquery;
+ PGresult *res;
+
+ initPQExpBuffer(&fquery);
+ printfPQExpBuffer(&fquery, "FETCH NEXT %s", cursor_name);
+ res = PSQLexec(fquery.data, false);
+ termPQExpBuffer(&fquery);
+
+ return res;
+ }
+
+ /*
+ * exec boolean expression
+ */
+ static bool
+ exec_boolean_expr(char *expr, bool *success)
+ {
+ PQExpBufferData expr_query;
+ PGresult *r;
+ bool result;
+
+
+ initPQExpBuffer(&expr_query);
+ printfPQExpBuffer(&expr_query, "SELECT (%s)::boolean", expr);
+
+ r = PSQLexec(expr_query.data, false);
+ termPQExpBuffer(&expr_query);
+
+ if (!r)
+ {
+ *success = false;
+ PQclear(r);
+
+ return false;
+ }
+
+ *success = true;
+ result = !(PQgetisnull(r, 0, 0) || strcmp(PQgetvalue(r, 0, 0), "f") == 0);
+ PQclear(r);
+
+ return result;
+ }
*** ./help.c.orig 2009-12-18 09:18:14.000000000 +0100
--- ./help.c 2009-12-28 09:59:21.273911721 +0100
***************
*** 224,229 ****
--- 224,230 ----
fprintf(output, _(" \\du[+] [PATTERN] list roles (users)\n"));
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
fprintf(output, _(" \\l[+] list all databases\n"));
+ fprintf(output, _(" \\lf[-] [PATTERN] show function's source code\n"));
fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));
fprintf(output, "\n");
***************
*** 235,241 ****
ON(pset.popt.topt.format == PRINT_HTML));
fprintf(output, _(" \\pset NAME [VALUE] set table output option\n"
" (NAME := {format|border|expanded|fieldsep|footer|null|\n"
! " numericlocale|recordsep|tuples_only|title|tableattr|pager})\n"));
fprintf(output, _(" \\t [on|off] show only rows (currently %s)\n"),
ON(pset.popt.topt.tuples_only));
fprintf(output, _(" \\T [STRING] set HTML
tag attributes, or unset if none\n"));
--- 236,243 ----
ON(pset.popt.topt.format == PRINT_HTML));
fprintf(output, _(" \\pset NAME [VALUE] set table output option\n"
" (NAME := {format|border|expanded|fieldsep|footer|null|\n"
! " numericlocale|recordsep|tuples_only|title|tableattr|pager|\n"
! " textwrapping})\n"));
fprintf(output, _(" \\t [on|off] show only rows (currently %s)\n"),
ON(pset.popt.topt.tuples_only));
fprintf(output, _(" \\T [STRING] set HTML tag attributes, or unset if none\n"));
***************
*** 263,269 ****
fprintf(output, _(" \\set [NAME [VALUE]] set internal variable, or list all if no parameters\n"));
fprintf(output, _(" \\unset NAME unset (delete) internal variable\n"));
fprintf(output, "\n");
!
fprintf(output, _("Large Objects\n"));
fprintf(output, _(" \\lo_export LOBOID FILE\n"
" \\lo_import FILE [COMMENT]\n"
--- 265,284 ----
fprintf(output, _(" \\set [NAME [VALUE]] set internal variable, or list all if no parameters\n"));
fprintf(output, _(" \\unset NAME unset (delete) internal variable\n"));
fprintf(output, "\n");
!
! fprintf(output, _("Scripting\n"));
! fprintf(output, _(" \\forc CURSORNAME iteration over cursor\n"));
! fprintf(output, _(" \\endforc [CURSORNAME] end of iteration over cursor\n"));
! fprintf(output, _(" \\if VALUE process body when VALUE is true \n"));
! fprintf(output, _(" \\endif end of conditional command\n"));
! fprintf(output, _(" \\else process next lines\n"));
! fprintf(output, _(" \\ifdef [NAME] process body if variable NAME exists\n"));
! fprintf(output, _(" \\endifdef end of ifdef command\n"));
! fprintf(output, _(" \\necommand name define new psql command\n"));
! fprintf(output, _(" \\endnewcommand end of newcommand command\n"));
!
! fprintf(output, _("\n"));
!
fprintf(output, _("Large Objects\n"));
fprintf(output, _(" \\lo_export LOBOID FILE\n"
" \\lo_import FILE [COMMENT]\n"
*** ./mainloop.c.orig 2009-12-18 09:18:14.000000000 +0100
--- ./mainloop.c 2009-12-31 12:12:53.032456447 +0100
***************
*** 16,22 ****
#include "mb/pg_wchar.h"
-
/*
* Main processing loop for reading lines of input
* and sending them to the backend.
--- 16,21 ----
***************
*** 58,63 ****
--- 57,66 ----
pset.cur_cmd_source = source;
pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
pset.lineno = 0;
+ pset.current_loop = NULL;
+ pset.current_stmt = NULL;
+ pset.custom_statement_readbuffer = NULL;
+ pset.skip_mode = false;
/* Create working state */
scan_state = psql_scan_create();
***************
*** 122,137 ****
}
fflush(stdout);
/*
* get another line
*/
! if (pset.cur_cmd_interactive)
{
/* May need to reset prompt, eg after \r command */
if (query_buf->len == 0)
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
}
else
{
--- 125,251 ----
}
fflush(stdout);
+ pset.custom_stmt_mode = false;
/*
* get another line
*/
! if (pset.custom_statement_readbuffer)
! {
! psqlCustomStmtReaderData *CStmtBuffer = pset.custom_statement_readbuffer;
!
! char *_line = CStmtBuffer->reader;
! char *c = CStmtBuffer->reader;
! while (*c != '\n' && *c != '\0')
! c++;
!
! if (*c == '\0')
! {
! /* last row in definition */
! line = pg_strdup(_line);
! pset.custom_statement_readbuffer = CStmtBuffer->outer;
! free(CStmtBuffer->src);
! free(CStmtBuffer);
! }
! else
! {
! *c++ = '\0';
! pset.custom_statement_readbuffer->reader = c;
! line = pg_strdup(_line);
! }
! pset.custom_stmt_mode = true;
! }
! else if (pset.current_loop && pset.current_loop->reader_pos)
{
+ if (*(pset.current_loop->reader_pos) != '\0')
+ {
+ char *_line = pset.current_loop->reader_pos;
+ /* move string_reading_pos to next line */
+ char *c = pset.current_loop->reader_pos;
+
+ while (*c != '\n' && *c != '\0')
+ c++;
+
+ if (*c == '\n')
+ *c++ = '\0';
+
+ /* store begin of next line */
+ pset.current_loop->reader_pos = c;
+ line = pg_strdup(_line);
+ }
+ else
+ {
+ line = NULL;
+ successResult = EXIT_FAILURE;
+ }
+ }
+ else if (pset.cur_cmd_interactive)
+ {
+ psqlCustomStatement *cstmt = pset.custom_statements;
+
/* May need to reset prompt, eg after \r command */
if (query_buf->len == 0)
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(prompt_status));
+
+ /* try to evaluate custom command, but only when there are not active writer */
+ if (line != NULL && !(pset.custom_statements && pset.custom_statements->writer))
+ {
+ while (cstmt != NULL)
+ {
+ psqlCustomStmtReaderData *reader;
+ PsqlScanState scan_state_custom_call;
+ int i;
+ char buffer[5];
+ int namelen = strlen(cstmt->name);
+ char *args = line + namelen;
+
+
+ if (strncmp(line, cstmt->name, namelen) != 0)
+ {
+ cstmt = cstmt->next;
+ continue;
+ }
+ /* when line is longer, then command name, then char on namelen+1 have to be space */
+ else if (strlen(line) > namelen && line[namelen] != ' ')
+ {
+ cstmt = cstmt->next;
+ continue;
+ }
+
+ reader = pg_malloc(sizeof(psqlCustomStmtReaderData));
+ reader->outer = pset.custom_statement_readbuffer;
+ reader->src = pg_strdup(cstmt->src);
+ reader->reader = reader->src;
+ pset.custom_statement_readbuffer = reader;
+
+ pg_append_history(line, history_buf);
+ pg_send_history(history_buf);
+
+ scan_state_custom_call = psql_scan_create();
+ psql_scan_setup(scan_state_custom_call, args, strlen(args));
+
+ for (i = 1; i <= 10; i++)
+ {
+ char *opt;
+
+ snprintf(buffer, 10, "%d", i);
+ opt = psql_scan_slash_option(scan_state_custom_call,
+ OT_NORMAL, NULL, true);
+ SetVariable(pset.vars, buffer, opt);
+ }
+
+ psql_scan_finish(scan_state_custom_call);
+ psql_scan_destroy(scan_state_custom_call);
+ free(line);
+ line = NULL;
+
+ break;
+ }
+
+ if (line == NULL)
+ continue;
+ }
}
else
{
***************
*** 214,225 ****
/* Setting this will not have effect until next line. */
die_on_error = pset.on_error_stop;
/*
* Parse line, looking for command separators.
*/
psql_scan_setup(scan_state, line, strlen(line));
success = true;
! line_saved_in_history = false;
while (success || !die_on_error)
{
--- 328,350 ----
/* Setting this will not have effect until next line. */
die_on_error = pset.on_error_stop;
+ /* save line, if stack buffer is opened */
+ if (pset.current_loop && pset.current_loop->writeable)
+ appendPQExpBuffer(pset.current_loop->lines, "%s\n", line);
+
+ /* save command if writer is active */
+ if (pset.custom_statements && pset.custom_statements->writer)
+ appendPQExpBuffer(pset.custom_statements->writer, "%s\n", line);
+
/*
* Parse line, looking for command separators.
*/
psql_scan_setup(scan_state, line, strlen(line));
success = true;
!
! /* stacked lines are saved in history */
!
! line_saved_in_history = (pset.current_loop && pset.current_loop->reader_pos != NULL) || pset.custom_stmt_mode;
while (success || !die_on_error)
{
***************
*** 248,260 ****
*/
if (pset.cur_cmd_interactive && !line_saved_in_history)
{
pg_append_history(line, history_buf);
pg_send_history(history_buf);
line_saved_in_history = true;
}
/* execute query */
! success = SendQuery(query_buf->data);
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
/* transfer query to previous_buf by pointer-swapping */
--- 373,389 ----
*/
if (pset.cur_cmd_interactive && !line_saved_in_history)
{
+
pg_append_history(line, history_buf);
pg_send_history(history_buf);
line_saved_in_history = true;
}
/* execute query */
! if (!pset.skip_mode)
! success = SendQuery(query_buf->data);
! else
! success = PSQL_CMD_SEND;
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
/* transfer query to previous_buf by pointer-swapping */
*** ./Makefile.orig 2009-11-11 00:12:13.000000000 +0100
--- ./Makefile 2009-12-18 09:20:35.000000000 +0100
***************
*** 22,28 ****
OBJS= command.o common.o help.o input.o stringutils.o mainloop.o copy.o \
startup.o prompt.o variables.o large_obj.o print.o describe.o \
tab-complete.o mbprint.o dumputils.o keywords.o kwlookup.o \
! sql_help.o \
$(WIN32RES)
FLEXFLAGS = -Cfe
--- 22,28 ----
OBJS= command.o common.o help.o input.o stringutils.o mainloop.o copy.o \
startup.o prompt.o variables.o large_obj.o print.o describe.o \
tab-complete.o mbprint.o dumputils.o keywords.o kwlookup.o \
! sql_help.o psqlscript.o \
$(WIN32RES)
FLEXFLAGS = -Cfe
*** ./print.c.orig 2009-12-18 09:18:14.000000000 +0100
--- ./print.c 2009-12-31 12:16:14.652455771 +0100
***************
*** 52,57 ****
--- 52,59 ----
{ "-", "+", "+", "+" },
{ "-", "+", "+", "+" },
{ "-", "+", "+", "+" },
+ { "", "|", "|", "|" },
+ { "-", "+", "+", "+" },
{ "", "|", "|", "|" }
},
"|",
***************
*** 73,78 ****
--- 75,82 ----
{ "-", "+", "+", "+" },
{ "-", "+", "+", "+" },
{ "-", "+", "+", "+" },
+ { "", "|", "|", "|" },
+ { "-", "+", "+", "+" },
{ "", "|", "|", "|" }
},
":",
***************
*** 98,103 ****
--- 102,111 ----
/* ─, └, ┴, ┘ */
{ "\342\224\200", "\342\224\224", "\342\224\264", "\342\224\230" },
/* N/A, │, │, │ */
+ { "", "\342\224\202", "\342\224\202", "\342\224\202" },
+ /* ─, ├, ┼, ┤ */
+ { "\342\224\200", "\342\224\234", "\342\224\274", "\342\224\244" },
+ /* N/A, │, │, │ */
{ "", "\342\224\202", "\342\224\202", "\342\224\202" }
},
/* │ */
***************
*** 119,127 ****
true
};
/* Local functions */
! static int strlen_max_width(unsigned char *str, int *target_width, int encoding);
static void IsPagerNeeded(const printTableContent *cont, const int extra_lines,
FILE **fout, bool *is_pager);
--- 127,298 ----
true
};
+ const printTextFormat pg_utf8_custom_single_format =
+ {
+ "custom-single",
+ {
+ /* ─, ┌, ┬, ┐ */
+ { "\342\224\200", "\342\224\214", "\342\224\254", "\342\224\220" },
+ /* ─, ├, ┴, ┤ */
+ { "\342\224\200", "\342\224\234", "\342\224\264", "\342\224\244" },
+ /* ─, └, ┴, ┘ */
+ { "\342\224\200", "\342\224\224", "\342\224\200", "\342\224\230" },
+ /* N/A, │, │, │ */
+ { "", "\342\224\202", "\342\224\202", "\342\224\202" },
+ /* ─, ├, ─, ┤ */
+ { "\342\224\200", "\342\224\234", "\342\224\274", "\342\224\244" },
+ /* N/A, │, │, │ */
+ { "", "\342\224\202", "\342\224\202", "\342\224\202" }
+ },
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ true
+ };
+
+ const printTextFormat pg_utf8_custom_double_border_format =
+ {
+ "custom-double-border",
+ {
+ /* ═, ╔, ╤, ╗ */
+ { "\342\225\220", "\342\225\224", "\342\225\244", "\342\225\227" },
+ /* ─, ╟, ┼, ╢ */
+ { "\342\224\200", "\342\225\237", "\342\224\274", "\342\225\242" },
+ /* ═, ╚, ╧, ╝ */
+ { "\342\225\220", "\342\225\232", "\342\225\247", "\342\225\235" },
+ /* N/A, ║, │, ║ */
+ { "", "\342\225\221", "\342\224\202", "\342\225\221" },
+ /* ─, ╟, ┼, ╢ */
+ { "\342\224\200", "\342\225\237", "\342\224\274", "\342\225\242" },
+ /* N/A, ║, │, ║ */
+ { "", "\342\225\221", "\342\224\202", "\342\225\221" }
+ },
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ true
+ };
+
+ const printTextFormat pg_utf8_custom_double_border_header_format =
+ {
+ "custom-double-border-header",
+ {
+ /* ═, ╔, ╤, ╗ */
+ { "\342\225\220", "\342\225\224", "\342\225\244", "\342\225\227" },
+ /* ═, ╠, ╪, ╣ */
+ { "\342\225\220", "\342\225\240", "\342\225\252", "\342\225\243" },
+ /* ═, ╚, ╧, ╝ */
+ { "\342\225\220", "\342\225\232", "\342\225\247", "\342\225\235" },
+ /* N/A, ║, │, ║ */
+ { "", "\342\225\221", "\342\224\202", "\342\225\221" },
+ /* ─, ╟, ┼, ╢ */
+ { "\342\224\200", "\342\225\237", "\342\224\274", "\342\225\242" },
+ /* N/A, ║, │, ║ */
+ { "", "\342\225\221", "\342\224\202", "\342\225\221" }
+ },
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ true
+ };
+
+ const printTextFormat pg_utf8_custom_double_border_header_columns_format =
+ {
+ "custom-double-border-header-columns",
+ {
+ /* ═, ╔, ╦, ╗ */
+ { "\342\225\220", "\342\225\224", "\342\225\246", "\342\225\227" },
+ /* ═, ╠, ╬, ╣ */
+ { "\342\225\220", "\342\225\240", "\342\225\254", "\342\225\243" },
+ /* ═, ╚, ╩, ╝ */
+ { "\342\225\220", "\342\225\232", "\342\225\251", "\342\225\235" },
+ /* N/A, ║, ║, ║ */
+ { "", "\342\225\221", "\342\225\221", "\342\225\221" },
+ /* ─, ╟, ╫, ╢ */
+ { "\342\224\200", "\342\225\237", "\342\225\253", "\342\225\242" },
+ /* N/A, ║, ║, ║ */
+ { "", "\342\225\221", "\342\225\221", "\342\225\221" }
+ },
+ /* ║ */
+ "\342\225\221",
+ /* ║ */
+ "\342\225\221",
+ /* ║ */
+ "\342\225\221",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ true
+ };
+
+ const printTextFormat pg_utf8_custom_elegant_format =
+ {
+ "custom-elegant",
+ {
+ /* ═, ╔, ╦, ╗ */
+ { "\342\225\220", "\342\225\224", "\342\225\246", "\342\225\227" },
+ /* ═, ╠, ╩, ╣ */
+ { "\342\225\220", "\342\225\240", "\342\225\251", "\342\225\243" },
+ /* ═, ╚, ═, ╝ */
+ { "\342\225\220", "\342\225\232", "\342\225\220", "\342\225\235" },
+ /* N/A, ║, │, ║ */
+ { "", "\342\225\221", "\342\224\202", "\342\225\221" },
+ /* ─, ╟, ┼, ╢ */
+ { "\342\224\200", "\342\225\237", "\342\224\274", "\342\225\242" },
+ /* N/A, ║, ║, ║ */
+ { "", "\342\225\221", "\342\225\221", "\342\225\221" }
+ },
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ /* │ */
+ "\342\224\202",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ true
+ };
+
/* Local functions */
! static int strlen_max_width(unsigned char *str, int *target_width, int encoding,
! printTextWrappingMode wmod,
! bool *word_overflow);
!
static void IsPagerNeeded(const printTableContent *cont, const int extra_lines,
FILE **fout, bool *is_pager);
***************
*** 450,456 ****
if (border == 1)
fputs(lformat->hrule, fout);
! else if (border == 2)
fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
for (i = 0; i < ncolumns; i++)
--- 621,627 ----
if (border == 1)
fputs(lformat->hrule, fout);
! else if (border > 1)
fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
for (i = 0; i < ncolumns; i++)
***************
*** 468,474 ****
}
}
! if (border == 2)
fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
else if (border == 1)
fputs(lformat->hrule, fout);
--- 639,645 ----
}
}
! if (border > 1)
fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
else if (border == 1)
fputs(lformat->hrule, fout);
***************
*** 489,494 ****
--- 660,666 ----
unsigned short opt_border = cont->opt->border;
const printTextFormat *format = get_line_style(cont->opt);
const printTextLineFormat *dformat = &format->lrule[PRINT_RULE_DATA];
+ const printTextLineFormat *hformat = &format->lrule[PRINT_RULE_HEADER];
unsigned int col_count = 0,
cell_count = 0;
***************
*** 522,529 ****
if (cancel_pressed)
return;
! if (opt_border > 2)
! opt_border = 2;
if (cont->ncolumns > 0)
{
--- 694,701 ----
if (cancel_pressed)
return;
! if (opt_border > 3)
! opt_border = 3;
if (cont->ncolumns > 0)
{
***************
*** 564,569 ****
--- 736,760 ----
nl_lines,
bytes_required;
+ /*
+ * Search and replace pipe character '|' in headers. Headers are
+ * possible a constant strings, so we have to copy content.
+ */
+ if (cont->opt->multiline_header)
+ {
+ const char *header = cont->headers[i];
+ char c;
+ char *subst_header = pg_malloc(strlen(header));
+ char *cp;
+
+ cp = subst_header;
+ while ((c = *header++) != '\0')
+ *cp++ = (c != '|') ? c : '\n';
+ *cp = '\0';
+
+ cont->headers[i] = subst_header;
+ }
+
pg_wcssize((unsigned char *) cont->headers[i], strlen(cont->headers[i]),
encoding, &width, &nl_lines, &bytes_required);
if (width > max_width[i])
***************
*** 797,803 ****
int more_col_wrapping;
int curr_nl_line;
! if (opt_border == 2)
_print_horizontal_line(col_count, width_wrap, opt_border,
PRINT_RULE_TOP, format, fout);
--- 988,994 ----
int more_col_wrapping;
int curr_nl_line;
! if (opt_border == 2 || opt_border == 3)
_print_horizontal_line(col_count, width_wrap, opt_border,
PRINT_RULE_TOP, format, fout);
***************
*** 811,818 ****
memset(header_done, false, col_count * sizeof(bool));
while (more_col_wrapping)
{
! if (opt_border == 2)
! fputs(dformat->leftvrule, fout);
for (i = 0; i < cont->ncolumns; i++)
{
--- 1002,1009 ----
memset(header_done, false, col_count * sizeof(bool));
while (more_col_wrapping)
{
! if (opt_border == 2 || opt_border == 3)
! fputs(hformat->leftvrule, fout);
for (i = 0; i < cont->ncolumns; i++)
{
***************
*** 827,836 ****
if (!header_done[i])
{
nbspace = width_wrap[i] - this_line->width;
!
! /* centered */
! fprintf(fout, "%-*s%s%-*s",
! nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
if (!(this_line + 1)->ptr)
{
--- 1018,1036 ----
if (!header_done[i])
{
nbspace = width_wrap[i] - this_line->width;
!
! if (cont->opt->header_style == PRINT_HEADER_CENTER)
! /* centered */
! fprintf(fout, "%-*s%s%-*s",
! nbspace / 2, "", this_line->ptr, (nbspace + 1) / 2, "");
! else if (cont->opt->header_style == PRINT_HEADER_LEFT)
! /* left aligned */
! fprintf(fout, "%s%-*s",
! this_line->ptr, nbspace, "");
! else if (cont->opt->header_style == PRINT_HEADER_RIGHT)
! /* right aligned */
! fprintf(fout, "%-*s%s",
! nbspace, "", this_line->ptr);
if (!(this_line + 1)->ptr)
{
***************
*** 842,857 ****
fprintf(fout, "%*s", width_wrap[i], "");
if (opt_border != 0 || format->wrap_right_border == true)
! fputs(!header_done[i] ? format->header_nl_right : " ",
! fout);
if (opt_border != 0 && i < col_count - 1)
! fputs(dformat->midvrule, fout);
}
curr_nl_line++;
! if (opt_border == 2)
! fputs(dformat->rightvrule, fout);
fputc('\n', fout);
}
--- 1042,1062 ----
fprintf(fout, "%*s", width_wrap[i], "");
if (opt_border != 0 || format->wrap_right_border == true)
! {
! if (cont->opt->multiline_header)
! /* don't show wrap marks in multiline headre mode */
! fputs(" ", fout);
! else
! fputs(!header_done[i] ? format->header_nl_right : " ", fout);
! }
if (opt_border != 0 && i < col_count - 1)
! fputs(hformat->midvrule, fout);
}
curr_nl_line++;
! if (opt_border > 1)
! fputs(hformat->rightvrule, fout);
fputc('\n', fout);
}
***************
*** 868,873 ****
--- 1073,1083 ----
if (cancel_pressed)
break;
+ if (opt_border == 3 && i > 1)
+ _print_horizontal_line(col_count, width_wrap, opt_border,
+ PRINT_RULE_BETWEEN_DATA, format, fout);
+
+
/*
* Format each cell. Format again, if it's a numeric formatting
* locale (e.g. 123,456 vs. 123456)
***************
*** 901,907 ****
more_lines = false;
/* left border */
! if (opt_border == 2)
fputs(dformat->leftvrule, fout);
/* for each column */
--- 1111,1117 ----
more_lines = false;
/* left border */
! if (opt_border > 1)
fputs(dformat->leftvrule, fout);
/* for each column */
***************
*** 911,917 ****
struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
int bytes_to_output;
int chars_to_output = width_wrap[j];
! bool finalspaces = (opt_border == 2 || j < col_count - 1);
/* Print left-hand wrap or newline mark */
if (opt_border != 0)
--- 1121,1127 ----
struct lineptr *this_line = &col_lineptrs[j][curr_nl_line[j]];
int bytes_to_output;
int chars_to_output = width_wrap[j];
! bool finalspaces = (opt_border > 1 || j < col_count - 1);
/* Print left-hand wrap or newline mark */
if (opt_border != 0)
***************
*** 932,941 ****
}
else
{
/* Get strlen() of the characters up to width_wrap */
bytes_to_output =
strlen_max_width(this_line->ptr + bytes_output[j],
! &chars_to_output, encoding);
/*
* If we exceeded width_wrap, it means the display width
--- 1142,1156 ----
}
else
{
+ bool word_overflow;
+
/* Get strlen() of the characters up to width_wrap */
bytes_to_output =
strlen_max_width(this_line->ptr + bytes_output[j],
! &chars_to_output,
! encoding,
! cont->opt->textwrapping,
! &word_overflow);
/*
* If we exceeded width_wrap, it means the display width
***************
*** 961,966 ****
--- 1176,1184 ----
}
bytes_output[j] += bytes_to_output;
+ /* if we break test in space, then skip space */
+ if (!word_overflow)
+ bytes_output[j] += 1;
/* Do we have more text to wrap? */
if (*(this_line->ptr + bytes_output[j]) != '\0')
***************
*** 1003,1009 ****
fputs(format->wrap_right, fout);
else if (wrap[j] == PRINT_LINE_WRAP_NEWLINE)
fputs(format->nl_right, fout);
! else if (opt_border == 2 || j < col_count - 1)
fputc(' ', fout);
/* Print column divider, if not the last column */
--- 1221,1227 ----
fputs(format->wrap_right, fout);
else if (wrap[j] == PRINT_LINE_WRAP_NEWLINE)
fputs(format->nl_right, fout);
! else if (opt_border > 1 || j < col_count - 1)
fputc(' ', fout);
/* Print column divider, if not the last column */
***************
*** 1021,1027 ****
}
/* end-of-row border */
! if (opt_border == 2)
fputs(dformat->rightvrule, fout);
fputc('\n', fout);
--- 1239,1245 ----
}
/* end-of-row border */
! if (opt_border > 1)
fputs(dformat->rightvrule, fout);
fputc('\n', fout);
***************
*** 1030,1036 ****
if (cont->opt->stop_table)
{
! if (opt_border == 2 && !cancel_pressed)
_print_horizontal_line(col_count, width_wrap, opt_border,
PRINT_RULE_BOTTOM, format, fout);
--- 1248,1254 ----
if (cont->opt->stop_table)
{
! if (opt_border > 1 && !cancel_pressed)
_print_horizontal_line(col_count, width_wrap, opt_border,
PRINT_RULE_BOTTOM, format, fout);
***************
*** 1058,1064 ****
--- 1276,1286 ----
free(header_done);
free(bytes_output);
for (i = 0; i < col_count; i++)
+ {
free(format_buf[i]);
+ if (cont->opt->multiline_header)
+ free((char *) cont->headers[i]);
+ }
free(format_buf);
if (is_pager)
***************
*** 1080,1086 ****
unsigned int i;
int reclen = 0;
! if (opt_border == 2)
fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
else if (opt_border == 1)
fputs(lformat->hrule, fout);
--- 1302,1308 ----
unsigned int i;
int reclen = 0;
! if (opt_border > 1)
fprintf(fout, "%s%s", lformat->leftvrule, lformat->hrule);
else if (opt_border == 1)
fputs(lformat->hrule, fout);
***************
*** 1092,1098 ****
else
reclen = fprintf(fout, "[ RECORD %lu ]", record);
}
! if (opt_border != 2)
reclen++;
if (reclen < 0)
reclen = 0;
--- 1314,1320 ----
else
reclen = fprintf(fout, "[ RECORD %lu ]", record);
}
! if (opt_border != 2 && opt_border != 3)
reclen++;
if (reclen < 0)
reclen = 0;
***************
*** 1118,1124 ****
reclen = 0;
for (i = reclen; i < dwidth; i++)
fputs(opt_border > 0 ? lformat->hrule : " ", fout);
! if (opt_border == 2)
fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
fputc('\n', fout);
}
--- 1340,1346 ----
reclen = 0;
for (i = reclen; i < dwidth; i++)
fputs(opt_border > 0 ? lformat->hrule : " ", fout);
! if (opt_border > 1)
fprintf(fout, "%s%s", lformat->hrule, lformat->rightvrule);
fputc('\n', fout);
}
***************
*** 1147,1154 ****
if (cancel_pressed)
return;
! if (opt_border > 2)
! opt_border = 2;
if (cont->cells[0] == NULL && cont->opt->start_table &&
cont->opt->stop_table)
--- 1369,1376 ----
if (cancel_pressed)
return;
! if (opt_border > 3)
! opt_border = 3;
if (cont->cells[0] == NULL && cont->opt->start_table &&
cont->opt->stop_table)
***************
*** 1238,1244 ****
if (!opt_tuples_only)
print_aligned_vertical_line(cont, record++, hwidth, dwidth,
pos, fout);
! else if (i != 0 || !cont->opt->start_table || opt_border == 2)
print_aligned_vertical_line(cont, 0, hwidth, dwidth,
pos, fout);
}
--- 1460,1466 ----
if (!opt_tuples_only)
print_aligned_vertical_line(cont, record++, hwidth, dwidth,
pos, fout);
! else if (i != 0 || !cont->opt->start_table || opt_border > 1)
print_aligned_vertical_line(cont, 0, hwidth, dwidth,
pos, fout);
}
***************
*** 1255,1261 ****
dcomplete = hcomplete = 0;
while (!dcomplete || !hcomplete)
{
! if (opt_border == 2)
fprintf(fout, "%s ", dformat->leftvrule);
if (!hcomplete)
{
--- 1477,1483 ----
dcomplete = hcomplete = 0;
while (!dcomplete || !hcomplete)
{
! if (opt_border > 1)
fprintf(fout, "%s ", dformat->leftvrule);
if (!hcomplete)
{
***************
*** 1313,1319 ****
if (cont->opt->stop_table)
{
! if (opt_border == 2 && !cancel_pressed)
print_aligned_vertical_line(cont, 0, hwidth, dwidth,
PRINT_RULE_BOTTOM, fout);
--- 1535,1541 ----
if (cont->opt->stop_table)
{
! if (opt_border > 1 && !cancel_pressed)
print_aligned_vertical_line(cont, 0, hwidth, dwidth,
PRINT_RULE_BOTTOM, fout);
***************
*** 1623,1630 ****
if (cancel_pressed)
return;
! if (opt_border > 2)
! opt_border = 2;
if (cont->opt->start_table)
{
--- 1845,1852 ----
if (cancel_pressed)
return;
! if (opt_border > 3)
! opt_border = 3;
if (cont->opt->start_table)
{
***************
*** 1639,1645 ****
/* begin environment and set alignments and borders */
fputs("\\begin{tabular}{", fout);
! if (opt_border == 2)
fputs("| ", fout);
for (i = 0; i < cont->ncolumns; i++)
{
--- 1861,1867 ----
/* begin environment and set alignments and borders */
fputs("\\begin{tabular}{", fout);
! if (opt_border > 1)
fputs("| ", fout);
for (i = 0; i < cont->ncolumns; i++)
{
***************
*** 1647,1658 ****
if (opt_border != 0 && i < cont->ncolumns - 1)
fputs(" | ", fout);
}
! if (opt_border == 2)
fputs(" |", fout);
fputs("}\n", fout);
! if (!opt_tuples_only && opt_border == 2)
fputs("\\hline\n", fout);
/* print headers */
--- 1869,1880 ----
if (opt_border != 0 && i < cont->ncolumns - 1)
fputs(" | ", fout);
}
! if (opt_border > 1)
fputs(" |", fout);
fputs("}\n", fout);
! if (!opt_tuples_only && opt_border > 1)
fputs("\\hline\n", fout);
/* print headers */
***************
*** 1696,1702 ****
if (cont->opt->stop_table)
{
! if (opt_border == 2)
fputs("\\hline\n", fout);
fputs("\\end{tabular}\n\n\\noindent ", fout);
--- 1918,1924 ----
if (cont->opt->stop_table)
{
! if (opt_border > 1)
fputs("\\hline\n", fout);
fputs("\\end{tabular}\n\n\\noindent ", fout);
***************
*** 1750,1756 ****
fputs("cl", fout);
else if (opt_border == 1)
fputs("c|l", fout);
! else if (opt_border == 2)
fputs("|c|l|", fout);
fputs("}\n", fout);
}
--- 1972,1978 ----
fputs("cl", fout);
else if (opt_border == 1)
fputs("c|l", fout);
! else if (opt_border > 1)
fputs("|c|l|", fout);
fputs("}\n", fout);
}
***************
*** 1765,1771 ****
break;
if (!opt_tuples_only)
{
! if (opt_border == 2)
{
fputs("\\hline\n", fout);
fprintf(fout, "\\multicolumn{2}{|c|}{\\textit{Record %lu}} \\\\\n", record++);
--- 1987,1993 ----
break;
if (!opt_tuples_only)
{
! if (opt_border > 1)
{
fputs("\\hline\n", fout);
fprintf(fout, "\\multicolumn{2}{|c|}{\\textit{Record %lu}} \\\\\n", record++);
***************
*** 1785,1791 ****
if (cont->opt->stop_table)
{
! if (opt_border == 2)
fputs("\\hline\n", fout);
fputs("\\end{tabular}\n\n\\noindent ", fout);
--- 2007,2013 ----
if (cont->opt->stop_table)
{
! if (opt_border > 1)
fputs("\\hline\n", fout);
fputs("\\end{tabular}\n\n\\noindent ", fout);
***************
*** 1849,1856 ****
if (cancel_pressed)
return;
! if (opt_border > 2)
! opt_border = 2;
if (cont->opt->start_table)
{
--- 2071,2078 ----
if (cancel_pressed)
return;
! if (opt_border > 3)
! opt_border = 3;
if (cont->opt->start_table)
{
***************
*** 1864,1870 ****
/* begin environment and set alignments and borders */
fputs(".LP\n.TS\n", fout);
! if (opt_border == 2)
fputs("center box;\n", fout);
else
fputs("center;\n", fout);
--- 2086,2092 ----
/* begin environment and set alignments and borders */
fputs(".LP\n.TS\n", fout);
! if (opt_border > 1)
fputs("center box;\n", fout);
else
fputs("center;\n", fout);
***************
*** 1950,1957 ****
if (cancel_pressed)
return;
! if (opt_border > 2)
! opt_border = 2;
if (cont->opt->start_table)
{
--- 2172,2179 ----
if (cancel_pressed)
return;
! if (opt_border > 3)
! opt_border = 3;
if (cont->opt->start_table)
{
***************
*** 1965,1971 ****
/* begin environment and set alignments and borders */
fputs(".LP\n.TS\n", fout);
! if (opt_border == 2)
fputs("center box;\n", fout);
else
fputs("center;\n", fout);
--- 2187,2193 ----
/* begin environment and set alignments and borders */
fputs(".LP\n.TS\n", fout);
! if (opt_border > 1)
fputs("center box;\n", fout);
else
fputs("center;\n", fout);
***************
*** 1989,1995 ****
{
if (current_format != 1)
{
! if (opt_border == 2 && record > 1)
fputs("_\n", fout);
if (current_format != 0)
fputs(".T&\n", fout);
--- 2211,2217 ----
{
if (current_format != 1)
{
! if (opt_border > 1 && record > 1)
fputs("_\n", fout);
if (current_format != 0)
fputs(".T&\n", fout);
***************
*** 2467,2472 ****
--- 2689,2701 ----
case CASHOID:
align = 'r';
break;
+ case TEXTOID:
+ case VARCHAROID:
+ if (opt->topt.textwrapping == TEXTWRAPPING_FLUSH_LEFT)
+ align = 'w';
+ else
+ align = 'l';
+ break;
default:
align = 'l';
break;
***************
*** 2561,2581 ****
return &pg_asciiformat;
}
/*
* Compute the byte distance to the end of the string or *target_width
* display character positions, whichever comes first. Update *target_width
* to be the number of display character positions actually filled.
*/
static int
! strlen_max_width(unsigned char *str, int *target_width, int encoding)
{
unsigned char *start = str;
unsigned char *end = str + strlen((char *) str);
int curr_width = 0;
while (str < end)
{
! int char_width = PQdsplen((char *) str, encoding);
/*
* If the display width of the new character causes the string to
--- 2790,2843 ----
return &pg_asciiformat;
}
+ const char *
+ get_header_style(printHeaderStyle style)
+ {
+ if (style == PRINT_HEADER_LEFT)
+ return "left";
+ else if (style == PRINT_HEADER_CENTER)
+ return "center";
+ else
+ return "right";
+ }
+
+ const char *
+ get_textwrapping_mode(printTextWrappingMode wmod)
+ {
+ if (wmod == TEXTWRAPPING_DEFAULT)
+ return "default";
+ else if (wmod == TEXTWRAPPING_FLUSH_LEFT)
+ return "flush-left";
+ else
+ return "unknown textwrapping mode";
+ }
+
/*
* Compute the byte distance to the end of the string or *target_width
* display character positions, whichever comes first. Update *target_width
* to be the number of display character positions actually filled.
*/
static int
! strlen_max_width(unsigned char *str, int *target_width, int encoding,
! printTextWrappingMode wmod,
! bool *word_overflow)
{
unsigned char *start = str;
unsigned char *end = str + strlen((char *) str);
int curr_width = 0;
+ int last_space_width = 0;
+ unsigned char *last_space = NULL;
+ bool overflow = false;
while (str < end)
{
! int char_width = PQdsplen((char *) str, encoding);
!
! if (wmod == TEXTWRAPPING_FLUSH_LEFT && *str == ' ')
! {
! last_space = str;
! last_space_width = curr_width;
! }
/*
* If the display width of the new character causes the string to
***************
*** 2584,2597 ****
* accept it.
*/
if (*target_width < curr_width + char_width && curr_width != 0)
break;
curr_width += char_width;
-
str += PQmblen((char *) str, encoding);
}
! *target_width = curr_width;
!
return str - start;
}
--- 2846,2872 ----
* accept it.
*/
if (*target_width < curr_width + char_width && curr_width != 0)
+ {
+ overflow = true;
break;
+ }
curr_width += char_width;
str += PQmblen((char *) str, encoding);
}
! if (last_space != NULL && overflow)
! {
!
! *target_width = last_space_width;
! *word_overflow = false;
! str = last_space;
! }
! else
! {
! *target_width = curr_width;
! *word_overflow = true;
! }
!
return str - start;
}
*** ./print.h.orig 2009-12-18 09:18:14.000000000 +0100
--- ./print.h 2009-12-30 09:38:29.560059344 +0100
***************
*** 38,44 ****
PRINT_RULE_TOP, /* top horizontal line */
PRINT_RULE_MIDDLE, /* intra-data horizontal line */
PRINT_RULE_BOTTOM, /* bottom horizontal line */
! PRINT_RULE_DATA /* data line (hrule is unused here) */
} printTextRule;
typedef enum printTextLineWrap
--- 38,46 ----
PRINT_RULE_TOP, /* top horizontal line */
PRINT_RULE_MIDDLE, /* intra-data horizontal line */
PRINT_RULE_BOTTOM, /* bottom horizontal line */
! PRINT_RULE_DATA, /* data line (hrule is unused here) */
! PRINT_RULE_BETWEEN_DATA, /* line between data rows */
! PRINT_RULE_HEADER /* header rule (hrule is unused here) */
} printTextRule;
typedef enum printTextLineWrap
***************
*** 49,59 ****
PRINT_LINE_WRAP_NEWLINE /* Newline in data */
} printTextLineWrap;
typedef struct printTextFormat
{
/* A complete line style */
const char *name; /* for display purposes */
! printTextLineFormat lrule[4]; /* indexed by enum printTextRule */
const char *midvrule_nl; /* vertical line for continue after newline */
const char *midvrule_wrap; /* vertical line for wrapped data */
const char *midvrule_blank; /* vertical line for blank data */
--- 51,67 ----
PRINT_LINE_WRAP_NEWLINE /* Newline in data */
} printTextLineWrap;
+ typedef enum printTextWrappingMode
+ {
+ TEXTWRAPPING_DEFAULT, /* Default PostgreSQL behave */
+ TEXTWRAPPING_FLUSH_LEFT /* Flush to left mode */
+ } printTextWrappingMode;
+
typedef struct printTextFormat
{
/* A complete line style */
const char *name; /* for display purposes */
! printTextLineFormat lrule[6]; /* indexed by enum printTextRule */
const char *midvrule_nl; /* vertical line for continue after newline */
const char *midvrule_wrap; /* vertical line for wrapped data */
const char *midvrule_blank; /* vertical line for blank data */
***************
*** 67,79 ****
* when border=0? */
} printTextFormat;
typedef struct printTableOpt
{
enum printFormat format; /* see enum above */
bool expanded; /* expanded/vertical output (if supported by
* output format) */
unsigned short int border; /* Print a border around the table. 0=none,
! * 1=dividing lines, 2=full */
unsigned short int pager; /* use pager for output (if to stdout and
* stdout is a tty) 0=off 1=on 2=always */
bool tuples_only; /* don't output headers, row counts, etc. */
--- 75,94 ----
* when border=0? */
} printTextFormat;
+ typedef enum printHeaderStyle
+ {
+ PRINT_HEADER_CENTER = 0,
+ PRINT_HEADER_LEFT,
+ PRINT_HEADER_RIGHT
+ } printHeaderStyle;
+
typedef struct printTableOpt
{
enum printFormat format; /* see enum above */
bool expanded; /* expanded/vertical output (if supported by
* output format) */
unsigned short int border; /* Print a border around the table. 0=none,
! * 1=dividing lines, 2=add border, 3=add between lines */
unsigned short int pager; /* use pager for output (if to stdout and
* stdout is a tty) 0=off 1=on 2=always */
bool tuples_only; /* don't output headers, row counts, etc. */
***************
*** 81,86 ****
--- 96,102 ----
bool stop_table; /* print stop decoration, eg
*/
unsigned long prior_records; /* start offset for record counters */
const printTextFormat *line_style; /* line style (NULL for default) */
+ printTextWrappingMode textwrapping; /* mode of text wrapping */
char *fieldSep; /* field separator for unaligned text mode */
char *recordSep; /* record separator for unaligned text mode */
bool numericLocale; /* locale-aware numeric units separator and
***************
*** 89,94 ****
--- 105,112 ----
int encoding; /* character encoding */
int env_columns; /* $COLUMNS on psql start, 0 is unset */
int columns; /* target width for wrapped format */
+ printHeaderStyle header_style; /* header style */
+ bool multiline_header; /* allows multilines header */
} printTableOpt;
/*
***************
*** 121,127 ****
const char **cell; /* Pointer to the last added cell */
printTableFooter *footers; /* Pointer to the first footer */
printTableFooter *footer; /* Pointer to the last added footer */
! char *aligns; /* Array of alignment specifiers; 'l' or 'r',
* one per column */
char *align; /* Pointer to the last added alignment */
} printTableContent;
--- 139,145 ----
const char **cell; /* Pointer to the last added cell */
printTableFooter *footers; /* Pointer to the first footer */
printTableFooter *footer; /* Pointer to the last added footer */
! char *aligns; /* Array of alignment specifiers; 'l', 'f' or 'r',
* one per column */
char *align; /* Pointer to the last added alignment */
} printTableContent;
***************
*** 144,149 ****
--- 162,172 ----
extern const printTextFormat pg_asciiformat_old;
extern const printTextFormat pg_utf8format;
+ extern const printTextFormat pg_utf8_custom_single_format;
+ extern const printTextFormat pg_utf8_custom_double_border_format;
+ extern const printTextFormat pg_utf8_custom_double_border_header_format;
+ extern const printTextFormat pg_utf8_custom_double_border_header_columns_format;
+ extern const printTextFormat pg_utf8_custom_elegant_format;
extern FILE *PageOutput(int lines, unsigned short int pager);
extern void ClosePager(FILE *pagerpipe);
***************
*** 168,173 ****
--- 191,200 ----
extern void setDecimalLocale(void);
extern const printTextFormat *get_line_style(const printTableOpt *opt);
+ extern const char *get_textwrapping_mode(printTextWrappingMode wmod);
+
+ extern const char *get_header_style(printHeaderStyle style);
+
#ifndef __CYGWIN__
#define DEFAULT_PAGER "more"
*** ./psqlscan.l.orig 2009-11-12 01:13:00.000000000 +0100
--- ./psqlscan.l 2009-12-30 11:57:01.576058871 +0100
***************
*** 691,697 ****
value = GetVariable(pset.vars, yytext + 1);
! if (value)
{
/* It is a variable, perform substitution */
push_new_buffer(value);
--- 691,697 ----
value = GetVariable(pset.vars, yytext + 1);
! if (value && !pset.skip_mode)
{
/* It is a variable, perform substitution */
push_new_buffer(value);
***************
*** 707,712 ****
--- 707,802 ----
}
}
+ :"{"[A-Za-z0-9_]+"}" {
+ /* Possible psql literal quote variable substitution */
+ char *varname = pg_strdup(yytext + 2);
+ const char *value;
+
+ varname[yyleng - 3] = '\0';
+
+ value = GetVariable(pset.vars, varname);
+ free(varname);
+
+ if (value && !pset.skip_mode)
+ {
+ /* It is a variable, perform substitution */
+ const char *values[1];
+ PGresult *res;
+
+ values[0] = value;
+ res = PQexecParams(pset.db,
+ "SELECT quote_literal($1)",
+ 1,
+ NULL,
+ values,
+ NULL,
+ NULL,
+ 0);
+
+ if (PQresultStatus(res) == PGRES_TUPLES_OK)
+ push_new_buffer(PQgetvalue(res, 0, 0));
+ else
+ psql_error("cannot execute quote_ident function");
+
+ PQclear(res);
+ /* yy_scan_string already made buffer active */
+ }
+ else
+ {
+ /*
+ * if the variable doesn't exist we'll copy the
+ * string as is
+ */
+ ECHO;
+ }
+ }
+
+ :"["[A-Za-z0-9_]+"]" {
+ /* Possible psql ident variable substitution */
+ char *varname = pg_strdup(yytext + 2);
+ const char *value;
+
+ varname[yyleng - 3] = '\0';
+
+ value = GetVariable(pset.vars, varname);
+ free(varname);
+
+ if (value && !pset.skip_mode)
+ {
+ /* It is a variable, perform substitution */
+ const char *values[1];
+ PGresult *res;
+
+ values[0] = value;
+ res = PQexecParams(pset.db,
+ "SELECT quote_ident($1)",
+ 1,
+ NULL,
+ values,
+ NULL,
+ NULL,
+ 0);
+
+ if (PQresultStatus(res) == PGRES_TUPLES_OK)
+ push_new_buffer(PQgetvalue(res, 0, 0));
+ else
+ psql_error("cannot execute quote_ident function");
+
+ PQclear(res);
+ /* yy_scan_string already made buffer active */
+ }
+ else
+ {
+ /*
+ * if the variable doesn't exist we'll copy the
+ * string as is
+ */
+ ECHO;
+ }
+
+ }
+
+
/*
* Back to backend-compatible rules.
*/
***************
*** 996,1001 ****
--- 1086,1102 ----
"`" { return LEXRES_OK; }
+ :[A-Za-z0-9_]* {
+ const char *value;
+
+ value = GetVariable(pset.vars, yytext + 1);
+
+ if (value)
+ appendPQExpBufferStr(output_buf, value);
+ else
+ ECHO;
+ }
+
{other}|\n { ECHO; }
}
*** ./psqlscript.c.orig 2009-12-14 11:08:06.000000000 +0100
--- ./psqlscript.c 2009-12-31 09:29:29.081331753 +0100
***************
*** 0 ****
--- 1,188 ----
+ #include "postgres_fe.h"
+ #include "psqlscript.h"
+ #include "pqexpbuffer.h"
+ #include "command.h"
+ #include "common.h"
+
+ psqlNestedLoop *
+ remove_loop(psqlNestedLoop *nloop, ScriptStatementType stype,
+ const char *cmd, backslashResult *status,
+ bool *skip_mode)
+ {
+ psqlNestedLoop *outer;
+
+ /*
+ * without \set ON_ERROR_STOP is possible continue in
+ * problematic sequences, so this function have to be
+ * more than usually robust.
+ */
+ if (nloop == NULL)
+ {
+ psql_error("\\%s: unexpected final statement\n", cmd);
+ *status = PSQL_CMD_ERROR;
+ return NULL;
+ }
+
+
+ outer = nloop->outer;
+
+ /* loop with zero cycles don't fill restored lines */
+ if (nloop->restored_lines != NULL)
+ free(nloop->restored_lines);
+
+ /* local buffer send to outer buffer */
+ if (nloop->lines != NULL)
+ {
+ if (outer && outer->writeable)
+ appendPQExpBuffer(outer->lines, "%s", nloop->lines->data);
+
+ if (outer && outer->reader_pos)
+ outer->reader_pos += nloop->lines->len;
+
+ destroyPQExpBuffer(nloop->lines);
+ }
+
+ /* set original skip mode */
+ *skip_mode = nloop->outer_skip_mode;
+
+ switch (nloop->typ)
+ {
+ case PSQL_FORC:
+ psql_assert(nloop->params.cursor_name != NULL);
+ free(nloop->params.cursor_name);
+ if (stype != PSQL_FORC)
+ {
+ psql_error("\\%s: expected \\endforc\n", cmd);
+ *status = PSQL_CMD_ERROR;
+ }
+ break;
+
+ default:
+ psql_error("unknow block type\n");
+ *status = PSQL_CMD_ERROR;
+ }
+ free(nloop);
+
+ return outer;
+ }
+
+ psqlNestedLoop *
+ new_for_cursor(char *cursor_name, psqlNestedLoop *outer, bool skip_mode)
+ {
+ psqlNestedLoop *forc = pg_malloc(sizeof(psqlNestedLoop));
+
+ forc->typ = PSQL_FORC;
+ forc->lines = createPQExpBuffer();
+ forc->writeable = true;
+ forc->params.cursor_name = cursor_name;
+ forc->outer = outer;
+ forc->restored_lines = NULL;
+ forc->reader_pos = NULL;
+
+ /* save skip mode */
+ forc->outer_skip_mode = skip_mode;
+
+ /* propagete reader from outer loop */
+ if (outer)
+ forc->reader_pos = outer->reader_pos;
+
+ return forc;
+ }
+
+ /*
+ * define new statement - stack of statements controlls statement's
+ * nesting (for syntax control) and carry stack of skip_modes.
+ */
+ psqlNestedStmt *
+ new_loop(psqlNestedStmt *outer, ScriptStatementType stype, bool skip_mode)
+ {
+ psqlNestedStmt *stmt = pg_malloc(sizeof(psqlNestedStmt));
+
+ stmt->typ = stype;
+ stmt->outer_skip_mode = skip_mode;
+ stmt->outer = outer;
+
+ return stmt;
+ }
+
+ psqlNestedStmt *
+ new_if(psqlNestedStmt *outer, ScriptStatementType stype, bool skip_mode)
+ {
+ psqlNestedIf *stmt = pg_malloc(sizeof(psqlNestedIf));
+
+ stmt->typ = stype;
+ stmt->outer_skip_mode = skip_mode;
+ stmt->outer = outer;
+ stmt->successful = false;
+
+ return (psqlNestedStmt*) stmt;
+ }
+
+
+ psqlNestedStmt *
+ remove_stmt(psqlNestedStmt *stmt, ScriptStatementType stype,
+ const char *cmd, backslashResult *status,
+ bool *skip_mode)
+ {
+ psqlNestedStmt *outer;
+
+ /*
+ * without \set ON_ERROR_STOP is possible continue in
+ * problematic sequences, so this function have to be
+ * more than usually robust.
+ */
+ if (stmt == NULL)
+ {
+ psql_error("\\%s: unexpected final statement\n", cmd);
+ *status = PSQL_CMD_ERROR;
+ return NULL;
+ }
+
+ outer = stmt->outer;
+ *skip_mode = stmt->outer_skip_mode;
+
+ if (stmt->typ != stype)
+ {
+ free(stmt);
+ psql_error("\\%s: unexpected final statement\n", cmd);
+ *status = PSQL_CMD_ERROR;
+ return outer;
+ }
+
+ free(stmt);
+
+ return outer;
+ }
+
+ psqlNestedStmt *
+ new_newcommand(psqlNestedStmt *outer, ScriptStatementType stype, bool skip_mode)
+ {
+ psqlNestedStmt *stmt = pg_malloc(sizeof(psqlNestedStmt));
+
+ stmt->typ = stype;
+ stmt->outer_skip_mode = skip_mode;
+ stmt->outer = outer;
+
+ return stmt;
+ }
+
+ psqlCustomStatement *
+ new_custom_statement(char *name, psqlCustomStatement *custom_statements, backslashResult *status)
+ {
+ psqlCustomStatement *cust_stmt;
+
+ /* don't allows nested definitions */
+ if (custom_statements != NULL && custom_statements->writer != NULL)
+ {
+ psql_error("nested definitions are not allowed\n");
+ *status = PSQL_CMD_ERROR;
+ }
+
+ cust_stmt = pg_malloc(sizeof(psqlCustomStatement));
+ cust_stmt->name = name;
+ cust_stmt->next = custom_statements;
+ cust_stmt->src = NULL;
+ cust_stmt->writer = createPQExpBuffer();
+
+ return cust_stmt;
+ }
*** ./psqlscript.h.orig 2009-12-14 10:26:19.000000000 +0100
--- ./psqlscript.h 2009-12-28 14:34:49.257788620 +0100
***************
*** 0 ****
--- 1,73 ----
+
+ #ifndef PSQLSCRIPT_H
+ #define PSQLSCRIPT_H
+
+ #include "pqexpbuffer.h"
+ #include "command.h"
+
+ typedef enum
+ {
+ PSQL_FORC,
+ PSQL_IF,
+ PSQL_IFDEF,
+ PSQL_NEWCOMMAND
+ } ScriptStatementType;
+
+ typedef struct _psqlNestedStmt
+ {
+ ScriptStatementType typ;
+ bool outer_skip_mode; /* skip mode state before start of statement */
+ struct _psqlNestedStmt *outer; /* pointer to outer block (if exists) */
+ } psqlNestedStmt;
+
+ typedef struct _psqlNestedIf
+ {
+ ScriptStatementType typ;
+ bool outer_skip_mode; /* skip mode state before start of statement */
+ struct _psqlNestedStmt *outer; /* pointer to outer block (if exists) */
+ bool successful; /* true when any part is processed */
+ } psqlNestedIf;
+
+ typedef struct _psqlNestedLoop
+ {
+ ScriptStatementType typ;
+ bool outer_skip_mode; /* skip mode state before start of loop */
+ struct _psqlNestedLoop *outer; /* pointer to outer block (if exists) */
+ PQExpBuffer lines;
+ bool writeable;
+ union
+ {
+ char *cursor_name;
+ } params;
+ char *restored_lines; /* begin of allocated space for restored lines */
+ char *reader_pos; /* current position for reading in restored lines */
+ } psqlNestedLoop;
+
+ typedef struct _psqlCustomStatement
+ {
+ char *name;
+ struct _psqlCustomStatement *next;
+ char *src;
+ PQExpBuffer writer;
+ } psqlCustomStatement;
+
+ typedef struct _psqlCustomStmtReaderData
+ {
+ struct _psqlCustomStmtReaderData *outer;
+ char *reader;
+ char *src;
+ } psqlCustomStmtReaderData;
+
+ extern psqlNestedLoop *new_for_cursor(char *cursor_name, psqlNestedLoop *outer, bool skip_mode);
+ extern psqlNestedLoop *remove_loop(psqlNestedLoop *nloop, ScriptStatementType stype,
+ const char *cmd, backslashResult *status, bool *skip_mode);
+
+ extern psqlNestedStmt *new_loop(psqlNestedStmt *outer, ScriptStatementType stype, bool skip_mode);
+ extern psqlNestedStmt *new_if(psqlNestedStmt *outer, ScriptStatementType stype, bool skip_mode);
+ extern psqlNestedStmt *remove_stmt(psqlNestedStmt *stmt, ScriptStatementType stype,
+ const char *cmd, backslashResult *status, bool *skip_mode);
+ extern psqlNestedStmt *new_newcommand(psqlNestedStmt *outer, ScriptStatementType stype, bool skip_mode);
+ extern psqlCustomStatement *new_custom_statement(char *name, psqlCustomStatement *custom_statements,
+ backslashResult *status);
+
+ #endif
*** ./settings.h.orig 2009-12-18 09:18:14.000000000 +0100
--- ./settings.h 2009-12-30 14:48:05.540059631 +0100
***************
*** 9,14 ****
--- 9,16 ----
#define SETTINGS_H
#include "libpq-fe.h"
+ #include "pqexpbuffer.h"
+ #include "psqlscript.h"
#include "variables.h"
#include "print.h"
***************
*** 111,116 ****
--- 113,127 ----
const char *prompt2;
const char *prompt3;
PGVerbosity verbosity; /* current error verbosity level */
+ /*
+ * Support for construct
+ */
+ psqlNestedLoop *current_loop; /* pointer to loop's stack */
+ psqlNestedStmt *current_stmt; /* pointer to meta controll's stack */
+ psqlCustomStatement *custom_statements; /* pointer to list of cust. statements */
+ psqlCustomStmtReaderData *custom_statement_readbuffer; /* used for expended custom statements */
+ bool custom_stmt_mode; /* execution of custom statement */
+ bool skip_mode;
} PsqlSettings;
extern PsqlSettings pset;
*** ./startup.c.orig 2009-12-18 09:18:14.000000000 +0100
--- ./startup.c 2009-12-30 15:23:00.154059260 +0100
***************
*** 122,135 ****
--- 122,139 ----
pset.queryFoutPipe = false;
pset.cur_cmd_source = stdin;
pset.cur_cmd_interactive = false;
+ pset.custom_statements = NULL;
/* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */
pset.popt.topt.format = PRINT_ALIGNED;
+ pset.popt.topt.textwrapping = TEXTWRAPPING_DEFAULT;
+ pset.popt.topt.header_style = PRINT_HEADER_CENTER;
pset.popt.topt.border = 1;
pset.popt.topt.pager = 1;
pset.popt.topt.start_table = true;
pset.popt.topt.stop_table = true;
pset.popt.default_footer = true;
+ pset.popt.topt.multiline_header = false;
/* We must get COLUMNS here before readline() sets it */
pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0;
*** ./tab-complete.c.orig 2009-12-11 04:34:56.000000000 +0100
--- ./tab-complete.c 2009-12-30 20:02:39.164184063 +0100
***************
*** 630,638 ****
"\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\deu", "\\dew", "\\df",
"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl",
"\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
! "\\e", "\\echo", "\\ef", "\\encoding",
! "\\f", "\\g", "\\h", "\\help", "\\H", "\\i", "\\l",
! "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
"\\set", "\\t", "\\T",
"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
--- 630,639 ----
"\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\deu", "\\dew", "\\df",
"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl",
"\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
! "\\e", "\\echo", "\\ef", "\\encoding", "\\endif", "\\endforc", "\\else", "\\elseif",
! "\\endifdef", "\\f", "\\forc", "\\g", "\\h", "\\help", "\\H", "\\i", "\\if", "\\ifdef",
! "\\newcommand", "\\endnewcommand",
! "\\l", "\\lf", "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
"\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
"\\set", "\\t", "\\T",
"\\timing", "\\unset", "\\x", "\\w", "\\z", "\\!", NULL
***************
*** 2265,2270 ****
--- 2266,2274 ----
else if (strcmp(prev_wd, "\\ef") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
+
+ else if (strncmp(prev_wd, "\\lf", strlen("\\lf")) == 0)
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (strcmp(prev_wd, "\\encoding") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_encodings);
***************
*** 2277,2283 ****
static const char *const my_list[] =
{"format", "border", "expanded",
"null", "fieldsep", "tuples_only", "title", "tableattr",
! "linestyle", "pager", "recordsep", NULL};
COMPLETE_WITH_LIST(my_list);
}
--- 2281,2288 ----
static const char *const my_list[] =
{"format", "border", "expanded",
"null", "fieldsep", "tuples_only", "title", "tableattr",
! "linestyle", "pager", "recordsep", "headerstyle", "multiline-header",
! "textwrapping", NULL};
COMPLETE_WITH_LIST(my_list);
}