Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * A stack of automaton states to handle nested conditionals. 3 : * 4 : * Copyright (c) 2000-2025, 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 18914 : conditional_stack_create(void) 19 : { 20 18914 : ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData)); 21 : 22 18914 : cstack->head = NULL; 23 18914 : return cstack; 24 : } 25 : 26 : /* 27 : * Destroy all the elements from the stack. The stack itself is not freed. 28 : */ 29 : void 30 18630 : conditional_stack_reset(ConditionalStack cstack) 31 : { 32 18630 : if (!cstack) 33 0 : return; /* nothing to do here */ 34 : 35 18642 : while (conditional_stack_pop(cstack)) 36 12 : continue; 37 : } 38 : 39 : /* 40 : * destroy stack 41 : */ 42 : void 43 18626 : conditional_stack_destroy(ConditionalStack cstack) 44 : { 45 18626 : conditional_stack_reset(cstack); 46 18626 : free(cstack); 47 18626 : } 48 : 49 : /* 50 : * Create a new conditional branch. 51 : */ 52 : void 53 13958 : conditional_stack_push(ConditionalStack cstack, ifState new_state) 54 : { 55 13958 : IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem)); 56 : 57 13958 : p->if_state = new_state; 58 13958 : p->query_len = -1; 59 13958 : p->paren_depth = -1; 60 13958 : p->next = cstack->head; 61 13958 : cstack->head = p; 62 13958 : } 63 : 64 : /* 65 : * Destroy the topmost conditional branch. 66 : * Returns false if there was no branch to end. 67 : */ 68 : bool 69 32582 : conditional_stack_pop(ConditionalStack cstack) 70 : { 71 32582 : IfStackElem *p = cstack->head; 72 : 73 32582 : if (!p) 74 18632 : return false; 75 13950 : cstack->head = cstack->head->next; 76 13950 : free(p); 77 13950 : return true; 78 : } 79 : 80 : /* 81 : * Returns current stack depth, for debugging purposes. 82 : */ 83 : int 84 0 : conditional_stack_depth(ConditionalStack cstack) 85 : { 86 0 : if (cstack == NULL) 87 0 : return -1; 88 : else 89 : { 90 0 : IfStackElem *p = cstack->head; 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 106 387760 : conditional_stack_peek(ConditionalStack cstack) 107 : { 108 387760 : if (conditional_stack_empty(cstack)) 109 383308 : return IFSTATE_NONE; 110 4452 : 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 322 : conditional_stack_poke(ConditionalStack cstack, ifState new_state) 119 : { 120 322 : if (conditional_stack_empty(cstack)) 121 0 : return false; 122 322 : cstack->head->if_state = new_state; 123 322 : return true; 124 : } 125 : 126 : /* 127 : * True if there are no active \if-blocks. 128 : */ 129 : bool 130 406958 : conditional_stack_empty(ConditionalStack cstack) 131 : { 132 406958 : 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 386586 : conditional_active(ConditionalStack cstack) 141 : { 142 386586 : ifState s = conditional_stack_peek(cstack); 143 : 144 386586 : 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 252 : conditional_stack_set_query_len(ConditionalStack cstack, int len) 152 : { 153 : Assert(!conditional_stack_empty(cstack)); 154 252 : cstack->head->query_len = len; 155 252 : } 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 216 : conditional_stack_get_query_len(ConditionalStack cstack) 163 : { 164 216 : if (conditional_stack_empty(cstack)) 165 0 : return -1; 166 216 : return cstack->head->query_len; 167 : } 168 : 169 : /* 170 : * Save current parenthesis nesting depth in topmost stack entry. 171 : */ 172 : void 173 252 : conditional_stack_set_paren_depth(ConditionalStack cstack, int depth) 174 : { 175 : Assert(!conditional_stack_empty(cstack)); 176 252 : cstack->head->paren_depth = depth; 177 252 : } 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 216 : conditional_stack_get_paren_depth(ConditionalStack cstack) 185 : { 186 216 : if (conditional_stack_empty(cstack)) 187 0 : return -1; 188 216 : return cstack->head->paren_depth; 189 : }