/* * Walker function to find a function call which is supposed to write * database. */ static bool function_call_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, FuncCall)) { FuncCall *fcall = (FuncCall *)node; char *fname; int length = list_length(fcall->funcname); if (length > 0) { if (length == 1) /* no schema qualification? */ { fname = strVal(linitial(fcall->funcname)); } else { fname = strVal(lsecond(fcall->funcname)); /* with schema qualification */ } pool_debug("function_call_walker: function name: %s", fname); /* * Check white list if any. */ if (pool_config->num_white_function_list > 0) { /* Search function in the white list regex patterns */ if (pattern_compare(fname, WHITELIST, "white_function_list") == 1) { /* If the function is found in the white list, we can ignore it */ return raw_expression_tree_walker(node, function_call_walker, context); } /* * Since the function was not found in white list, we * have found a writing function. */ ctx->has_function_call = true; return false; } /* * Check black list if any. */ if (pool_config->num_black_function_list > 0) { /* Search function in the black list regex patterns */ if (pattern_compare(fname, BLACKLIST, "black_function_list") == 1) { /* Found. */ ctx->has_function_call = true; return false; } } } } return raw_expression_tree_walker(node, function_call_walker, context); }
/* * Walker function to find a view */ static bool view_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; char *relname; if (node == NULL) return false; if (IsA(node, RangeVar)) { RangeVar *rgv = (RangeVar *) node; relname = make_table_name_from_rangevar(rgv); ereport(DEBUG1, (errmsg("view walker. checking relation \"%s\"", relname))); if (is_view(relname)) { ctx->has_view = true; return false; } } return raw_expression_tree_walker(node, view_walker, context); }
static bool const_record_walker(Node *node, pgssConstLocations *jstate) { bool result; if (node == NULL) return false; if (IsA(node, A_Const)) { RecordConstLocation(jstate, castNode(A_Const, node)->location); } else if (IsA(node, ParamRef)) { /* Track the highest ParamRef number */ if (((ParamRef *) node)->number > jstate->highest_extern_param_id) jstate->highest_extern_param_id = castNode(ParamRef, node)->number; } else if (IsA(node, DefElem)) { return const_record_walker((Node *) ((DefElem *) node)->arg, jstate); } else if (IsA(node, RawStmt)) { return const_record_walker((Node *) ((RawStmt *) node)->stmt, jstate); } else if (IsA(node, VariableSetStmt)) { return const_record_walker((Node *) ((VariableSetStmt *) node)->args, jstate); } else if (IsA(node, CopyStmt)) { return const_record_walker((Node *) ((CopyStmt *) node)->query, jstate); } else if (IsA(node, ExplainStmt)) { return const_record_walker((Node *) ((ExplainStmt *) node)->query, jstate); } else if (IsA(node, AlterRoleStmt)) { return const_record_walker((Node *) ((AlterRoleStmt *) node)->options, jstate); } else if (IsA(node, DeclareCursorStmt)) { return const_record_walker((Node *) ((DeclareCursorStmt *) node)->query, jstate); } PG_TRY(); { result = raw_expression_tree_walker(node, const_record_walker, (void*) jstate); } PG_CATCH(); { FlushErrorState(); result = false; } PG_END_TRY(); return result; }
/* * Walker function to find non immutable function call. */ static bool non_immutable_function_call_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, FuncCall)) { FuncCall *fcall = (FuncCall *) node; char *fname; int length = list_length(fcall->funcname); if (length > 0) { if (length == 1) /* no schema qualification? */ { fname = strVal(linitial(fcall->funcname)); } else { fname = strVal(lsecond(fcall->funcname)); /* with schema * qualification */ } ereport(DEBUG1, (errmsg("non immutable function walker. checking function \"%s\"", fname))); /* Check system catalog if the function is immutable */ if (is_immutable_function(fname) == false) { /* Non immutable function call found */ ctx->has_non_immutable_function_call = true; return false; } } } else if (IsA(node, TypeCast)) { /* CURRENT_DATE, CURRENT_TIME, LOCALTIMESTAMP, LOCALTIME etc. */ TypeCast *tc = (TypeCast *) node; if ((isSystemType((Node *) tc->typeName, "date") || isSystemType((Node *) tc->typeName, "timestamp") || isSystemType((Node *) tc->typeName, "timestamptz") || isSystemType((Node *) tc->typeName, "time") || isSystemType((Node *) tc->typeName, "timetz"))) { ctx->has_non_immutable_function_call = true; return false; } } return raw_expression_tree_walker(node, non_immutable_function_call_walker, context); }
/* * Extract table oids from SELECT statement. Returns number of oids. * Oids are returned as an int array. The contents of oid array are * discarded by next call to this function. */ int pool_extract_table_oids_from_select_stmt(Node *node, SelectContext *ctx) { if (!IsA(node, SelectStmt)) return 0; ctx->num_oids = 0; raw_expression_tree_walker(node, select_table_walker, ctx); return ctx->num_oids; }
static bool const_record_walker(Node *node, pgssConstLocations *jstate) { bool result; if (node == NULL) return false; if ((IsA(node, A_Const) && ((A_Const *) node)->location >= 0) || (IsA(node, DefElem) && ((DefElem *) node)->location >= 0)) { /* enlarge array if needed */ if (jstate->clocations_count >= jstate->clocations_buf_size) { jstate->clocations_buf_size *= 2; jstate->clocations = (pgssLocationLen *) repalloc(jstate->clocations, jstate->clocations_buf_size * sizeof(pgssLocationLen)); } jstate->clocations[jstate->clocations_count].location = IsA(node, DefElem) ? ((DefElem *) node)->location : ((A_Const *) node)->location; /* initialize lengths to -1 to simplify fill_in_constant_lengths */ jstate->clocations[jstate->clocations_count].length = -1; jstate->clocations_count++; } else if (IsA(node, VariableSetStmt)) { return const_record_walker((Node *) ((VariableSetStmt *) node)->args, jstate); } else if (IsA(node, CopyStmt)) { return const_record_walker((Node *) ((CopyStmt *) node)->query, jstate); } else if (IsA(node, ExplainStmt)) { return const_record_walker((Node *) ((ExplainStmt *) node)->query, jstate); } else if (IsA(node, AlterRoleStmt)) { return const_record_walker((Node *) ((AlterRoleStmt *) node)->options, jstate); } PG_TRY(); { result = raw_expression_tree_walker(node, const_record_walker, (void*) jstate); } PG_CATCH(); { FlushErrorState(); result = false; } PG_END_TRY(); return result; }
/* * Return true if this SELECT has function calls *and* supposed to * modify database. We check black/white function list to determine * whether the function modifies database. */ bool pool_has_function_call(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_function_call = false; raw_expression_tree_walker(node, function_call_walker, &ctx); return ctx.has_function_call; }
/* * Return true if this SELECT has temporary table. */ bool pool_has_temp_table(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_temp_table = false; raw_expression_tree_walker(node, temp_table_walker, &ctx); return ctx.has_temp_table; }
/* * Return true if this SELECT has a view. */ bool pool_has_view(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_view = false; raw_expression_tree_walker(node, view_walker, &ctx); return ctx.has_view; }
/* * Return true if this SELECT has non immutable function calls. */ bool pool_has_non_immutable_function_call(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_non_immutable_function_call = false; raw_expression_tree_walker(node, non_immutable_function_call_walker, &ctx); pool_debug("pool_has_non_immutable_function_call: %d", ctx.has_non_immutable_function_call); return ctx.has_non_immutable_function_call; }
/* * Walker function to find intoClause or lockingClause. */ static bool insertinto_or_locking_clause_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, IntoClause) || IsA(node, LockingClause)) { ctx->has_insertinto_or_locking_clause = true; return false; } return raw_expression_tree_walker(node, insertinto_or_locking_clause_walker, ctx); }
/* * Return true if this SELECT has system catalog table. */ bool pool_has_system_catalog(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_system_catalog = false; raw_expression_tree_walker(node, system_catalog_walker, &ctx); return ctx.has_system_catalog; }
static bool relation_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, RangeVar)) { ctx->has_temp_table = true; return false; } return raw_expression_tree_walker(node, relation_walker, context); }
/* * Search the pg_terminate_backend() call in the query */ int pool_get_terminate_backend_pid(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_function_call = false; ctx.pg_terminate_backend_pid = 0; raw_expression_tree_walker(node, function_call_walker, &ctx); return ctx.pg_terminate_backend_pid; }
/* * Return true if this SELECT has INSERT INTO or FOR SHARE or FOR UPDATE. */ bool pool_has_insertinto_or_locking_clause(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_insertinto_or_locking_clause = false; raw_expression_tree_walker(node, insertinto_or_locking_clause_walker, &ctx); pool_debug("pool_has_insertinto_or_locking_clause: returns %d", ctx.has_insertinto_or_locking_clause); return ctx.has_insertinto_or_locking_clause; }
/* * Return true if this SELECT has INSERT INTO or FOR SHARE or FOR UPDATE. */ bool pool_has_insertinto_or_locking_clause(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_insertinto_or_locking_clause = false; raw_expression_tree_walker(node, insertinto_or_locking_clause_walker, &ctx); ereport(DEBUG1, (errmsg("checking if query has INSERT INTO, FOR SHARE or FOR UPDATE"), errdetail("result = %d", ctx.has_insertinto_or_locking_clause))); return ctx.has_insertinto_or_locking_clause; }
/* * Return true if this SELECT has non immutable function calls. */ bool pool_has_non_immutable_function_call(Node *node) { SelectContext ctx; if (!IsA(node, SelectStmt)) return false; ctx.has_non_immutable_function_call = false; raw_expression_tree_walker(node, non_immutable_function_call_walker, &ctx); ereport(DEBUG1, (errmsg("checking if SELECT statement contains the IMMUTABLE function call"), errdetail("result = %d", ctx.has_non_immutable_function_call))); return ctx.has_non_immutable_function_call; }
/* * Walker function to extract table oids from SELECT statement. */ static bool select_table_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; int num_oids; if (node == NULL) return false; if (IsA(node, RangeVar)) { RangeVar *rgv = (RangeVar *) node; char *table; int oid; table = make_table_name_from_rangevar(rgv); oid = pool_table_name_to_oid(table); if (oid) { if (POOL_MAX_SELECT_OIDS <= ctx->num_oids) { ereport(DEBUG1, (errmsg("extracting table oids from SELECT statement"), errdetail("number of oids = %d exceeds the maximum limit = %d", ctx->num_oids, POOL_MAX_SELECT_OIDS))); return false; } num_oids = ctx->num_oids++; ctx->table_oids[num_oids] = oid; strlcpy(ctx->table_names[num_oids], table, POOL_NAMEDATALEN); ereport(DEBUG1, (errmsg("extracting table oids from SELECT statement"), errdetail("ctx->table_names[%d] = \"%s\"", num_oids, ctx->table_names[num_oids]))); } } return raw_expression_tree_walker(node, select_table_walker, context); }
/* * Walker function to extract table oids from SELECT statement. */ static bool select_table_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; int num_oids; if (node == NULL) return false; if (IsA(node, RangeVar)) { RangeVar *rgv = (RangeVar *)node; char *table; int oid; char *s; table = make_table_name_from_rangevar(rgv); oid = pool_table_name_to_oid(table); if (oid) { if (POOL_MAX_SELECT_OIDS <= ctx->num_oids) { pool_debug("select_table_walker: number of oids exceeds"); return false; } num_oids = ctx->num_oids++; ctx->table_oids[num_oids] = oid; s = strip_quote(table); strlcpy(ctx->table_names[num_oids], s, POOL_NAMEDATALEN); free(s); pool_debug("select_table_walker: ctx->table_names[%d] = %s", num_oids, ctx->table_names[num_oids]); } } return raw_expression_tree_walker(node, select_table_walker, context); }
/* * Walker function to find a temp table */ static bool temp_table_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, RangeVar)) { RangeVar *rgv = (RangeVar *)node; pool_debug("temp_table_walker: relname: %s", rgv->relname); if (is_temp_table(rgv->relname)) { ctx->has_temp_table = true; return false; } } return raw_expression_tree_walker(node, temp_table_walker, context); }
/* * Walker function to find a view */ static bool view_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; char *relname; if (node == NULL) return false; if (IsA(node, RangeVar)) { RangeVar *rgv = (RangeVar *)node; relname = make_table_name_from_rangevar(rgv); pool_debug("view_walker: relname: %s", relname); if (is_view(relname)) { ctx->has_view = true; return false; } } return raw_expression_tree_walker(node, view_walker, context); }
/* * Walker function to find a system catalog */ static bool system_catalog_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, RangeVar)) { RangeVar *rgv = (RangeVar *) node; ereport(DEBUG1, (errmsg("system catalog walker, checking relation \"%s\"", rgv->relname))); if (is_system_catalog(rgv->relname)) { ctx->has_system_catalog = true; return false; } } return raw_expression_tree_walker(node, system_catalog_walker, context); }
/* * Walker function to find a temp table */ static bool temp_table_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, RangeVar)) { RangeVar *rgv = (RangeVar *) node; ereport(DEBUG1, (errmsg("temporary table walker. checking relation \"%s\"", rgv->relname))); if (is_temp_table(rgv->relname)) { ctx->has_temp_table = true; return false; } } return raw_expression_tree_walker(node, temp_table_walker, context); }
/* * Walker function to find a function call which is supposed to write * database. */ static bool function_call_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, FuncCall)) { FuncCall *fcall = (FuncCall *) node; char *fname; int length = list_length(fcall->funcname); if (length > 0) { if (length == 1) /* no schema qualification? */ { fname = strVal(linitial(fcall->funcname)); } else { fname = strVal(lsecond(fcall->funcname)); /* with schema * qualification */ } ereport(DEBUG1, (errmsg("function call walker, function name: \"%s\"", fname))); if (ctx->pg_terminate_backend_pid == 0 && strcmp("pg_terminate_backend", fname) == 0) { if (list_length(fcall->args) == 1) { Node *arg = linitial(fcall->args); if (IsA(arg, A_Const) && ((A_Const *) arg)->val.type == T_Integer) { ctx->pg_terminate_backend_pid = ((A_Const *) arg)->val.val.ival; ereport(DEBUG1, (errmsg("pg_terminate_backend pid = %d", ctx->pg_terminate_backend_pid))); } } } /* * Check white list if any. */ if (pool_config->num_white_function_list > 0) { /* Search function in the white list regex patterns */ if (pattern_compare(fname, WHITELIST, "white_function_list") == 1) { /* * If the function is found in the white list, we can * ignore it */ return raw_expression_tree_walker(node, function_call_walker, context); } /* * Since the function was not found in white list, we have * found a writing function. */ ctx->has_function_call = true; return false; } /* * Check black list if any. */ if (pool_config->num_black_function_list > 0) { /* Search function in the black list regex patterns */ if (pattern_compare(fname, BLACKLIST, "black_function_list") == 1) { /* Found. */ ctx->has_function_call = true; return false; } } } } return raw_expression_tree_walker(node, function_call_walker, context); }