---------- * exec_stmt_foreach_a Loop over elements or slices of an array * * When looping over elements, the loop variable is the same type that the * array stores (eg: integer), when looping through slices, the loop variable * is an array of size and dimensions to match the size of the slice. * ---------- */
| 2945 | * ---------- |
| 2946 | */ |
| 2947 | static int |
| 2948 | exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt) |
| 2949 | { |
| 2950 | ArrayType *arr; |
| 2951 | Oid arrtype; |
| 2952 | int32 arrtypmod; |
| 2953 | PLpgSQL_datum *loop_var; |
| 2954 | Oid loop_var_elem_type; |
| 2955 | bool found = false; |
| 2956 | int rc = PLPGSQL_RC_OK; |
| 2957 | MemoryContext stmt_mcontext; |
| 2958 | MemoryContext oldcontext; |
| 2959 | ArrayIterator array_iterator; |
| 2960 | Oid iterator_result_type; |
| 2961 | int32 iterator_result_typmod; |
| 2962 | Datum value; |
| 2963 | bool isnull; |
| 2964 | |
| 2965 | /* get the value of the array expression */ |
| 2966 | value = exec_eval_expr(estate, stmt->expr, &isnull, &arrtype, &arrtypmod); |
| 2967 | if (isnull) |
| 2968 | ereport(ERROR, |
| 2969 | (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), |
| 2970 | errmsg("FOREACH expression must not be null"))); |
| 2971 | |
| 2972 | /* |
| 2973 | * Do as much as possible of the code below in stmt_mcontext, to avoid any |
| 2974 | * leaks from called subroutines. We need a private stmt_mcontext since |
| 2975 | * we'll be calling arbitrary statement code. |
| 2976 | */ |
| 2977 | stmt_mcontext = get_stmt_mcontext(estate); |
| 2978 | push_stmt_mcontext(estate); |
| 2979 | oldcontext = MemoryContextSwitchTo(stmt_mcontext); |
| 2980 | |
| 2981 | /* check the type of the expression - must be an array */ |
| 2982 | if (!OidIsValid(get_element_type(arrtype))) |
| 2983 | ereport(ERROR, |
| 2984 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
| 2985 | errmsg("FOREACH expression must yield an array, not type %s", |
| 2986 | format_type_be(arrtype)))); |
| 2987 | |
| 2988 | /* |
| 2989 | * We must copy the array into stmt_mcontext, else it will disappear in |
| 2990 | * exec_eval_cleanup. This is annoying, but cleanup will certainly happen |
| 2991 | * while running the loop body, so we have little choice. |
| 2992 | */ |
| 2993 | arr = DatumGetArrayTypePCopy(value); |
| 2994 | |
| 2995 | /* Clean up any leftover temporary memory */ |
| 2996 | exec_eval_cleanup(estate); |
| 2997 | |
| 2998 | /* Slice dimension must be less than or equal to array dimension */ |
| 2999 | if (stmt->slice < 0 || stmt->slice > ARR_NDIM(arr)) |
| 3000 | ereport(ERROR, |
| 3001 | (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), |
| 3002 | errmsg("slice dimension (%d) is out of the valid range 0..%d", |
| 3003 | stmt->slice, ARR_NDIM(arr)))); |
| 3004 |
no test coverage detected