diff --git a/src/bin/psql/.gitignore b/src/bin/psql/.gitignore index 7272f6e35db2e..dacbf3046d4b4 100644 --- a/src/bin/psql/.gitignore +++ b/src/bin/psql/.gitignore @@ -3,4 +3,5 @@ /sql_help.h /sql_help.c /psql +/slash2sql /tmp_check/ diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile index 5b1545d9948ad..18c1adad29920 100644 --- a/src/bin/psql/Makefile +++ b/src/bin/psql/Makefile @@ -43,12 +43,34 @@ OBJS = \ tab-complete.o \ variables.o +SQLCMD_OBJS = \ + $(WIN32RES) \ + slash2sql.o \ + command.o \ + common.o \ + copy.o \ + crosstabview.o \ + describe.o \ + help.o \ + input.o \ + large_obj.o \ + mainloop.o \ + prompt.o \ + psqlscanslash.o \ + sql_help.o \ + stringutils.o \ + tab-complete.o \ + variables.o -all: psql + +all: psql slash2sql psql: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) +slash2sql: $(SQLCMD_OBJS) | submake-libpq submake-libpgport submake-libpgfeutils + $(CC) $(CFLAGS) $(SQLCMD_OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) + help.o: sql_help.h # See notes in src/backend/parser/Makefile about the following two rules @@ -66,16 +88,17 @@ tab-complete.c: gen_tabcomplete.pl tab-complete.in.c install: all installdirs $(INSTALL_PROGRAM) psql$(X) '$(DESTDIR)$(bindir)/psql$(X)' + $(INSTALL_PROGRAM) slash2sql$(X) '$(DESTDIR)$(bindir)/slash2sql$(X)' $(INSTALL_DATA) $(srcdir)/psqlrc.sample '$(DESTDIR)$(datadir)/psqlrc.sample' installdirs: $(MKDIR_P) '$(DESTDIR)$(bindir)' '$(DESTDIR)$(datadir)' uninstall: - rm -f '$(DESTDIR)$(bindir)/psql$(X)' '$(DESTDIR)$(datadir)/psqlrc.sample' + rm -f '$(DESTDIR)$(bindir)/psql$(X)' '$(DESTDIR)$(bindir)/slash2sql$(X)' '$(DESTDIR)$(datadir)/psqlrc.sample' clean distclean: - rm -f psql$(X) $(OBJS) lex.backup + rm -f psql$(X) slash2sql$(X) $(OBJS) $(SQLCMD_OBJS) lex.backup rm -rf tmp_check rm -f sql_help.h sql_help.c psqlscanslash.c tab-complete.c diff --git a/src/bin/psql/slash2sql.c b/src/bin/psql/slash2sql.c new file mode 100644 index 0000000000000..b740dbd40467d --- /dev/null +++ b/src/bin/psql/slash2sql.c @@ -0,0 +1,83 @@ +/* + * slash2sql - expand slash commands into SQL + * + * src/bin/psql/slash2sql.c + */ +#include "postgres_fe.h" +#include "command.h" +#include "common.h" +#include "common/logging.h" +#include "mainloop.h" +#include "settings.h" +#include "libpq-int.h" + +/* Global psql options */ +PsqlSettings pset; + +/* + * Main entry point + */ +int main(int argc, char *argv[]) +{ + char *cmd = NULL; + int successResult; + memset(&pset, 0, sizeof(pset)); + + // Disable query execution + pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC; + // Create a fake/empty connection object + pset.db = (PGconn *)malloc(sizeof(PGconn)); + memset(pset.db, 0, sizeof(PGconn)); + + // extract the command as the first argument + if (argc > 1 && argv[1][0] == '\\') + { + cmd = pg_strdup(argv[1] + 1); + } + + /* If a command was provided via command line, execute it and exit */ + if (cmd != NULL && strlen(cmd) > 0) + { + PsqlScanState scan_state; + ConditionalStack cond_stack; + PQExpBuffer query_buf; + PQExpBuffer previous_buf; + + /* Initialize scan state */ + scan_state = psql_scan_create(&psqlscan_callbacks); + cond_stack = conditional_stack_create(); + psql_scan_set_passthrough(scan_state, cond_stack); + + /* Initialize query buffers */ + query_buf = createPQExpBuffer(); + previous_buf = createPQExpBuffer(); + + /* Set up scan state */ + psql_scan_setup(scan_state, cmd, strlen(cmd), 0, standard_strings()); + + // Convert to SQL and output + HandleSlashCmds(scan_state, cond_stack, query_buf, previous_buf); + + // Clean up + psql_scan_destroy(scan_state); + conditional_stack_destroy(cond_stack); + destroyPQExpBuffer(query_buf); + destroyPQExpBuffer(previous_buf); + + // HandleSlashCmds always returns PSQL_CMD_ERROR when execution is disabled + successResult = EXIT_SUCCESS; + } + else + { + pg_log_error("invalid command"); + successResult = EXIT_FAILURE; + } + + /* Clean up */ + if (pset.db) + free(pset.db); + if (cmd) + free(cmd); + + return successResult; +}