Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : * A stack of automaton states to handle nested conditionals.
3 : *
4 : * Copyright (c) 2000-2023, 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
2201 tgl 18 CBC 6299 : conditional_stack_create(void)
19 : {
20 6299 : ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
21 :
22 6299 : cstack->head = NULL;
23 6299 : return cstack;
24 : }
25 :
26 : /*
27 : * Destroy all the elements from the stack. The stack itself is not freed.
28 : */
29 : void
382 ishii 30 6188 : conditional_stack_reset(ConditionalStack cstack)
2201 tgl 31 4 : {
382 ishii 32 6188 : if (!cstack)
382 ishii 33 UBC 0 : return; /* nothing to do here */
34 :
2201 tgl 35 CBC 6192 : while (conditional_stack_pop(cstack))
36 4 : continue;
37 : }
38 :
39 : /*
40 : * destroy stack
41 : */
42 : void
382 ishii 43 6186 : conditional_stack_destroy(ConditionalStack cstack)
44 : {
45 6186 : conditional_stack_reset(cstack);
2201 tgl 46 6186 : free(cstack);
47 6186 : }
48 :
49 : /*
50 : * Create a new conditional branch.
51 : */
52 : void
53 6160 : conditional_stack_push(ConditionalStack cstack, ifState new_state)
54 : {
55 6160 : IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
56 :
57 6160 : p->if_state = new_state;
58 6160 : p->query_len = -1;
59 6160 : p->paren_depth = -1;
60 6160 : p->next = cstack->head;
61 6160 : cstack->head = p;
62 6160 : }
63 :
64 : /*
65 : * Destroy the topmost conditional branch.
66 : * Returns false if there was no branch to end.
67 : */
68 : bool
69 12346 : conditional_stack_pop(ConditionalStack cstack)
70 : {
71 12346 : IfStackElem *p = cstack->head;
72 :
73 12346 : if (!p)
74 6189 : return false;
75 6157 : cstack->head = cstack->head->next;
76 6157 : free(p);
77 6157 : return true;
78 : }
79 :
80 : /*
81 : * Returns current stack depth, for debugging purposes.
82 : */
83 : int
1844 teodor 84 UBC 0 : conditional_stack_depth(ConditionalStack cstack)
85 : {
86 0 : if (cstack == NULL)
87 0 : return -1;
88 : else
89 : {
1809 tgl 90 0 : IfStackElem *p = cstack->head;
1844 teodor 91 0 : int depth = 0;
92 :
93 0 : while (p != NULL)
94 : {
95 0 : depth++;
96 0 : p = p->next;
97 : }
98 0 : return depth;
99 : }
100 : }
101 :
102 : /*
103 : * Fetch the current state of the top of the stack.
104 : */
105 : ifState
2201 tgl 106 CBC 168575 : conditional_stack_peek(ConditionalStack cstack)
107 : {
108 168575 : if (conditional_stack_empty(cstack))
109 166101 : return IFSTATE_NONE;
110 2474 : return cstack->head->if_state;
111 : }
112 :
113 : /*
114 : * Change the state of the topmost branch.
115 : * Returns false if there was no branch state to set.
116 : */
117 : bool
118 137 : conditional_stack_poke(ConditionalStack cstack, ifState new_state)
119 : {
120 137 : if (conditional_stack_empty(cstack))
2201 tgl 121 UBC 0 : return false;
2201 tgl 122 CBC 137 : cstack->head->if_state = new_state;
123 137 : return true;
124 : }
125 :
126 : /*
127 : * True if there are no active \if-blocks.
128 : */
129 : bool
130 180589 : conditional_stack_empty(ConditionalStack cstack)
131 : {
132 180589 : return cstack->head == NULL;
133 : }
134 :
135 : /*
136 : * True if we should execute commands normally; that is, the current
137 : * conditional branch is active, or there is no open \if block.
138 : */
139 : bool
140 168009 : conditional_active(ConditionalStack cstack)
141 : {
142 168009 : ifState s = conditional_stack_peek(cstack);
143 :
144 168009 : return s == IFSTATE_NONE || s == IFSTATE_TRUE || s == IFSTATE_ELSE_TRUE;
145 : }
146 :
147 : /*
148 : * Save current query buffer length in topmost stack entry.
149 : */
150 : void
151 114 : conditional_stack_set_query_len(ConditionalStack cstack, int len)
152 : {
153 114 : Assert(!conditional_stack_empty(cstack));
154 114 : cstack->head->query_len = len;
155 114 : }
156 :
157 : /*
158 : * Fetch last-recorded query buffer length from topmost stack entry.
159 : * Will return -1 if no stack or it was never saved.
160 : */
161 : int
162 98 : conditional_stack_get_query_len(ConditionalStack cstack)
163 : {
164 98 : if (conditional_stack_empty(cstack))
2201 tgl 165 UBC 0 : return -1;
2201 tgl 166 CBC 98 : return cstack->head->query_len;
167 : }
168 :
169 : /*
170 : * Save current parenthesis nesting depth in topmost stack entry.
171 : */
172 : void
173 114 : conditional_stack_set_paren_depth(ConditionalStack cstack, int depth)
174 : {
175 114 : Assert(!conditional_stack_empty(cstack));
176 114 : cstack->head->paren_depth = depth;
177 114 : }
178 :
179 : /*
180 : * Fetch last-recorded parenthesis nesting depth from topmost stack entry.
181 : * Will return -1 if no stack or it was never saved.
182 : */
183 : int
184 98 : conditional_stack_get_paren_depth(ConditionalStack cstack)
185 : {
186 98 : if (conditional_stack_empty(cstack))
2201 tgl 187 UBC 0 : return -1;
2201 tgl 188 CBC 98 : return cstack->head->paren_depth;
189 : }
|