Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : * A stack of automaton states to handle nested conditionals.
3 : : *
4 : : * Copyright (c) 2000-2026, PostgreSQL Global Development Group
5 : : *
6 : : * src/fe_utils/conditional.c
7 : : *
8 : : *-------------------------------------------------------------------------
9 : : */
10 : : #include "postgres_fe.h"
11 : :
12 : : #include "fe_utils/conditional.h"
13 : :
14 : : /*
15 : : * create stack
16 : : */
17 : : ConditionalStack
18 : 10757 : conditional_stack_create(void)
19 : : {
20 : 10757 : ConditionalStack cstack = pg_malloc_object(ConditionalStackData);
21 : :
22 : 10757 : cstack->head = NULL;
23 : 10757 : return cstack;
24 : : }
25 : :
26 : : /*
27 : : * Destroy all the elements from the stack. The stack itself is not freed.
28 : : */
29 : : void
30 : 10617 : conditional_stack_reset(ConditionalStack cstack)
31 : 15 : {
32 [ - + ]: 10617 : if (!cstack)
33 : 0 : return; /* nothing to do here */
34 : :
35 [ + + ]: 10632 : while (conditional_stack_pop(cstack))
36 : 15 : continue;
37 : : }
38 : :
39 : : /*
40 : : * destroy stack
41 : : */
42 : : void
43 : 10606 : conditional_stack_destroy(ConditionalStack cstack)
44 : : {
45 : 10606 : conditional_stack_reset(cstack);
46 : 10606 : free(cstack);
47 : 10606 : }
48 : :
49 : : /*
50 : : * Create a new conditional branch.
51 : : */
52 : : void
53 : 32359 : conditional_stack_push(ConditionalStack cstack, ifState new_state)
54 : : {
55 : 32359 : IfStackElem *p = pg_malloc_object(IfStackElem);
56 : :
57 : 32359 : p->if_state = new_state;
58 : 32359 : p->query_len = -1;
59 : 32359 : p->lex_state = NULL;
60 : 32359 : p->next = cstack->head;
61 : 32359 : cstack->head = p;
62 : 32359 : }
63 : :
64 : : /*
65 : : * Destroy the topmost conditional branch.
66 : : * Returns false if there was no branch to end.
67 : : */
68 : : bool
69 : 42973 : conditional_stack_pop(ConditionalStack cstack)
70 : : {
71 : 42973 : IfStackElem *p = cstack->head;
72 : :
73 [ + + ]: 42973 : if (!p)
74 : 10618 : return false;
75 : 32355 : cstack->head = cstack->head->next;
76 [ + + ]: 32355 : if (p->lex_state)
77 : 156 : free(p->lex_state);
78 : 32355 : free(p);
79 : 32355 : return true;
80 : : }
81 : :
82 : : /*
83 : : * Returns current stack depth, for debugging purposes.
84 : : */
85 : : int
86 : 0 : conditional_stack_depth(ConditionalStack cstack)
87 : : {
88 [ # # ]: 0 : if (cstack == NULL)
89 : 0 : return -1;
90 : : else
91 : : {
92 : 0 : IfStackElem *p = cstack->head;
93 : 0 : int depth = 0;
94 : :
95 [ # # ]: 0 : while (p != NULL)
96 : : {
97 : 0 : depth++;
98 : 0 : p = p->next;
99 : : }
100 : 0 : return depth;
101 : : }
102 : : }
103 : :
104 : : /*
105 : : * Fetch the current state of the top of the stack.
106 : : */
107 : : ifState
108 : 335239 : conditional_stack_peek(ConditionalStack cstack)
109 : : {
110 [ + + ]: 335239 : if (conditional_stack_empty(cstack))
111 : 332111 : return IFSTATE_NONE;
112 : 3128 : return cstack->head->if_state;
113 : : }
114 : :
115 : : /*
116 : : * Change the state of the topmost branch.
117 : : * Returns false if there was no branch state to set.
118 : : */
119 : : bool
120 : 232 : conditional_stack_poke(ConditionalStack cstack, ifState new_state)
121 : : {
122 [ - + ]: 232 : if (conditional_stack_empty(cstack))
123 : 0 : return false;
124 : 232 : cstack->head->if_state = new_state;
125 : 232 : return true;
126 : : }
127 : :
128 : : /*
129 : : * True if there are no active \if-blocks.
130 : : */
131 : : bool
132 : 346054 : conditional_stack_empty(ConditionalStack cstack)
133 : : {
134 : 346054 : return cstack->head == NULL;
135 : : }
136 : :
137 : : /*
138 : : * True if we should execute commands normally; that is, the current
139 : : * conditional branch is active, or there is no open \if block.
140 : : */
141 : : bool
142 : 334460 : conditional_active(ConditionalStack cstack)
143 : : {
144 : 334460 : ifState s = conditional_stack_peek(cstack);
145 : :
146 [ + + + + : 334460 : return s == IFSTATE_NONE || s == IFSTATE_TRUE || s == IFSTATE_ELSE_TRUE;
+ + ]
147 : : }
148 : :
149 : : /*
150 : : * Save current query buffer length in topmost stack entry.
151 : : */
152 : : void
153 : 200 : conditional_stack_set_query_len(ConditionalStack cstack, int len)
154 : : {
155 : : Assert(!conditional_stack_empty(cstack));
156 : 200 : cstack->head->query_len = len;
157 : 200 : }
158 : :
159 : : /*
160 : : * Fetch last-recorded query buffer length from topmost stack entry.
161 : : * Will return -1 if no stack or it was never saved.
162 : : */
163 : : int
164 : 169 : conditional_stack_get_query_len(ConditionalStack cstack)
165 : : {
166 [ - + ]: 169 : if (conditional_stack_empty(cstack))
167 : 0 : return -1;
168 : 169 : return cstack->head->query_len;
169 : : }
170 : :
171 : : /*
172 : : * Save current lexer state in topmost stack entry.
173 : : *
174 : : * The lexer state is presumed to be a single pg_malloc'd chunk.
175 : : * It will be freed automatically when the stack entry is popped.
176 : : */
177 : : void
178 : 200 : conditional_stack_set_lex_state(ConditionalStack cstack,
179 : : PsqlScanStateSave *lex_state)
180 : : {
181 : : Assert(!conditional_stack_empty(cstack));
182 [ + + ]: 200 : if (cstack->head->lex_state) /* free old state, if any */
183 : 44 : free(cstack->head->lex_state);
184 : 200 : cstack->head->lex_state = lex_state;
185 : 200 : }
186 : :
187 : : /*
188 : : * Fetch last-recorded lexer state from topmost stack entry.
189 : : * Will return NULL if no stack or it was never saved.
190 : : */
191 : : PsqlScanStateSave *
192 : 169 : conditional_stack_get_lex_state(ConditionalStack cstack)
193 : : {
194 [ - + ]: 169 : if (conditional_stack_empty(cstack))
195 : 0 : return NULL;
196 : 169 : return cstack->head->lex_state;
197 : : }
|