1 /*------------------------------------------------------------------------- 2 * 3 * bool.c 4 * Functions for the built-in type "bool". 5 * 6 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group 7 * Portions Copyright (c) 1994, Regents of the University of California 8 * 9 * 10 * IDENTIFICATION 11 * src/backend/utils/adt/bool.c 12 * 13 *------------------------------------------------------------------------- 14 */ 15 16 #include "postgres.h" 17 18 #include <ctype.h> 19 20 #include "libpq/pqformat.h" 21 #include "utils/builtins.h" 22 23 /* 24 * Try to interpret value as boolean value. Valid values are: true, 25 * false, yes, no, on, off, 1, 0; as well as unique prefixes thereof. main(int argc,char * argv[])26 * If the string parses okay, return true, else false. 27 * If okay and result is not NULL, return the value in *result. 28 */ 29 bool 30 parse_bool(const char *value, bool *result) 31 { 32 return parse_bool_with_len(value, strlen(value), result); 33 } 34 35 bool 36 parse_bool_with_len(const char *value, size_t len, bool *result) 37 { 38 switch (*value) 39 { 40 case 't': 41 case 'T': 42 if (pg_strncasecmp(value, "true", len) == 0) 43 { 44 if (result) 45 *result = true; 46 return true; 47 } 48 break; 49 case 'f': 50 case 'F': 51 if (pg_strncasecmp(value, "false", len) == 0) 52 { 53 if (result) 54 *result = false; 55 return true; 56 } 57 break; 58 case 'y': 59 case 'Y': 60 if (pg_strncasecmp(value, "yes", len) == 0) 61 { 62 if (result) 63 *result = true; 64 return true; 65 } 66 break; 67 case 'n': 68 case 'N': 69 if (pg_strncasecmp(value, "no", len) == 0) 70 { 71 if (result) 72 *result = false; 73 return true; 74 } 75 break; 76 case 'o': 77 case 'O': 78 /* 'o' is not unique enough */ 79 if (pg_strncasecmp(value, "on", (len > 2 ? len : 2)) == 0) 80 { 81 if (result) 82 *result = true; 83 return true; 84 } 85 else if (pg_strncasecmp(value, "off", (len > 2 ? len : 2)) == 0) 86 { 87 if (result) 88 *result = false; 89 return true; 90 } 91 break; 92 case '1': 93 if (len == 1) 94 { 95 if (result) 96 *result = true; 97 return true; 98 } 99 break; 100 case '0': 101 if (len == 1) 102 { 103 if (result) 104 *result = false; 105 return true; 106 } 107 break; 108 default: 109 break; 110 } 111 112 if (result) 113 *result = false; /* suppress compiler warning */ 114 return false; 115 } 116 117 /***************************************************************************** 118 * USER I/O ROUTINES * 119 *****************************************************************************/ 120 121 /* 122 * boolin - converts "t" or "f" to 1 or 0 123 * 124 * Check explicitly for "true/false" and TRUE/FALSE, 1/0, YES/NO, ON/OFF. 125 * Reject other values. 126 * 127 * In the switch statement, check the most-used possibilities first. 128 */ 129 Datum 130 boolin(PG_FUNCTION_ARGS) 131 { 132 const char *in_str = PG_GETARG_CSTRING(0); 133 const char *str; 134 size_t len; 135 bool result; 136 137 /* 138 * Skip leading and trailing whitespace 139 */ 140 str = in_str; 141 while (isspace((unsigned char) *str)) 142 str++; 143 144 len = strlen(str); 145 while (len > 0 && isspace((unsigned char) str[len - 1])) 146 len--; 147 148 if (parse_bool_with_len(str, len, &result)) 149 PG_RETURN_BOOL(result); 150 151 ereport(ERROR, 152 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 153 errmsg("invalid input syntax for type %s: \"%s\"", 154 "boolean", in_str))); 155 156 /* not reached */ 157 PG_RETURN_BOOL(false); 158 } 159 160 /* 161 * boolout - converts 1 or 0 to "t" or "f" 162 */ 163 Datum 164 boolout(PG_FUNCTION_ARGS) 165 { 166 bool b = PG_GETARG_BOOL(0); 167 char *result = (char *) palloc(2); 168 169 result[0] = (b) ? 't' : 'f'; 170 result[1] = '\0'; 171 PG_RETURN_CSTRING(result); 172 } 173 174 /* 175 * boolrecv - converts external binary format to bool 176 * 177 * The external representation is one byte. Any nonzero value is taken 178 * as "true". 179 */ 180 Datum 181 boolrecv(PG_FUNCTION_ARGS) 182 { 183 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); 184 int ext; 185 186 ext = pq_getmsgbyte(buf); 187 PG_RETURN_BOOL((ext != 0) ? true : false); 188 } 189 190 /* 191 * boolsend - converts bool to binary format 192 */ 193 Datum 194 boolsend(PG_FUNCTION_ARGS) 195 { 196 bool arg1 = PG_GETARG_BOOL(0); 197 StringInfoData buf; 198 199 pq_begintypsend(&buf); 200 pq_sendbyte(&buf, arg1 ? 1 : 0); 201 PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); 202 } 203 204 /* 205 * booltext - cast function for bool => text 206 * 207 * We need this because it's different from the behavior of boolout(); 208 * this function follows the SQL-spec result (except for producing lower case) 209 */ 210 Datum 211 booltext(PG_FUNCTION_ARGS) 212 { 213 bool arg1 = PG_GETARG_BOOL(0); 214 const char *str; 215 216 if (arg1) 217 str = "true"; 218 else 219 str = "false"; 220 221 PG_RETURN_TEXT_P(cstring_to_text(str)); 222 } 223 224 225 /***************************************************************************** 226 * PUBLIC ROUTINES * 227 *****************************************************************************/ 228 229 Datum 230 booleq(PG_FUNCTION_ARGS) 231 { 232 bool arg1 = PG_GETARG_BOOL(0); 233 bool arg2 = PG_GETARG_BOOL(1); 234 235 PG_RETURN_BOOL(arg1 == arg2); 236 } 237 238 Datum 239 boolne(PG_FUNCTION_ARGS) 240 { 241 bool arg1 = PG_GETARG_BOOL(0); 242 bool arg2 = PG_GETARG_BOOL(1); 243 244 PG_RETURN_BOOL(arg1 != arg2); 245 } 246 247 Datum 248 boollt(PG_FUNCTION_ARGS) 249 { 250 bool arg1 = PG_GETARG_BOOL(0); 251 bool arg2 = PG_GETARG_BOOL(1); 252 253 PG_RETURN_BOOL(arg1 < arg2); 254 } 255 256 Datum 257 boolgt(PG_FUNCTION_ARGS) 258 { 259 bool arg1 = PG_GETARG_BOOL(0); 260 bool arg2 = PG_GETARG_BOOL(1); 261 262 PG_RETURN_BOOL(arg1 > arg2); 263 } 264 265 Datum 266 boolle(PG_FUNCTION_ARGS) 267 { 268 bool arg1 = PG_GETARG_BOOL(0); 269 bool arg2 = PG_GETARG_BOOL(1); 270 271 PG_RETURN_BOOL(arg1 <= arg2); 272 } 273 274 Datum 275 boolge(PG_FUNCTION_ARGS) 276 { 277 bool arg1 = PG_GETARG_BOOL(0); 278 bool arg2 = PG_GETARG_BOOL(1); 279 280 PG_RETURN_BOOL(arg1 >= arg2); 281 } 282 283 /* 284 * boolean-and and boolean-or aggregates. 285 */ 286 287 /* 288 * Function for standard EVERY aggregate conforming to SQL 2003. 289 * The aggregate is also named bool_and for consistency. 290 * 291 * Note: this is only used in plain aggregate mode, not moving-aggregate mode. 292 */ 293 Datum 294 booland_statefunc(PG_FUNCTION_ARGS) 295 { 296 PG_RETURN_BOOL(PG_GETARG_BOOL(0) && PG_GETARG_BOOL(1)); 297 } 298 299 /* 300 * Function for standard ANY/SOME aggregate conforming to SQL 2003. 301 * The aggregate is named bool_or, because ANY/SOME have parsing conflicts. 302 * 303 * Note: this is only used in plain aggregate mode, not moving-aggregate mode. 304 */ 305 Datum 306 boolor_statefunc(PG_FUNCTION_ARGS) 307 { 308 PG_RETURN_BOOL(PG_GETARG_BOOL(0) || PG_GETARG_BOOL(1)); 309 } 310 311 typedef struct BoolAggState 312 { 313 int64 aggcount; /* number of non-null values aggregated */ 314 int64 aggtrue; /* number of values aggregated that are true */ 315 } BoolAggState; 316 317 static BoolAggState * 318 makeBoolAggState(FunctionCallInfo fcinfo) 319 { 320 BoolAggState *state; 321 MemoryContext agg_context; 322 323 if (!AggCheckCallContext(fcinfo, &agg_context)) 324 elog(ERROR, "aggregate function called in non-aggregate context"); 325 326 state = (BoolAggState *) MemoryContextAlloc(agg_context, 327 sizeof(BoolAggState)); 328 state->aggcount = 0; 329 state->aggtrue = 0; 330 331 return state; 332 } 333 334 Datum 335 bool_accum(PG_FUNCTION_ARGS) 336 { 337 BoolAggState *state; 338 339 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); 340 341 /* Create the state data on first call */ 342 if (state == NULL) 343 state = makeBoolAggState(fcinfo); 344 345 if (!PG_ARGISNULL(1)) 346 { 347 state->aggcount++; 348 if (PG_GETARG_BOOL(1)) 349 state->aggtrue++; 350 } 351 352 PG_RETURN_POINTER(state); 353 } 354 355 Datum 356 bool_accum_inv(PG_FUNCTION_ARGS) 357 { 358 BoolAggState *state; 359 360 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); 361 362 /* bool_accum should have created the state data */ 363 if (state == NULL) 364 elog(ERROR, "bool_accum_inv called with NULL state"); 365 366 if (!PG_ARGISNULL(1)) 367 { 368 state->aggcount--; 369 if (PG_GETARG_BOOL(1)) 370 state->aggtrue--; 371 } 372 373 PG_RETURN_POINTER(state); 374 } 375 376 Datum 377 bool_alltrue(PG_FUNCTION_ARGS) 378 { 379 BoolAggState *state; 380 381 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); 382 383 /* if there were no non-null values, return NULL */ 384 if (state == NULL || state->aggcount == 0) 385 PG_RETURN_NULL(); 386 387 /* true if all non-null values are true */ 388 PG_RETURN_BOOL(state->aggtrue == state->aggcount); 389 } 390 391 Datum 392 bool_anytrue(PG_FUNCTION_ARGS) 393 { 394 BoolAggState *state; 395 396 state = PG_ARGISNULL(0) ? NULL : (BoolAggState *) PG_GETARG_POINTER(0); 397 398 /* if there were no non-null values, return NULL */ 399 if (state == NULL || state->aggcount == 0) 400 PG_RETURN_NULL(); 401 402 /* true if any non-null value is true */ 403 PG_RETURN_BOOL(state->aggtrue > 0); 404 } 405