/* * Return a strdup'ed string converted from the specified encoding to the * database encoding. */ static char * db_encoding_strdup(int encoding, const char *str) { char *pstr; char *mstr; /* convert the string to the database encoding */ pstr = (char *) pg_do_encoding_conversion( (unsigned char *) str, strlen(str), encoding, GetDatabaseEncoding()); mstr = strdup(pstr); if (pstr != str) pfree(pstr); return mstr; }
Datum xmlnode_in(PG_FUNCTION_ARGS) { pg_enc dbEnc; XMLNodeParserStateData parserState; char *input = PG_GETARG_CSTRING(0); if (strlen(input) == 0) { elog(ERROR, "zero length input string"); } dbEnc = GetDatabaseEncoding(); initXMLParserState(&parserState, input, false); xmlnodeParseNode(&parserState); finalizeXMLParserState(&parserState); PG_RETURN_POINTER(parserState.result); }
/* * On WIN32, strftime() returns the encoding in CP_ACP (the default * operating system codpage for that computer), which is likely different * from SERVER_ENCODING. This is especially important in Japanese versions * of Windows which will use SJIS encoding, which we don't support as a * server encoding. * * So, instead of using strftime(), use wcsftime() to return the value in * wide characters (internally UTF16) and then convert it to the appropriate * database encoding. * * Note that this only affects the calls to strftime() in this file, which are * used to get the locale-aware strings. Other parts of the backend use * pg_strftime(), which isn't locale-aware and does not need to be replaced. */ static size_t strftime_win32(char *dst, size_t dstlen, const char *format, const struct tm * tm) { size_t len; wchar_t wformat[8]; /* formats used below need 3 bytes */ wchar_t wbuf[MAX_L10N_DATA]; /* get a wchar_t version of the format string */ len = MultiByteToWideChar(CP_UTF8, 0, format, -1, wformat, lengthof(wformat)); if (len == 0) elog(ERROR, "could not convert format string from UTF-8: error code %lu", GetLastError()); len = wcsftime(wbuf, MAX_L10N_DATA, wformat, tm); if (len == 0) { /* * strftime failed, possibly because the result would not fit in * MAX_L10N_DATA. Return 0 with the contents of dst unspecified. */ return 0; } len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen - 1, NULL, NULL); if (len == 0) elog(ERROR, "could not convert string to UTF-8: error code %lu", GetLastError()); dst[len] = '\0'; if (GetDatabaseEncoding() != PG_UTF8) { char *convstr = pg_any_to_server(dst, len, PG_UTF8); if (convstr != dst) { strlcpy(dst, convstr, dstlen); len = strlen(dst); pfree(convstr); } } return len; }
/* * Equivalent of X509_NAME_oneline that respects encoding * * This function converts X509_NAME structure to the text variable * converting all textual data into current database encoding. * * Parameter: X509_NAME *name X509_NAME structure to be converted * * Returns: text datum which contains string representation of * X509_NAME */ Datum X509_NAME_to_text(X509_NAME *name) { BIO *membuf = BIO_new(BIO_s_mem()); int i, nid, count = X509_NAME_entry_count(name); X509_NAME_ENTRY *e; ASN1_STRING *v; const char *field_name; size_t size; char nullterm; char *sp; char *dp; text *result; (void) BIO_set_close(membuf, BIO_CLOSE); for (i = 0; i < count; i++) { e = X509_NAME_get_entry(name, i); nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e)); v = X509_NAME_ENTRY_get_data(e); field_name = OBJ_nid2sn(nid); if (!field_name) field_name = OBJ_nid2ln(nid); BIO_printf(membuf, "/%s=", field_name); ASN1_STRING_print_ex(membuf, v, ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB) | ASN1_STRFLGS_UTF8_CONVERT)); } /* ensure null termination of the BIO's content */ nullterm = '\0'; BIO_write(membuf, &nullterm, 1); size = BIO_get_mem_data(membuf, &sp); dp = (char *) pg_do_encoding_conversion((unsigned char *) sp, size - 1, PG_UTF8, GetDatabaseEncoding()); result = cstring_to_text(dp); if (dp != sp) pfree(dp); BIO_free(membuf); PG_RETURN_TEXT_P(result); }
static char * percent_encode(unsigned char *s, int srclen) { unsigned char *end; StringInfoData buf; int len; initStringInfo(&buf); if (srclen < 0) srclen = strlen((char *) s); end = s + srclen; for (; s < end; s += len) { unsigned char *utf; int ulen; len = pg_mblen((const char *) s); if (len == 1) { if (('0' <= s[0] && s[0] <= '9') || ('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z') || (s[0] == '-') || (s[0] == '.') || (s[0] == '_') || (s[0] == '~')) { appendStringInfoChar(&buf, s[0]); continue; } } utf = pg_do_encoding_conversion(s, len, GetDatabaseEncoding(), PG_UTF8); ulen = pg_encoding_mblen(PG_UTF8, (const char *) utf); while(ulen--) { appendStringInfo(&buf, "%%%2X", *utf); utf++; } } return buf.data; }
Datum pg_sasl_prepare(PG_FUNCTION_ARGS) { char *password = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *prep_password = NULL; if (GetDatabaseEncoding() != PG_UTF8) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Database encoding is not UTF-8"))); if (pg_saslprep(password, &prep_password) != SASLPREP_SUCCESS) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Error while processing SASLprep"))); PG_RETURN_TEXT_P(cstring_to_text(prep_password)); }
char* String_createNTS(jstring javaString) { char* result = 0; if( 0 == javaString ) return result; if ( uninitialized ) { const char* u8buf; s_server_encoding = GetDatabaseEncoding(); u8buf = JNI_getStringUTFChars( javaString, NULL); if ( 0 == u8buf ) return result; result = (char*)pg_do_encoding_conversion( (unsigned char *)u8buf, (int)strlen( u8buf), PG_UTF8, s_server_encoding); if ( result == u8buf ) result = pstrdup( result); JNI_releaseStringUTFChars( javaString, u8buf); return result; } else { jobject charbuf = JNI_callStaticObjectMethodLocked(s_CharBuffer_class, s_CharBuffer_wrap, javaString); StringInfoData sid; initStringInfo(&sid); appendCharBuffer(&sid, charbuf); JNI_deleteLocalRef(charbuf); result = (char*)pg_do_encoding_conversion( (unsigned char *)sid.data, sid.len, PG_UTF8, s_server_encoding); /* pg_do_encoding_conversion will return the source argument * when no conversion is required. Don't free it in that case. */ if(result != sid.data) pfree(sid.data); } return result; }
jstring String_createJavaStringFromNTS(const char* cp) { jstring result = 0; if(cp != 0) { /* Would be nice if a direct conversion to UTF16 was provided. */ char* utf8 = (char*)pg_do_encoding_conversion((unsigned char*)cp, strlen(cp), GetDatabaseEncoding(), PG_UTF8); result = JNI_newStringUTF(utf8); /* pg_do_encoding_conversion will return the source argument * when no conversion is required. We don't want to accidentally * free that pointer. */ if(utf8 != cp) pfree(utf8); } return result; }
char* String_createNTS(jstring javaString) { char* result = 0; if(javaString != 0) { /* Would be nice if a direct conversion from UTF16 was provided. */ char* utf8 = (char*)JNI_getStringUTFChars(javaString, 0); result = (char*)pg_do_encoding_conversion( (unsigned char*)utf8, strlen(utf8), PG_UTF8, GetDatabaseEncoding()); /* pg_do_encoding_conversion will return the source argument * when no conversion is required. We always want a copy here. */ if(result == utf8) result = pstrdup(result); JNI_releaseStringUTFChars(javaString, utf8); } return result; }
void executormgr_setup_env(MemoryContext ctx) { MemoryContext old; if (executor_cache.init) return; executor_cache.pool = poolmgr_create_pool(ctx, (PoolMgrCleanCallback) executormgr_destory); executor_cache.entrydb_pool = poolmgr_create_pool(ctx, (PoolMgrCleanCallback) executormgr_destory); executor_cache.ctx = ctx; executor_cache.init = true; /* TODO: Setup dispatcher information. But should remove in the future. */ old = MemoryContextSwitchTo(ctx); MyProcPort->dboid = MyDatabaseId; MyProcPort->dbdtsoid = get_database_dts(MyDatabaseId); MyProcPort->bootstrap_user = get_rolname(BOOTSTRAP_SUPERUSERID); MyProcPort->encoding = GetDatabaseEncoding(); MemoryContextSwitchTo(old); }
void String_appendJavaString(StringInfoData* buf, jstring javaString) { if(javaString != 0) { /* Would be nice if a direct conversion from UTF16 was provided. */ char* utf8 = (char*)JNI_getStringUTFChars(javaString, 0); char* dbEnc = (char*)pg_do_encoding_conversion( (unsigned char*)utf8, strlen(utf8), PG_UTF8, GetDatabaseEncoding()); appendStringInfoString(buf, dbEnc); /* pg_do_encoding_conversion will return the source argument * when no conversion is required. We don't want to accidentally * free that pointer. */ if(dbEnc != utf8) pfree(dbEnc); JNI_releaseStringUTFChars(javaString, utf8); } }
Datum xmldoc_in(PG_FUNCTION_ARGS) { pg_enc dbEnc; XMLNodeParserStateData parserState; char *input = PG_GETARG_CSTRING(0); if (strlen(input) == 0) { elog(ERROR, "zero length input string"); } dbEnc = GetDatabaseEncoding(); if (dbEnc != PG_UTF8) { elog(ERROR, "The current version of xmlnode requires both database encoding to be UTF-8."); } initXMLParserState(&parserState, input, false); xmlnodeParseDoc(&parserState); finalizeXMLParserState(&parserState); PG_RETURN_POINTER(parserState.result); }
static void locate_stem_module(DictSnowball *d, char *lang) { const stemmer_module *m; /* * First, try to find exact match of stemmer module. Stemmer with * PG_SQL_ASCII encoding is treated as working with any server encoding */ for (m = stemmer_modules; m->name; m++) { if ((m->enc == PG_SQL_ASCII || m->enc == GetDatabaseEncoding()) && pg_strcasecmp(m->name, lang) == 0) { d->stem = m->stem; d->z = m->create(); d->needrecode = false; return; } } /* * Second, try to find stemmer for needed language for UTF8 encoding. */ for (m = stemmer_modules; m->name; m++) { if (m->enc == PG_UTF8 && pg_strcasecmp(m->name, lang) == 0) { d->stem = m->stem; d->z = m->create(); d->needrecode = true; return; } } ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("no Snowball stemmer available for language \"%s\" and encoding \"%s\"", lang, GetDatabaseEncodingName()))); }
/* * On WIN32, strftime() returns the encoding in CP_ACP (the default * operating system codpage for that computer), which is likely different * from SERVER_ENCODING. This is especially important in Japanese versions * of Windows which will use SJIS encoding, which we don't support as a * server encoding. * * So, instead of using strftime(), use wcsftime() to return the value in * wide characters (internally UTF16) and then convert it to the appropriate * database encoding. * * Note that this only affects the calls to strftime() in this file, which are * used to get the locale-aware strings. Other parts of the backend use * pg_strftime(), which isn't locale-aware and does not need to be replaced. */ static size_t strftime_win32(char *dst, size_t dstlen, const wchar_t *format, const struct tm * tm) { size_t len; wchar_t wbuf[MAX_L10N_DATA]; int encoding; encoding = GetDatabaseEncoding(); len = wcsftime(wbuf, MAX_L10N_DATA, format, tm); if (len == 0) /* * strftime call failed - return 0 with the contents of dst * unspecified */ return 0; len = WideCharToMultiByte(CP_UTF8, 0, wbuf, len, dst, dstlen, NULL, NULL); if (len == 0) elog(ERROR, "could not convert string to UTF-8: error code %lu", GetLastError()); dst[len] = '\0'; if (encoding != PG_UTF8) { char *convstr = (char *) pg_do_encoding_conversion((unsigned char *) dst, len, PG_UTF8, encoding); if (dst != convstr) { strlcpy(dst, convstr, dstlen); len = strlen(dst); } } return len; }
size_t char2wchar(wchar_t *to, const char *from, size_t len) { if (len == 0) return 0; #ifdef WIN32 if (GetDatabaseEncoding() == PG_UTF8) { int r; r = MultiByteToWideChar(CP_UTF8, 0, from, len, to, len); if (!r) { pg_verifymbstr(from, strlen(from), false); 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."))); } Assert(r <= len); return r; } else #endif /* WIN32 */ if ( lc_ctype_is_c() ) { /* * pg_mb2wchar_with_len always adds trailing '\0', so * 'to' should be allocated with sufficient space */ return pg_mb2wchar_with_len(from, (pg_wchar *)to, len); } return mbstowcs(to, from, len); }
/* * Convert a C string in the PostgreSQL server encoding to a Python * unicode object. Reference ownership is passed to the caller. */ PyObject * PyString_FromStringAndSize(const char *s, Py_ssize_t size) { char *utf8string; PyObject *o; utf8string = (char *) pg_do_encoding_conversion((unsigned char *) s, strlen(s), GetDatabaseEncoding(), PG_UTF8); if (size < 0) { o = PyUnicode_FromString(utf8string); } else { o = PyUnicode_FromStringAndSize(utf8string, size); } if (utf8string != s) pfree(utf8string); return o; }
/* * wchar2char --- convert wide characters to multibyte format * * This has the same API as the standard wcstombs() function; in particular, * tolen is the maximum number of bytes to store at *to, and *from must be * zero-terminated. The output will be zero-terminated iff there is room. */ size_t wchar2char(char *to, const wchar_t *from, size_t tolen) { size_t result; if (tolen == 0) return 0; #ifdef WIN32 /* * On Windows, the "Unicode" locales assume UTF16 not UTF8 encoding, and * for some reason mbstowcs and wcstombs won't do this for us, so we use * MultiByteToWideChar(). */ if (GetDatabaseEncoding() == PG_UTF8) { result = WideCharToMultiByte(CP_UTF8, 0, from, -1, to, tolen, NULL, NULL); /* A zero return is failure */ if (result <= 0) result = -1; else { Assert(result <= tolen); /* Microsoft counts the zero terminator in the result */ result--; } } else #endif /* WIN32 */ { Assert(!lc_ctype_is_c()); result = wcstombs(to, from, tolen); } return result; }
static inline int Generic_Text_IC_like(text *str, text *pat) { char *s, *p; int slen, plen; /* * For efficiency reasons, in the single byte case we don't call lower() * on the pattern and text, but instead call to_lower on each character. * In the multi-byte case we don't have much choice :-( */ if (pg_database_encoding_max_length() > 1) { /* lower's result is never packed, so OK to use old macros here */ pat = DatumGetTextP(DirectFunctionCall1(lower, PointerGetDatum(pat))); p = VARDATA(pat); plen = (VARSIZE(pat) - VARHDRSZ); str = DatumGetTextP(DirectFunctionCall1(lower, PointerGetDatum(str))); s = VARDATA(str); slen = (VARSIZE(str) - VARHDRSZ); if (GetDatabaseEncoding() == PG_UTF8) return UTF8_MatchText(s, slen, p, plen); else return MB_MatchText(s, slen, p, plen); } else { p = VARDATA_ANY(pat); plen = VARSIZE_ANY_EXHDR(pat); s = VARDATA_ANY(str); slen = VARSIZE_ANY_EXHDR(str); return SB_IMatchText(s, slen, p, plen); } }
Datum chr (PG_FUNCTION_ARGS) { uint32 cvalue = PG_GETARG_UINT32(0); text *result; int encoding = GetDatabaseEncoding(); if (encoding == PG_UTF8 && cvalue > 127) { /* for Unicode we treat the argument as a code point */ int bytes; char *wch; /* We only allow valid Unicode code points */ if (cvalue > 0x001fffff) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("requested character too large for encoding: %d", cvalue))); if (cvalue > 0xffff) bytes = 4; else if (cvalue > 0x07ff) bytes = 3; else bytes = 2; result = (text *) palloc(VARHDRSZ + bytes); SET_VARSIZE(result, VARHDRSZ + bytes); wch = VARDATA(result); if (bytes == 2) { wch[0] = 0xC0 | ((cvalue >> 6) & 0x1F); wch[1] = 0x80 | (cvalue & 0x3F);; }
/* * Bind gettext to the codeset equivalent with the database encoding. */ void pg_bind_textdomain_codeset(const char *domainname) { #if defined(ENABLE_NLS) int encoding = GetDatabaseEncoding(); int i; /* * gettext() uses the codeset specified by LC_CTYPE by default, so if that * matches the database encoding we don't need to do anything. In CREATE * DATABASE, we enforce or trust that the locale's codeset matches * database encoding, except for the C locale. In C locale, we bind * gettext() explicitly to the right codeset. * * On Windows, though, gettext() tends to get confused so we always bind * it. */ #ifndef WIN32 const char *ctype = setlocale(LC_CTYPE, NULL); if (pg_strcasecmp(ctype, "C") != 0 && pg_strcasecmp(ctype, "POSIX") != 0) return; #endif for (i = 0; pg_enc2gettext_tbl[i].name != NULL; i++) { if (pg_enc2gettext_tbl[i].encoding == encoding) { if (bind_textdomain_codeset(domainname, pg_enc2gettext_tbl[i].name) == NULL) elog(LOG, "bind_textdomain_codeset failed"); break; } } #endif }
/* * Set the client encoding and save fmgrinfo for the conversion * function if necessary. Returns 0 if okay, -1 if not (bad encoding * or can't support conversion) */ int SetClientEncoding(int encoding, bool doit) { int current_server_encoding; Oid to_server_proc, to_client_proc; FmgrInfo *to_server; FmgrInfo *to_client; MemoryContext oldcontext; if (!PG_VALID_FE_ENCODING(encoding)) return -1; /* Can't do anything during startup, per notes above */ if (!backend_startup_complete) { if (doit) pending_client_encoding = encoding; return 0; } current_server_encoding = GetDatabaseEncoding(); /* * Check for cases that require no conversion function. */ if (current_server_encoding == encoding || current_server_encoding == PG_SQL_ASCII || encoding == PG_SQL_ASCII) { if (doit) { ClientEncoding = &pg_enc2name_tbl[encoding]; ToServerConvProc = NULL; ToClientConvProc = NULL; if (MbProcContext) MemoryContextReset(MbProcContext); } return 0; } /* * If we're not inside a transaction then we can't do catalog lookups, so * fail. After backend startup, this could only happen if we are * re-reading postgresql.conf due to SIGHUP --- so basically this just * constrains the ability to change client_encoding on the fly from * postgresql.conf. Which would probably be a stupid thing to do anyway. */ if (!IsTransactionState()) return -1; /* * Look up the conversion functions. */ to_server_proc = FindDefaultConversionProc(encoding, current_server_encoding); if (!OidIsValid(to_server_proc)) return -1; to_client_proc = FindDefaultConversionProc(current_server_encoding, encoding); if (!OidIsValid(to_client_proc)) return -1; /* * Done if not wanting to actually apply setting. */ if (!doit) return 0; /* Before loading the new fmgr info, remove the old info, if any */ ToServerConvProc = NULL; ToClientConvProc = NULL; if (MbProcContext != NULL) { MemoryContextReset(MbProcContext); } else { /* * This is the first time through, so create the context. Make it a * child of TopMemoryContext so that these values survive across * transactions. */ MbProcContext = AllocSetContextCreate(TopMemoryContext, "MbProcContext", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); } /* Load the fmgr info into MbProcContext */ oldcontext = MemoryContextSwitchTo(MbProcContext); to_server = palloc(sizeof(FmgrInfo)); to_client = palloc(sizeof(FmgrInfo)); fmgr_info(to_server_proc, to_server); fmgr_info(to_client_proc, to_client); MemoryContextSwitchTo(oldcontext); ClientEncoding = &pg_enc2name_tbl[encoding]; ToServerConvProc = to_server; ToClientConvProc = to_client; return 0; }
/* * 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 SV * plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo) { dSP; SV *retval; int i; int count; SV *sv; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(&PL_sv_undef); /* no trigger data */ for (i = 0; i < desc->nargs; i++) { if (fcinfo->argnull[i]) XPUSHs(&PL_sv_undef); else if (desc->arg_is_rowtype[i]) { HeapTupleHeader td; Oid tupType; int32 tupTypmod; TupleDesc tupdesc; HeapTupleData tmptup; SV *hashref; td = DatumGetHeapTupleHeader(fcinfo->arg[i]); /* Extract rowtype info and find a tupdesc */ tupType = HeapTupleHeaderGetTypeId(td); tupTypmod = HeapTupleHeaderGetTypMod(td); tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); /* Build a temporary HeapTuple control structure */ tmptup.t_len = HeapTupleHeaderGetDatumLength(td); tmptup.t_data = td; hashref = plperl_hash_from_tuple(&tmptup, tupdesc); XPUSHs(sv_2mortal(hashref)); } else { char *tmp; tmp = DatumGetCString(FunctionCall1(&(desc->arg_out_func[i]), fcinfo->arg[i])); sv = newSVpv(tmp, 0); #if PERL_BCDVERSION >= 0x5006000L if (GetDatabaseEncoding() == PG_UTF8) SvUTF8_on(sv); #endif XPUSHs(sv_2mortal(sv)); pfree(tmp); } } PUTBACK; /* Do NOT use G_KEEPERR here */ count = perl_call_sv(desc->reference, G_SCALAR | G_EVAL); SPAGAIN; if (count != 1) { PUTBACK; FREETMPS; LEAVE; elog(ERROR, "didn't get a return item from function"); } if (SvTRUE(ERRSV)) { (void) POPs; PUTBACK; FREETMPS; LEAVE; /* XXX need to find a way to assign an errcode here */ ereport(ERROR, (errmsg("error from Perl function: %s", strip_trailing_ws(SvPV(ERRSV, PL_na))))); } retval = newSVsv(POPs); PUTBACK; FREETMPS; LEAVE; return retval; }
/* * Retrieve statement statistics. */ Datum pg_stat_statements(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; Oid userid = GetUserId(); bool is_superuser = superuser(); HASH_SEQ_STATUS hash_seq; pgssEntry *entry; if (!pgss || !pgss_hash) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("pg_stat_statements must be loaded via shared_preload_libraries"))); /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; MemoryContextSwitchTo(oldcontext); LWLockAcquire(pgss->lock, LW_SHARED); hash_seq_init(&hash_seq, pgss_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { Datum values[PG_STAT_STATEMENTS_COLS]; bool nulls[PG_STAT_STATEMENTS_COLS]; int i = 0; Counters tmp; memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); values[i++] = ObjectIdGetDatum(entry->key.userid); values[i++] = ObjectIdGetDatum(entry->key.dbid); if (is_superuser || entry->key.userid == userid) { char *qstr; qstr = (char *) pg_do_encoding_conversion((unsigned char *) entry->query, entry->key.query_len, entry->key.encoding, GetDatabaseEncoding()); values[i++] = CStringGetTextDatum(qstr); if (qstr != entry->query) pfree(qstr); } else values[i++] = CStringGetTextDatum("<insufficient privilege>"); /* copy counters to a local variable to keep locking time short */ { volatile pgssEntry *e = (volatile pgssEntry *) entry; SpinLockAcquire(&e->mutex); tmp = e->counters; SpinLockRelease(&e->mutex); } values[i++] = Int64GetDatumFast(tmp.calls); values[i++] = Float8GetDatumFast(tmp.total_time); values[i++] = Int64GetDatumFast(tmp.rows); values[i++] = Int64GetDatumFast(tmp.shared_blks_hit); values[i++] = Int64GetDatumFast(tmp.shared_blks_read); values[i++] = Int64GetDatumFast(tmp.shared_blks_written); values[i++] = Int64GetDatumFast(tmp.local_blks_hit); values[i++] = Int64GetDatumFast(tmp.local_blks_read); values[i++] = Int64GetDatumFast(tmp.local_blks_written); values[i++] = Int64GetDatumFast(tmp.temp_blks_read); values[i++] = Int64GetDatumFast(tmp.temp_blks_written); Assert(i == PG_STAT_STATEMENTS_COLS); tuplestore_putvalues(tupstore, tupdesc, values, nulls); } LWLockRelease(pgss->lock); /* clean up and return the tuplestore */ tuplestore_donestoring(tupstore); return (Datum) 0; }
/* * Store some statistics for a statement. */ static void pgss_store(const char *query, double total_time, uint64 rows, const BufferUsage *bufusage) { pgssHashKey key; double usage; pgssEntry *entry; Assert(query != NULL); /* Safety check... */ if (!pgss || !pgss_hash) return; /* Set up key for hashtable search */ key.userid = GetUserId(); key.dbid = MyDatabaseId; key.encoding = GetDatabaseEncoding(); key.query_len = strlen(query); if (key.query_len >= pgss->query_size) key.query_len = pg_encoding_mbcliplen(key.encoding, query, key.query_len, pgss->query_size - 1); key.query_ptr = query; usage = USAGE_EXEC(duration); /* Lookup the hash table entry with shared lock. */ LWLockAcquire(pgss->lock, LW_SHARED); entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL); if (!entry) { /* Must acquire exclusive lock to add a new entry. */ LWLockRelease(pgss->lock); LWLockAcquire(pgss->lock, LW_EXCLUSIVE); entry = entry_alloc(&key); } /* Grab the spinlock while updating the counters. */ { volatile pgssEntry *e = (volatile pgssEntry *) entry; SpinLockAcquire(&e->mutex); e->counters.calls += 1; e->counters.total_time += total_time; e->counters.rows += rows; e->counters.shared_blks_hit += bufusage->shared_blks_hit; e->counters.shared_blks_read += bufusage->shared_blks_read; e->counters.shared_blks_written += bufusage->shared_blks_written; e->counters.local_blks_hit += bufusage->local_blks_hit; e->counters.local_blks_read += bufusage->local_blks_read; e->counters.local_blks_written += bufusage->local_blks_written; e->counters.temp_blks_read += bufusage->temp_blks_read; e->counters.temp_blks_written += bufusage->temp_blks_written; e->counters.usage += usage; SpinLockRelease(&e->mutex); } LWLockRelease(pgss->lock); }
/* * CollationCreate * * Add a new tuple to pg_collation. * * if_not_exists: if true, don't fail on duplicate name, just print a notice * and return InvalidOid. * quiet: if true, don't fail on duplicate name, just silently return * InvalidOid (overrides if_not_exists). */ Oid CollationCreate(const char *collname, Oid collnamespace, Oid collowner, char collprovider, int32 collencoding, const char *collcollate, const char *collctype, const char *collversion, bool if_not_exists, bool quiet) { Relation rel; TupleDesc tupDesc; HeapTuple tup; Datum values[Natts_pg_collation]; bool nulls[Natts_pg_collation]; NameData name_name, name_collate, name_ctype; Oid oid; ObjectAddress myself, referenced; AssertArg(collname); AssertArg(collnamespace); AssertArg(collowner); AssertArg(collcollate); AssertArg(collctype); /* * Make sure there is no existing collation of same name & encoding. * * This would be caught by the unique index anyway; we're just giving a * friendlier error message. The unique index provides a backstop against * race conditions. */ if (SearchSysCacheExists3(COLLNAMEENCNSP, PointerGetDatum(collname), Int32GetDatum(collencoding), ObjectIdGetDatum(collnamespace))) { if (quiet) return InvalidOid; else if (if_not_exists) { ereport(NOTICE, (errcode(ERRCODE_DUPLICATE_OBJECT), collencoding == -1 ? errmsg("collation \"%s\" already exists, skipping", collname) : errmsg("collation \"%s\" for encoding \"%s\" already exists, skipping", collname, pg_encoding_to_char(collencoding)))); return InvalidOid; } else ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), collencoding == -1 ? errmsg("collation \"%s\" already exists", collname) : errmsg("collation \"%s\" for encoding \"%s\" already exists", collname, pg_encoding_to_char(collencoding)))); } /* open pg_collation; see below about the lock level */ rel = heap_open(CollationRelationId, ShareRowExclusiveLock); /* * Also forbid a specific-encoding collation shadowing an any-encoding * collation, or an any-encoding collation being shadowed (see * get_collation_name()). This test is not backed up by the unique index, * so we take a ShareRowExclusiveLock earlier, to protect against * concurrent changes fooling this check. */ if ((collencoding == -1 && SearchSysCacheExists3(COLLNAMEENCNSP, PointerGetDatum(collname), Int32GetDatum(GetDatabaseEncoding()), ObjectIdGetDatum(collnamespace))) || (collencoding != -1 && SearchSysCacheExists3(COLLNAMEENCNSP, PointerGetDatum(collname), Int32GetDatum(-1), ObjectIdGetDatum(collnamespace)))) { if (quiet) { heap_close(rel, NoLock); return InvalidOid; } else if (if_not_exists) { heap_close(rel, NoLock); ereport(NOTICE, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("collation \"%s\" already exists, skipping", collname))); return InvalidOid; } else ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("collation \"%s\" already exists", collname))); } tupDesc = RelationGetDescr(rel); /* form a tuple */ memset(nulls, 0, sizeof(nulls)); namestrcpy(&name_name, collname); values[Anum_pg_collation_collname - 1] = NameGetDatum(&name_name); values[Anum_pg_collation_collnamespace - 1] = ObjectIdGetDatum(collnamespace); values[Anum_pg_collation_collowner - 1] = ObjectIdGetDatum(collowner); values[Anum_pg_collation_collprovider - 1] = CharGetDatum(collprovider); values[Anum_pg_collation_collencoding - 1] = Int32GetDatum(collencoding); namestrcpy(&name_collate, collcollate); values[Anum_pg_collation_collcollate - 1] = NameGetDatum(&name_collate); namestrcpy(&name_ctype, collctype); values[Anum_pg_collation_collctype - 1] = NameGetDatum(&name_ctype); if (collversion) values[Anum_pg_collation_collversion - 1] = CStringGetTextDatum(collversion); else nulls[Anum_pg_collation_collversion - 1] = true; tup = heap_form_tuple(tupDesc, values, nulls); /* insert a new tuple */ oid = CatalogTupleInsert(rel, tup); Assert(OidIsValid(oid)); /* set up dependencies for the new collation */ myself.classId = CollationRelationId; myself.objectId = oid; myself.objectSubId = 0; /* create dependency on namespace */ referenced.classId = NamespaceRelationId; referenced.objectId = collnamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* create dependency on owner */ recordDependencyOnOwner(CollationRelationId, HeapTupleGetOid(tup), collowner); /* dependency on extension */ recordDependencyOnCurrentExtension(&myself, false); /* Post creation hook for new collation */ InvokeObjectPostCreateHook(CollationRelationId, oid, 0); heap_freetuple(tup); heap_close(rel, NoLock); return oid; }
void SetDefaultClientEncoding(void) { ClientEncoding = &pg_enc2name_tbl[GetDatabaseEncoding()]; }
/* * 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; }
static text * convert_to_utf8(text *src) { return convert_charset(src, GetDatabaseEncoding(), PG_UTF8); }
static text * convert_from_utf8(text *src) { return convert_charset(src, PG_UTF8, GetDatabaseEncoding()); }