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