Commits

Andrew Dunstan committed 372216c

Initial working version

  • Participants
  • Parent commits 51fed14
  • Branches psql-binout

Comments (0)

Files changed (9)

File src/bin/psql/command.c

 		status = PSQL_CMD_SEND;
 	}
 
+	/* \gb means send query, get/produce results in binary */
+	else if (strcmp(cmd, "gb") == 0)
+	{
+		char	   *fname = psql_scan_slash_option(scan_state,
+												   OT_FILEPIPE, NULL, false);
+
+		if (!fname)
+			pset.gfname = NULL;
+		else
+		{
+			expand_tilde(&fname);
+			pset.gfname = pg_strdup(fname);
+		}
+		free(fname);
+		status = PSQL_CMD_SEND_BIN;
+	}
+
+	/* \gB means send query, get/produce results in binary, and no separators */
+	else if (strcmp(cmd, "gbn") == 0)
+	{
+		char	   *fname = psql_scan_slash_option(scan_state,
+												   OT_FILEPIPE, NULL, false);
+
+		if (!fname)
+			pset.gfname = NULL;
+		else
+		{
+			expand_tilde(&fname);
+			pset.gfname = pg_strdup(fname);
+		}
+		free(fname);
+		status = PSQL_CMD_SEND_BIN_NS;
+	}
+
 	/* help */
 	else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
 	{

File src/bin/psql/command.h

 {
 	PSQL_CMD_UNKNOWN = 0,		/* not done parsing yet (internal only) */
 	PSQL_CMD_SEND,				/* query complete; send off */
+	PSQL_CMD_SEND_BIN,          /* same, but get/produce result in binary */
+	PSQL_CMD_SEND_BIN_NS,       /* same, but with no separators*/
 	PSQL_CMD_SKIP_LINE,			/* keep building query */
 	PSQL_CMD_TERMINATE,			/* quit program */
 	PSQL_CMD_NEWEDIT,			/* query buffer was changed (e.g., via \e) */

File src/bin/psql/common.c

  * Returns true if successful, false otherwise.
  */
 static bool
-PrintQueryTuples(const PGresult *results)
+PrintQueryTuples(const PGresult *results,
+				 bool binary,
+				 bool noseps)
 {
 	printQueryOpt my_popt = pset.popt;
 
 			return false;
 		}
 
-		printQuery(results, &my_popt, pset.queryFout, pset.logfile);
+		if (!binary)
+			printQuery(results, &my_popt, pset.queryFout, pset.logfile);
+		else
+			printQueryBin(results, &my_popt, pset.queryFout, pset.logfile, noseps);
 
 		/* close file/pipe, restore old setting */
 		setQFout(NULL);
 		pset.gfname = NULL;
 	}
 	else
-		printQuery(results, &my_popt, pset.queryFout, pset.logfile);
+	{
+		if (!binary)
+			printQuery(results, &my_popt, pset.queryFout, pset.logfile);
+		else
+			printQueryBin(results, &my_popt, pset.queryFout, pset.logfile, noseps);
+	}
 
 	return true;
 }
  * Returns true if the query executed successfully, false otherwise.
  */
 static bool
-PrintQueryResults(PGresult *results)
+PrintQueryResults(PGresult *results,
+				  bool binary,
+				  bool noseps)
 {
 	bool		success;
 	const char *cmdstatus;
 	{
 		case PGRES_TUPLES_OK:
 			/* print the data ... */
-			success = PrintQueryTuples(results);
+			success = PrintQueryTuples(results, binary, noseps);
 			/* if it's INSERT/UPDATE/DELETE RETURNING, also print status */
 			cmdstatus = PQcmdStatus(results);
 			if (strncmp(cmdstatus, "INSERT", 6) == 0 ||
  * Returns true if the query executed successfully, false otherwise.
  */
 bool
-SendQuery(const char *query)
+SendQuery(const char *query,
+		  bool binary,
+		  bool noseps)
 {
 	PGresult   *results;
 	PGTransactionStatusType transaction_status;
 		if (pset.timing)
 			INSTR_TIME_SET_CURRENT(before);
 
-		results = PQexec(pset.db, query);
+		if (! binary)
+			results = PQexec(pset.db, query);
+		else
+			results = PQexecParams(pset.db, query,0, NULL, NULL, NULL, NULL, 1);
 
 		/* these operations are included in the timing result: */
 		ResetCancelConn();
 
 		/* but printing results isn't: */
 		if (OK && results)
-			OK = PrintQueryResults(results);
+			OK = PrintQueryResults(results, binary, noseps);
 	}
 	else
 	{

File src/bin/psql/common.h

 
 extern PGresult *PSQLexec(const char *query, bool start_xact);
 
-extern bool SendQuery(const char *query);
+extern bool SendQuery(const char *query, bool binary, bool noseps);
 
 extern bool is_superuser(void);
 extern bool standard_strings(void);

File src/bin/psql/copy.c

 	/* Run it like a user command, interposing the data source or sink. */
 	save_file = *override_file;
 	*override_file = copystream;
-	success = SendQuery(query.data);
+	success = SendQuery(query.data, false, false);
 	*override_file = save_file;
 	termPQExpBuffer(&query);
 

File src/bin/psql/mainloop.c

 				}
 
 				/* execute query */
-				success = SendQuery(query_buf->data);
+				success = SendQuery(query_buf->data, false, false);
 				slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
 
 				/* transfer query to previous_buf by pointer-swapping */
 
 				success = slashCmdStatus != PSQL_CMD_ERROR;
 
-				if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_NEWEDIT) &&
+				if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_SEND_BIN || 
+					 slashCmdStatus == PSQL_CMD_SEND_BIN_NS || slashCmdStatus == PSQL_CMD_NEWEDIT) &&
 					query_buf->len == 0)
 				{
 					/* copy previous buffer to current for handling */
 					appendPQExpBufferStr(query_buf, previous_buf->data);
 				}
 
-				if (slashCmdStatus == PSQL_CMD_SEND)
+				if (slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_SEND_BIN || slashCmdStatus == PSQL_CMD_SEND_BIN_NS)
 				{
-					success = SendQuery(query_buf->data);
+					bool usebin = slashCmdStatus != PSQL_CMD_SEND;
+					bool noseps = slashCmdStatus == PSQL_CMD_SEND_BIN_NS;
+
+					success = SendQuery(query_buf->data, usebin, noseps);
 
 					/* transfer query to previous_buf by pointer-swapping */
 					{
 			pg_send_history(history_buf);
 
 		/* execute query */
-		success = SendQuery(query_buf->data);
+		success = SendQuery(query_buf->data, false, false);
 
 		if (!success && die_on_error)
 			successResult = EXIT_USER;

File src/bin/psql/print.c

 }
 
 /*
+ * Use this to print query results when results are produced in binary
+ * rather than text.
+ *
+ */
+void
+printQueryBin(const PGresult *result, const printQueryOpt *opt, FILE *fout, FILE *flog, bool noseps)
+{
+
+	int fields, rows, fld, row, flen;
+	char *val;
+
+	if (cancel_pressed)
+		return;
+
+	fields = PQnfields(result);
+	rows = PQntuples(result);
+
+	for (row = 0; row < rows; row++)
+	{
+		for (fld = 0; fld < fields; fld++)
+		{
+			if (! noseps && fld > 0)
+			{
+				if (opt->topt.fieldSep.separator_zero)
+					fputc(0, fout);
+				else
+					fprintf(fout, "%s", opt->topt.fieldSep.separator);
+			}
+			if (PQgetisnull(result,row,fld))
+				continue;
+			val = PQgetvalue(result,row,fld);
+			flen = PQgetlength(result,row,fld);
+			fwrite(val, flen, 1, fout);
+		}
+		if (!noseps)
+		{
+				if (opt->topt.recordSep.separator_zero)
+					fputc(0, fout);
+				else
+					fprintf(fout, "%s", opt->topt.recordSep.separator);			
+		}
+	}
+	
+
+}
+
+/*
  * Use this to print query results
  *
  * It calls printTable with all the things set straight.

File src/bin/psql/print.h

 extern void printTable(const printTableContent *cont, FILE *fout, FILE *flog);
 extern void printQuery(const PGresult *result, const printQueryOpt *opt,
 		   FILE *fout, FILE *flog);
+extern void printQueryBin(const PGresult *result, const printQueryOpt *opt,
+		   FILE *fout, FILE *flog, bool noseps);
 
 extern void setDecimalLocale(void);
 extern const printTextFormat *get_line_style(const printTableOpt *opt);

File src/bin/psql/startup.c

 		if (pset.echo == PSQL_ECHO_ALL)
 			puts(options.action_string);
 
-		successResult = SendQuery(options.action_string)
+		successResult = SendQuery(options.action_string, false, false)
 			? EXIT_SUCCESS : EXIT_FAILURE;
 	}