@@ -43,7 +43,7 @@ pg_strdup(const char *string)
4343 if (!string )
4444 {
4545 psql_error ("%s: pg_strdup: cannot duplicate null pointer (internal error)\n" ,
46- pset .progname );
46+ pset .progname );
4747 exit (EXIT_FAILURE );
4848 }
4949 tmp = strdup (string );
@@ -615,6 +615,65 @@ PrintQueryTuples(const PGresult *results)
615615}
616616
617617
618+ /*
619+ * StoreQueryTuple: assuming query result is OK, save data into variables
620+ *
621+ * Returns true if successful, false otherwise.
622+ */
623+ static bool
624+ StoreQueryTuple (const PGresult * result )
625+ {
626+ bool success = true;
627+
628+ if (PQntuples (result ) < 1 )
629+ {
630+ psql_error ("no rows returned for \\gset\n" );
631+ success = false;
632+ }
633+ else if (PQntuples (result ) > 1 )
634+ {
635+ psql_error ("more than one row returned for \\gset\n" );
636+ success = false;
637+ }
638+ else
639+ {
640+ int i ;
641+
642+ for (i = 0 ; i < PQnfields (result ); i ++ )
643+ {
644+ char * colname = PQfname (result , i );
645+ char * varname ;
646+ char * value ;
647+
648+ /* concate prefix and column name */
649+ varname = pg_malloc (strlen (pset .gset_prefix ) + strlen (colname ) + 1 );
650+ strcpy (varname , pset .gset_prefix );
651+ strcat (varname , colname );
652+
653+ if (!PQgetisnull (result , 0 , i ))
654+ value = PQgetvalue (result , 0 , i );
655+ else
656+ {
657+ /* for NULL value, unset rather than set the variable */
658+ value = NULL ;
659+ }
660+
661+ if (!SetVariable (pset .vars , varname , value ))
662+ {
663+ psql_error ("could not set variable \"%s\"\n" , varname );
664+ free (varname );
665+ success = false;
666+ break ;
667+ }
668+
669+ free (varname );
670+ }
671+ }
672+
673+ return success ;
674+ }
675+
676+
618677/*
619678 * ProcessResult: utility function for use by SendQuery() only
620679 *
@@ -752,7 +811,7 @@ PrintQueryStatus(PGresult *results)
752811
753812
754813/*
755- * PrintQueryResults: print out query results as required
814+ * PrintQueryResults: print out (or store) query results as required
756815 *
757816 * Note: Utility function for use by SendQuery() only.
758817 *
@@ -770,8 +829,11 @@ PrintQueryResults(PGresult *results)
770829 switch (PQresultStatus (results ))
771830 {
772831 case PGRES_TUPLES_OK :
773- /* print the data ... */
774- success = PrintQueryTuples (results );
832+ /* store or print the data ... */
833+ if (pset .gset_prefix )
834+ success = StoreQueryTuple (results );
835+ else
836+ success = PrintQueryTuples (results );
775837 /* if it's INSERT/UPDATE/DELETE RETURNING, also print status */
776838 cmdstatus = PQcmdStatus (results );
777839 if (strncmp (cmdstatus , "INSERT" , 6 ) == 0 ||
@@ -898,7 +960,7 @@ SendQuery(const char *query)
898960 if (on_error_rollback_warning == false && pset .sversion < 80000 )
899961 {
900962 psql_error ("The server (version %d.%d) does not support savepoints for ON_ERROR_ROLLBACK.\n" ,
901- pset .sversion / 10000 , (pset .sversion / 100 ) % 100 );
963+ pset .sversion / 10000 , (pset .sversion / 100 ) % 100 );
902964 on_error_rollback_warning = true;
903965 }
904966 else
@@ -1046,6 +1108,13 @@ SendQuery(const char *query)
10461108 pset .gfname = NULL ;
10471109 }
10481110
1111+ /* reset \gset trigger */
1112+ if (pset .gset_prefix )
1113+ {
1114+ free (pset .gset_prefix );
1115+ pset .gset_prefix = NULL ;
1116+ }
1117+
10491118 return OK ;
10501119}
10511120
@@ -1072,6 +1141,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
10721141 bool started_txn = false;
10731142 bool did_pager = false;
10741143 int ntuples ;
1144+ int fetch_count ;
10751145 char fetch_cmd [64 ];
10761146 instr_time before ,
10771147 after ;
@@ -1119,9 +1189,18 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
11191189 * elapsed_msec += INSTR_TIME_GET_MILLISEC (after );
11201190 }
11211191
1192+ /*
1193+ * In \gset mode, we force the fetch count to be 2, so that we will throw
1194+ * the appropriate error if the query returns more than one row.
1195+ */
1196+ if (pset .gset_prefix )
1197+ fetch_count = 2 ;
1198+ else
1199+ fetch_count = pset .fetch_count ;
1200+
11221201 snprintf (fetch_cmd , sizeof (fetch_cmd ),
11231202 "FETCH FORWARD %d FROM _psql_cursor" ,
1124- pset . fetch_count );
1203+ fetch_count );
11251204
11261205 /* prepare to write output to \g argument, if any */
11271206 if (pset .gfname )
@@ -1147,7 +1226,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
11471226 if (pset .timing )
11481227 INSTR_TIME_SET_CURRENT (before );
11491228
1150- /* get FETCH_COUNT tuples at a time */
1229+ /* get fetch_count tuples at a time */
11511230 results = PQexec (pset .db , fetch_cmd );
11521231
11531232 if (pset .timing )
@@ -1174,9 +1253,17 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
11741253 break ;
11751254 }
11761255
1256+ if (pset .gset_prefix )
1257+ {
1258+ /* StoreQueryTuple will complain if not exactly one row */
1259+ OK = StoreQueryTuple (results );
1260+ PQclear (results );
1261+ break ;
1262+ }
1263+
11771264 ntuples = PQntuples (results );
11781265
1179- if (ntuples < pset . fetch_count )
1266+ if (ntuples < fetch_count )
11801267 {
11811268 /* this is the last result set, so allow footer decoration */
11821269 my_popt .topt .stop_table = true;
@@ -1214,7 +1301,7 @@ ExecQueryUsingCursor(const char *query, double *elapsed_msec)
12141301 * writing things to the stream, we presume $PAGER has disappeared and
12151302 * stop bothering to pull down more data.
12161303 */
1217- if (ntuples < pset . fetch_count || cancel_pressed || flush_error ||
1304+ if (ntuples < fetch_count || cancel_pressed || flush_error ||
12181305 ferror (pset .queryFout ))
12191306 break ;
12201307 }
0 commit comments