Datum dabs_int_lexize(PG_FUNCTION_ARGS) { char *in = (char *) PG_GETARG_POINTER(1); char *out = pnstrdup(in, PG_GETARG_INT32(2)); char *start; char *end; TSLexeme *res = palloc0(sizeof(TSLexeme) * 2); res[1].lexeme = NULL; while (*out && t_iseq(out, '-')) out += pg_mblen(out); start = out; while (*out) out += pg_mblen(out); end = out; out = pnstrdup(start, end - start); res[0].lexeme = out; PG_RETURN_POINTER(res); }
Datum hstore_to_plperl(PG_FUNCTION_ARGS) { HStore *in = PG_GETARG_HS(0); int i; int count = HS_COUNT(in); char *base = STRPTR(in); HEntry *entries = ARRPTR(in); HV *hv; hv = newHV(); for (i = 0; i < count; i++) { const char *key; SV *value; key = pnstrdup(HS_KEY(entries, base, i), HS_KEYLEN(entries, i)); value = HS_VALISNULL(entries, i) ? newSV(0) : cstr2sv(pnstrdup(HS_VAL(entries, base, i), HS_VALLEN(entries, i))); (void) hv_store(hv, key, strlen(key), value, 0); } return PointerGetDatum(newRV((SV *) hv)); }
static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal) { switch (scalarVal->type) { case jbvNull: appendBinaryStringInfo(out, "null", 4); break; case jbvString: escape_json(out, pnstrdup(scalarVal->val.string.val, scalarVal->val.string.len)); break; case jbvNumeric: appendStringInfoString(out, DatumGetCString(DirectFunctionCall1(numeric_out, PointerGetDatum(scalarVal->val.numeric)))); break; case jbvBool: if (scalarVal->val.boolean) appendBinaryStringInfo(out, "true", 4); else appendBinaryStringInfo(out, "false", 5); break; default: elog(ERROR, "unknown jsonb scalar type"); } }
/* * Read the next line from a tsearch data file (expected to be in UTF-8), and * convert it to database encoding if needed. The returned string is palloc'd. * NULL return means EOF. * * Note: direct use of this function is now deprecated. Go through * tsearch_readline() to provide better error reporting. */ char * t_readline(FILE *fp) { int len; char *recoded; char buf[4096]; /* lines must not be longer than this */ if (fgets(buf, sizeof(buf), fp) == NULL) return NULL; len = strlen(buf); /* Make sure the input is valid UTF-8 */ (void) pg_verify_mbstr(PG_UTF8, buf, len, false); /* And convert */ recoded = pg_any_to_server(buf, len, PG_UTF8); if (recoded == buf) { /* * conversion didn't pstrdup, so we must. We can use the length of the * original string, because no conversion was done. */ recoded = pnstrdup(recoded, len); } return recoded; }
Datum hstore_to_jsonb(PG_FUNCTION_ARGS) { HStore *in = PG_GETARG_HS(0); int i; int count = HS_COUNT(in); char *base = STRPTR(in); HEntry *entries = ARRPTR(in); JsonbParseState *state = NULL; JsonbValue *res; res = pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL); for (i = 0; i < count; i++) { JsonbValue key, val; key.estSize = sizeof(JEntry); key.type = jbvString; key.val.string.len = HS_KEYLEN(entries, i); key.val.string.val = pnstrdup(HS_KEY(entries, base, i), key.val.string.len); key.estSize += key.val.string.len; res = pushJsonbValue(&state, WJB_KEY, &key); if (HS_VALISNULL(entries, i)) { val.estSize = sizeof(JEntry); val.type = jbvNull; } else { val.estSize = sizeof(JEntry); val.type = jbvString; val.val.string.len = HS_VALLEN(entries, i); val.val.string.val = pnstrdup(HS_VAL(entries, base, i), val.val.string.len); val.estSize += val.val.string.len; } res = pushJsonbValue(&state, WJB_VALUE, &val); } res = pushJsonbValue(&state, WJB_END_OBJECT, NULL); PG_RETURN_POINTER(JsonbValueToJsonb(res)); }
static void read_dictionary(DictSyn *d, char *filename) { char *real_filename = get_tsearch_config_filename(filename, "rules"); tsearch_readline_state trst; char *line; int cur = 0; if (!tsearch_readline_begin(&trst, real_filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open synonym file \"%s\": %m", real_filename))); while ((line = tsearch_readline(&trst)) != NULL) { char *value; char *key; char *end = NULL; if (*line == '\0') continue; value = lowerstr(line); pfree(line); key = find_word(value, &end); if (!key) { pfree(value); continue; } if (cur == d->len) { d->len = (d->len > 0) ? 2 * d->len : 16; if (d->syn) d->syn = (Syn *) repalloc(d->syn, sizeof(Syn) * d->len); else d->syn = (Syn *) palloc(sizeof(Syn) * d->len); } d->syn[cur].key = pnstrdup(key, end - key); d->syn[cur].value = value; cur++; } tsearch_readline_end(&trst); d->len = cur; if (cur > 1) qsort(d->syn, d->len, sizeof(Syn), compare_syn); pfree(real_filename); }
Datum fmcs_smiles(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); char *params = PG_GETARG_CSTRING(1); // elog(WARNING, str); str = findMCSsmiles(str, params); // elog(WARNING, str); Assert(str != 0); PG_RETURN_CSTRING(pnstrdup(str, strlen(str))); }
/* * Make copy of string with all trailing newline characters removed. */ char * pchomp(const char *in) { size_t n; n = strlen(in); while (n > 0 && in[n - 1] == '\n') n--; return pnstrdup(in, n); }
Datum mol_hash(PG_FUNCTION_ARGS) { CROMol mol; char *str; int len; fcinfo->flinfo->fn_extra = searchMolCache(fcinfo->flinfo->fn_extra, fcinfo->flinfo->fn_mcxt, PG_GETARG_DATUM(0), NULL, &mol, NULL); Assert(mol != 0); str = computeMolHash(mol, &len); Assert(str != 0 && strlen(str) != 0); PG_RETURN_CSTRING(pnstrdup(str, len)); }
Datum mol_inchikey(PG_FUNCTION_ARGS) { CROMol mol; const char *str; char *res, *opts = PG_GETARG_CSTRING(1); fcinfo->flinfo->fn_extra = searchMolCache(fcinfo->flinfo->fn_extra, fcinfo->flinfo->fn_mcxt, PG_GETARG_DATUM(0), NULL, &mol, NULL); str = MolInchiKey(mol, opts); res = pnstrdup(str, strlen(str)); free((void *)str); PG_RETURN_CSTRING(res); }
static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull) { JsonbInState *_state = (JsonbInState *) pstate; JsonbValue v; Assert(fname != NULL); v.type = jbvString; v.val.string.len = checkStringLen(strlen(fname)); v.val.string.val = pnstrdup(fname, v.val.string.len); v.estSize = sizeof(JEntry) + v.val.string.len; _state->res = pushJsonbValue(&_state->parseState, WJB_KEY, &v); }
Datum mol_formula(PG_FUNCTION_ARGS) { CROMol mol; char *str; int len; bool separateIsotopes = PG_GETARG_BOOL(1); bool abbreviateHIsotopes = PG_GETARG_BOOL(2); fcinfo->flinfo->fn_extra = searchMolCache(fcinfo->flinfo->fn_extra, fcinfo->flinfo->fn_mcxt, PG_GETARG_DATUM(0), NULL, &mol, NULL); str = makeMolFormulaText(mol, &len, separateIsotopes, abbreviateHIsotopes); PG_RETURN_CSTRING(pnstrdup(str, len)); }
Datum spell_lexize(PG_FUNCTION_ARGS) { DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0); char *in = (char *) PG_GETARG_POINTER(1); char *txt; char **res; char **ptr, **cptr; if (!PG_GETARG_INT32(2)) PG_RETURN_POINTER(NULL); res = palloc(sizeof(char *) * 2); txt = pnstrdup(in, PG_GETARG_INT32(2)); res = NINormalizeWord(&(d->obj), txt); pfree(txt); if (res == NULL) PG_RETURN_POINTER(NULL); ptr = cptr = res; while (*ptr) { if (searchstoplist(&(d->stoplist), *ptr)) { pfree(*ptr); *ptr = NULL; ptr++; } else { *cptr = *ptr; cptr++; ptr++; } } *cptr = NULL; PG_RETURN_POINTER(res); }
/* * Get the given source line as a palloc'd string */ static char * get_source_line(const char *src, int lineno) { const char *s = NULL; const char *next = src; int current = 0; /* sanity check */ if (lineno <= 0) return NULL; while (current < lineno) { s = next; next = strchr(s + 1, '\n'); current++; if (next == NULL) break; } if (current != lineno) return NULL; while (*s && isspace((unsigned char) *s)) s++; if (next == NULL) return pstrdup(s); /* * Sanity check, next < s if the line was all-whitespace, which should * never happen if Python reported a frame created on that line, but check * anyway. */ if (next < s) return NULL; return pnstrdup(s, next - s); }
/* * Replaces first occurrence of replace in string with replacement. * Caller is responsible for releasing memory allocated for result. * */ char* replace_string(const char* string, const char* replace, const char* replacement) { char* replaced = NULL; char* start = strstr(string, replace); if (start) { char* before_token = pnstrdup(string, start - string); char* after_token = pstrdup(string + (start - string) + strlen(replace)); replaced = palloc0(strlen(before_token) + strlen(replacement) + strlen(after_token) + 1); sprintf(replaced, "%s%s%s", before_token, replacement, after_token); //release memory pfree(before_token); pfree(after_token); } else { replaced = palloc0(strlen(string) + 1); sprintf(replaced, "%s", string); } return replaced; }
/* * Translates the Namenode structure to a NNHAConf structure * Input Namenode: * rpc_addr: mdw:9000 * http_addr: mdw:50070 */ static void set_one_namenode(NNHAConf *conf, int idx, Namenode *source) { char *portstart; int hostlen; validate_string(source->rpc_addr, "In configuration Namenode.rpc_address number %d is null or empty", idx + 1); portstart = strchr(source->rpc_addr, ':'); if (!portstart) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("dfs.namenode.rpc-address was set incorrectly in the configuration. ':' missing"))); hostlen = portstart - source->rpc_addr; portstart++; conf->nodes[idx] = pnstrdup(source->rpc_addr, hostlen); conf->rpcports[idx] = pstrdup(portstart); /* * we override the ha rest post from hdfs-site.xml, with pxf_service_port */ port_to_str(&(conf->restports[idx]), pxf_service_port); }
/* * char2wchar --- convert multibyte characters to wide characters * * This has almost the API of mbstowcs_l(), except that *from need not be * null-terminated; instead, the number of input bytes is specified as * fromlen. Also, we ereport() rather than returning -1 for invalid * input encoding. tolen is the maximum number of wchar_t's to store at *to. * The output will be zero-terminated iff there is room. */ size_t char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen, pg_locale_t locale) { size_t result; if (tolen == 0) return 0; #ifdef WIN32 /* See WIN32 "Unicode" comment above */ if (GetDatabaseEncoding() == PG_UTF8) { /* Win32 API does not work for zero-length input */ if (fromlen == 0) result = 0; else { result = MultiByteToWideChar(CP_UTF8, 0, from, fromlen, to, tolen - 1); /* A zero return is failure */ if (result == 0) result = -1; } if (result != -1) { Assert(result < tolen); /* Append trailing null wchar (MultiByteToWideChar() does not) */ to[result] = 0; } } else #endif /* WIN32 */ { /* mbstowcs requires ending '\0' */ char *str = pnstrdup(from, fromlen); if (locale == (pg_locale_t) 0) { /* Use mbstowcs directly for the default locale */ result = mbstowcs(to, str, tolen); } else { #ifdef HAVE_LOCALE_T #ifdef HAVE_MBSTOWCS_L /* Use mbstowcs_l for nondefault locales */ result = mbstowcs_l(to, str, tolen, locale); #else /* !HAVE_MBSTOWCS_L */ /* We have to temporarily set the locale as current ... ugh */ locale_t save_locale = uselocale(locale); result = mbstowcs(to, str, tolen); uselocale(save_locale); #endif /* HAVE_MBSTOWCS_L */ #else /* !HAVE_LOCALE_T */ /* Can't have locale != 0 without HAVE_LOCALE_T */ elog(ERROR, "mbstowcs_l is not available"); result = 0; /* keep compiler quiet */ #endif /* HAVE_LOCALE_T */ } pfree(str); } if (result == -1) { /* * Invalid multibyte character encountered. We try to give a useful * error message by letting pg_verifymbstr check the string. But it's * possible that the string is OK to us, and not OK to mbstowcs --- * this suggests that the LC_CTYPE locale is different from the * database encoding. Give a generic error message if verifymbstr * can't find anything wrong. */ pg_verifymbstr(from, fromlen, false); /* might not return */ /* but if it does ... */ ereport(ERROR, (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), errmsg("invalid multibyte character for locale"), errhint("The server's LC_CTYPE locale is probably incompatible with the database encoding."))); } return result; }
static void read_dictionary(DictSyn *d, char *filename) { char *real_filename = get_tsearch_config_filename(filename, "rules"); tsearch_readline_state trst; char *line; int cur = 0; if (!tsearch_readline_begin(&trst, real_filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open synonym file \"%s\": %m", real_filename))); while ((line = tsearch_readline(&trst)) != NULL) { char *value; char *key; char *pos; char *end; if (*line == '\0') continue; value = lowerstr(line); pfree(line); pos = value; while ((key = find_word(pos, &end)) != NULL) { /* Enlarge syn structure if full */ if (cur == d->len) { d->len = (d->len > 0) ? 2 * d->len : 16; if (d->syn) d->syn = (Syn *) repalloc(d->syn, sizeof(Syn) * d->len); else d->syn = (Syn *) palloc(sizeof(Syn) * d->len); } /* Save first word only if we will match it */ if (pos != value || d->matchorig) { d->syn[cur].key = pnstrdup(key, end - key); d->syn[cur].value = pstrdup(value); cur++; } pos = end; /* Don't bother scanning synonyms if we will not match them */ if (!d->matchsynonyms) break; } pfree(value); } tsearch_readline_end(&trst); d->len = cur; if (cur > 1) qsort(d->syn, d->len, sizeof(Syn), compare_syn); pfree(real_filename); }
Datum hstore_to_jsonb_loose(PG_FUNCTION_ARGS) { HStore *in = PG_GETARG_HS(0); int i; int count = HS_COUNT(in); char *base = STRPTR(in); HEntry *entries = ARRPTR(in); JsonbParseState *state = NULL; JsonbValue *res; StringInfoData tmp; bool is_number; initStringInfo(&tmp); res = pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL); for (i = 0; i < count; i++) { JsonbValue key, val; key.estSize = sizeof(JEntry); key.type = jbvString; key.val.string.len = HS_KEYLEN(entries, i); key.val.string.val = pnstrdup(HS_KEY(entries, base, i), key.val.string.len); key.estSize += key.val.string.len; res = pushJsonbValue(&state, WJB_KEY, &key); val.estSize = sizeof(JEntry); if (HS_VALISNULL(entries, i)) { val.type = jbvNull; } /* guess that values of 't' or 'f' are booleans */ else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 't') { val.type = jbvBool; val.val.boolean = true; } else if (HS_VALLEN(entries, i) == 1 && *(HS_VAL(entries, base, i)) == 'f') { val.type = jbvBool; val.val.boolean = false; } else { is_number = false; resetStringInfo(&tmp); appendBinaryStringInfo(&tmp, HS_VAL(entries, base, i), HS_VALLEN(entries, i)); /* * don't treat something with a leading zero followed by another * digit as numeric - could be a zip code or similar */ if (tmp.len > 0 && !(tmp.data[0] == '0' && isdigit((unsigned char) tmp.data[1])) && strspn(tmp.data, "+-0123456789Ee.") == tmp.len) { /* * might be a number. See if we can input it as a numeric * value. Ignore any actual parsed value. */ char *endptr = "junk"; long lval; lval = strtol(tmp.data, &endptr, 10); (void) lval; if (*endptr == '\0') { /* * strol man page says this means the whole string is * valid */ is_number = true; } else { /* not an int - try a double */ double dval; dval = strtod(tmp.data, &endptr); (void) dval; if (*endptr == '\0') is_number = true; } } if (is_number) { val.type = jbvNumeric; val.val.numeric = DatumGetNumeric( DirectFunctionCall3(numeric_in, CStringGetDatum(tmp.data), 0, -1)); val.estSize += VARSIZE_ANY(val.val.numeric) +sizeof(JEntry); } else { val.estSize = sizeof(JEntry); val.type = jbvString; val.val.string.len = HS_VALLEN(entries, i); val.val.string.val = pnstrdup(HS_VAL(entries, base, i), val.val.string.len); val.estSize += val.val.string.len; } } res = pushJsonbValue(&state, WJB_VALUE, &val); } res = pushJsonbValue(&state, WJB_END_OBJECT, NULL); PG_RETURN_POINTER(JsonbValueToJsonb(res)); }
/* * Extracts the error message from the full HTTP response * We test for several conditions in the http_ret_code and the HTTP response message. * The first condition that matches, defines the final message string and ends the function. * The layout of the HTTP response message is: <html> <head> <meta meta_data_attributes /> <title> title_content_which_has_a_brief_description_of_the_error </title> </head> <body> <h2> heading_containing_the_error_code </h2> <p> main_body_paragraph_with_a_detailed_description_of_the_error_on_the_rest_server_side <pre> the_error_in_original_format_not_HTML_ususally_the_title_of_the_java_exception</pre> </p> <h3>Caused by:</h3> <pre> the_full_java_exception_with_the_stack_output </pre> <hr /><i><small>Powered by Jetty://</small></i> <br/> <br/> </body> </html> * Our first priority is to get the paragraph <p> inside <body>, and in case we don't find it, then we try to get * the <title>. */ char* get_http_error_msg(long http_ret_code, char* msg, char* curl_error_buffer) { char *start, *end, *ret; StringInfoData errMsg; initStringInfo(&errMsg); /* * 1. The server not listening on the port specified in the <create external...> statement" * In this case there is no Response from the server, so we issue our own message */ if (http_ret_code == 0) { if (curl_error_buffer == NULL) return "There is no pxf servlet listening on the host and port specified in the external table url"; else { return curl_error_buffer; } } /* * 2. There is a response from the server since the http_ret_code is not 0, but there is no response message. * This is an abnormal situation that could be the result of a bug, libraries incompatibility or versioning issue * in the Rest server or our curl client. In this case we again issue our own message. */ if (!msg || (msg && strlen(msg) == 0) ) { appendStringInfo(&errMsg, "HTTP status code is %ld but HTTP response string is empty", http_ret_code); ret = pstrdup(errMsg.data); pfree(errMsg.data); return ret; } /* * 3. The "normal" case - There is an HTTP response and the response has a <body> section inside where * there is a paragraph contained by the <p> tag. */ start = strstr(msg, "<body>"); if (start != NULL) { start = strstr(start, "<p>"); if (start != NULL) { char *tmp; bool skip = false; start += 3; end = strstr(start, "</p>"); /* assuming where is a <p>, there is a </p> */ if (end != NULL) { /* Take one more line after the </p> */ tmp = strchr(end, '\n'); if (tmp != NULL) end = tmp; tmp = start; /* * Right now we have the full paragraph inside the <body>. We need to extract from it * the <pre> tags, the '\n' and the '\r'. */ while (tmp != end) { if (*tmp == '>') /* skipping the <pre> tags */ skip = false; else if (*tmp == '<') /* skipping the <pre> tags */ { skip = true; appendStringInfoChar(&errMsg, ' '); } else if (*tmp != '\n' && *tmp != '\r' && skip == false) appendStringInfoChar(&errMsg, *tmp); tmp++; } ret = pstrdup(errMsg.data); pfree(errMsg.data); return ret; } } } /* * 4. We did not find the <body>. So we try to print the <title>. */ start = strstr(msg, "<title>"); if (start != NULL) { start += 7; /* no need to check if end is null, if <title> exists then also </title> exists */ end = strstr(start, "</title>"); if (end != NULL) { ret = pnstrdup(start, end - start); return ret; } } /* * 5. This is an unexpected situation. We received an error message from the server but it does not have neither a <body> * nor a <title>. In this case we return the error message we received as-is. */ return msg; }
/* * For jsonb we always want the de-escaped value - that's what's in token */ static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype) { JsonbInState *_state = (JsonbInState *) pstate; JsonbValue v; v.estSize = sizeof(JEntry); switch (tokentype) { case JSON_TOKEN_STRING: Assert(token != NULL); v.type = jbvString; v.val.string.len = checkStringLen(strlen(token)); v.val.string.val = pnstrdup(token, v.val.string.len); v.estSize += v.val.string.len; break; case JSON_TOKEN_NUMBER: /* * No need to check size of numeric values, because maximum * numeric size is well below the JsonbValue restriction */ Assert(token != NULL); v.type = jbvNumeric; v.val.numeric = DatumGetNumeric(DirectFunctionCall3(numeric_in, CStringGetDatum(token), 0, -1)); v.estSize += VARSIZE_ANY(v.val.numeric) +sizeof(JEntry) /* alignment */ ; break; case JSON_TOKEN_TRUE: v.type = jbvBool; v.val.boolean = true; break; case JSON_TOKEN_FALSE: v.type = jbvBool; v.val.boolean = false; break; case JSON_TOKEN_NULL: v.type = jbvNull; break; default: /* should not be possible */ elog(ERROR, "invalid json token type"); break; } if (_state->parseState == NULL) { /* single scalar */ JsonbValue va; va.type = jbvArray; va.val.array.rawScalar = true; va.val.array.nElems = 1; _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, &va); _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v); _state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL); } else { JsonbValue *o = &_state->parseState->contVal; switch (o->type) { case jbvArray: _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v); break; case jbvObject: _state->res = pushJsonbValue(&_state->parseState, WJB_VALUE, &v); break; default: elog(ERROR, "unexpected parent of nested structure"); } } }
/* * char2wchar --- convert multibyte characters to wide characters * * This has almost the API of mbstowcs(), except that *from need not be * null-terminated; instead, the number of input bytes is specified as * fromlen. Also, we ereport() rather than returning -1 for invalid * input encoding. tolen is the maximum number of wchar_t's to store at *to. * The output will be zero-terminated iff there is room. */ size_t char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen) { size_t result; if (tolen == 0) return 0; #ifdef WIN32 /* See WIN32 "Unicode" comment above */ if (GetDatabaseEncoding() == PG_UTF8) { /* Win32 API does not work for zero-length input */ if (fromlen == 0) result = 0; else { result = MultiByteToWideChar(CP_UTF8, 0, from, fromlen, to, tolen - 1); /* A zero return is failure */ if (result == 0) result = -1; } if (result != -1) { Assert(result < tolen); /* Append trailing null wchar (MultiByteToWideChar() does not) */ to[result] = 0; } } else #endif /* WIN32 */ { /* mbstowcs requires ending '\0' */ char *str = pnstrdup(from, fromlen); Assert(!lc_ctype_is_c()); result = mbstowcs(to, str, tolen); pfree(str); } if (result == -1) { /* * Invalid multibyte character encountered. We try to give a useful * error message by letting pg_verifymbstr check the string. But it's * possible that the string is OK to us, and not OK to mbstowcs --- * this suggests that the LC_CTYPE locale is different from the * database encoding. Give a generic error message if verifymbstr * can't find anything wrong. */ pg_verifymbstr(from, fromlen, false); /* might not return */ /* but if it does ... */ ereport(ERROR, (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), errmsg("invalid multibyte character for locale"), errhint("The server's LC_CTYPE locale is probably incompatible with the database encoding."))); } return result; }