/*-snippet
{
  "body": [
    "PERFORM ax_utils.raise_error('${1:Enter your error message here.}', '${2:UNDEF}');"
  ],
  "description": [
    "Raises an error with specified message, code, and optional placeholder parameter(s) for the message.",
    "Code must be an exactly 5-character value (letters or numbers), as per PostgreSQL convention.",
    "If you want to use custom code values, consult PostgreSQL documentation for a list of existing error codes to prevent collisions:",
    "https://www.postgresql.org/docs/13/errcodes-appendix.html\n",
    "'PERFORM' is used because usually, you would want to throw an error inside of the function or condition block.",
    "If you just want to throw an error in the migration file (e.g. to test this snippet) - replace 'PERFORM' with 'SELECT'.\n",
    "Examples:",
    "ax_utils.raise_error('Sample error message without parameters', 'NPERR');",
    "ax_utils.raise_error('Sample error %s with one parameters', 'OPERR', 'message');",
    "ax_utils.raise_error('Sample error %s with %s parameters', 'TPERR', 'message', 'two');"
   ]
}
snippet-*/
CREATE OR REPLACE FUNCTION ax_utils.raise_error(
  error_message text,
  error_code text,
  VARIADIC placeholder_values text[] DEFAULT '{}'
) RETURNS void
  LANGUAGE plpgsql
  AS $$
BEGIN
  RAISE EXCEPTION '%', format(error_message, VARIADIC placeholder_values) using errcode = error_code;
END;
$$;

/*-snippet
{
  "body": [
    "PERFORM ax_utils.validate_identifier_length('${1:identifier}');"
  ],
  "description": [
    "Raises an exception if the provided identifer exceeds the PostgreSQL max length (63 bytes).",
    "This can be useful to prevent name truncation, identifier collisions and silently dropped constraints.",
    "If called from a function, the calling function will be referenced in the error message.",
    "An optional second 'hint' parameter can be provided which will be appended to the error message."
   ]
}
snippet-*/
CREATE OR REPLACE FUNCTION ax_utils.validate_identifier_length(identifier text, hint text default '') RETURNS void
    LANGUAGE plpgsql
    AS $$
DECLARE
  stack text; fcesig text; callinfo text;
BEGIN
  IF LENGTH(identifier) > 63 THEN
    -- get sig of calling function
    GET DIAGNOSTICS stack = PG_CONTEXT;
    fcesig := substring(substring(stack from 'function (.*)') from 'function (.*?) line');
    callinfo := CASE WHEN fcesig IS NULL THEN '' ELSE 'Long identifier in ' || fcesig::regprocedure::text || '. ' END;
    perform ax_utils.raise_error('%sIdentifier "%s" exceeds 63 bytes. %s', 'SETUP', callinfo, identifier, hint);
  END IF;
END;
$$;