@@ -480,6 +480,7 @@ typedef enum MetaCommand
480
480
META_SHELL , /* \shell */
481
481
META_SLEEP , /* \sleep */
482
482
META_GSET , /* \gset */
483
+ META_ASET , /* \aset */
483
484
META_IF , /* \if */
484
485
META_ELIF , /* \elif */
485
486
META_ELSE , /* \else */
@@ -504,14 +505,16 @@ static const char *QUERYMODE[] = {"simple", "extended", "prepared"};
504
505
* not applied.
505
506
* first_line A short, single-line extract of 'lines', for error reporting.
506
507
* type SQL_COMMAND or META_COMMAND
507
- * meta The type of meta-command, or META_NONE if command is SQL
508
+ * meta The type of meta-command, with META_NONE/GSET/ASET if command
509
+ * is SQL.
508
510
* argc Number of arguments of the command, 0 if not yet processed.
509
511
* argv Command arguments, the first of which is the command or SQL
510
512
* string itself. For SQL commands, after post-processing
511
513
* argv[0] is the same as 'lines' with variables substituted.
512
- * varprefix SQL commands terminated with \gset have this set
514
+ * varprefix SQL commands terminated with \gset or \aset have this set
513
515
* to a non NULL value. If nonempty, it's used to prefix the
514
516
* variable name that receives the value.
517
+ * aset do gset on all possible queries of a combined query (\;).
515
518
* expr Parsed expression, if needed.
516
519
* stats Time spent in this command.
517
520
*/
@@ -2489,6 +2492,8 @@ getMetaCommand(const char *cmd)
2489
2492
mc = META_ENDIF ;
2490
2493
else if (pg_strcasecmp (cmd , "gset" ) == 0 )
2491
2494
mc = META_GSET ;
2495
+ else if (pg_strcasecmp (cmd , "aset" ) == 0 )
2496
+ mc = META_ASET ;
2492
2497
else
2493
2498
mc = META_NONE ;
2494
2499
return mc ;
@@ -2711,17 +2716,25 @@ sendCommand(CState *st, Command *command)
2711
2716
* Process query response from the backend.
2712
2717
*
2713
2718
* If varprefix is not NULL, it's the variable name prefix where to store
2714
- * the results of the *last* command.
2719
+ * the results of the *last* command (META_GSET) or *all* commands
2720
+ * (META_ASET).
2715
2721
*
2716
2722
* Returns true if everything is A-OK, false if any error occurs.
2717
2723
*/
2718
2724
static bool
2719
- readCommandResponse (CState * st , char * varprefix )
2725
+ readCommandResponse (CState * st , MetaCommand meta , char * varprefix )
2720
2726
{
2721
2727
PGresult * res ;
2722
2728
PGresult * next_res ;
2723
2729
int qrynum = 0 ;
2724
2730
2731
+ /*
2732
+ * varprefix should be set only with \gset or \aset, and SQL commands do
2733
+ * not need it.
2734
+ */
2735
+ Assert ((meta == META_NONE && varprefix == NULL ) ||
2736
+ ((meta == META_GSET || meta == META_ASET ) && varprefix != NULL ));
2737
+
2725
2738
res = PQgetResult (st -> con );
2726
2739
2727
2740
while (res != NULL )
@@ -2736,7 +2749,7 @@ readCommandResponse(CState *st, char *varprefix)
2736
2749
{
2737
2750
case PGRES_COMMAND_OK : /* non-SELECT commands */
2738
2751
case PGRES_EMPTY_QUERY : /* may be used for testing no-op overhead */
2739
- if (is_last && varprefix != NULL )
2752
+ if (is_last && meta == META_GSET )
2740
2753
{
2741
2754
pg_log_error ("client %d script %d command %d query %d: expected one row, got %d" ,
2742
2755
st -> id , st -> use_file , st -> command , qrynum , 0 );
@@ -2745,14 +2758,22 @@ readCommandResponse(CState *st, char *varprefix)
2745
2758
break ;
2746
2759
2747
2760
case PGRES_TUPLES_OK :
2748
- if (is_last && varprefix != NULL )
2761
+ if (( is_last && meta == META_GSET ) || meta == META_ASET )
2749
2762
{
2750
- if (PQntuples (res ) != 1 )
2763
+ int ntuples = PQntuples (res );
2764
+
2765
+ if (meta == META_GSET && ntuples != 1 )
2751
2766
{
2767
+ /* under \gset, report the error */
2752
2768
pg_log_error ("client %d script %d command %d query %d: expected one row, got %d" ,
2753
2769
st -> id , st -> use_file , st -> command , qrynum , PQntuples (res ));
2754
2770
goto error ;
2755
2771
}
2772
+ else if (meta == META_ASET && ntuples <= 0 )
2773
+ {
2774
+ /* coldly skip empty result under \aset */
2775
+ break ;
2776
+ }
2756
2777
2757
2778
/* store results into variables */
2758
2779
for (int fld = 0 ; fld < PQnfields (res ); fld ++ )
@@ -2763,9 +2784,9 @@ readCommandResponse(CState *st, char *varprefix)
2763
2784
if (* varprefix != '\0' )
2764
2785
varname = psprintf ("%s%s" , varprefix , varname );
2765
2786
2766
- /* store result as a string */
2767
- if (!putVariable (st , "gset" , varname ,
2768
- PQgetvalue (res , 0 , fld )))
2787
+ /* store last row result as a string */
2788
+ if (!putVariable (st , meta == META_ASET ? "aset" : "gset" , varname ,
2789
+ PQgetvalue (res , ntuples - 1 , fld )))
2769
2790
{
2770
2791
/* internal error */
2771
2792
pg_log_error ("client %d script %d command %d query %d: error storing into variable %s" ,
@@ -3181,7 +3202,9 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg)
3181
3202
return ; /* don't have the whole result yet */
3182
3203
3183
3204
/* store or discard the query results */
3184
- if (readCommandResponse (st , sql_script [st -> use_file ].commands [st -> command ]-> varprefix ))
3205
+ if (readCommandResponse (st ,
3206
+ sql_script [st -> use_file ].commands [st -> command ]-> meta ,
3207
+ sql_script [st -> use_file ].commands [st -> command ]-> varprefix ))
3185
3208
st -> state = CSTATE_END_COMMAND ;
3186
3209
else
3187
3210
st -> state = CSTATE_ABORTED ;
@@ -4660,7 +4683,7 @@ process_backslash_command(PsqlScanState sstate, const char *source)
4660
4683
syntax_error (source , lineno , my_command -> first_line , my_command -> argv [0 ],
4661
4684
"unexpected argument" , NULL , -1 );
4662
4685
}
4663
- else if (my_command -> meta == META_GSET )
4686
+ else if (my_command -> meta == META_GSET || my_command -> meta == META_ASET )
4664
4687
{
4665
4688
if (my_command -> argc > 2 )
4666
4689
syntax_error (source , lineno , my_command -> first_line , my_command -> argv [0 ],
@@ -4804,10 +4827,10 @@ ParseScript(const char *script, const char *desc, int weight)
4804
4827
if (command )
4805
4828
{
4806
4829
/*
4807
- * If this is gset, merge into the preceding command. (We
4808
- * don't use a command slot in this case).
4830
+ * If this is gset or aset , merge into the preceding command.
4831
+ * (We don't use a command slot in this case).
4809
4832
*/
4810
- if (command -> meta == META_GSET )
4833
+ if (command -> meta == META_GSET || command -> meta == META_ASET )
4811
4834
{
4812
4835
Command * cmd ;
4813
4836
@@ -4830,6 +4853,9 @@ ParseScript(const char *script, const char *desc, int weight)
4830
4853
else
4831
4854
cmd -> varprefix = pg_strdup (command -> argv [1 ]);
4832
4855
4856
+ /* update the sql command meta */
4857
+ cmd -> meta = command -> meta ;
4858
+
4833
4859
/* cleanup unused command */
4834
4860
free_command (command );
4835
4861
0 commit comments