📄 varlena.c
字号:
/* now null pad to full length... */ while (len < NAMEDATALEN) { *(NameStr(*result) + len) = '\0'; len++; } PG_RETURN_NAME(result);}/* name_text() * Converts a Name type to a text type. */Datumname_text(PG_FUNCTION_ARGS){ Name s = PG_GETARG_NAME(0); text *result; int len; len = strlen(NameStr(*s));#ifdef STRINGDEBUG printf("text- convert string length %d (%d) ->%d\n", VARSIZE(s) - VARHDRSZ, VARSIZE(s), len);#endif result = palloc(VARHDRSZ + len); VARATT_SIZEP(result) = VARHDRSZ + len; memcpy(VARDATA(result), NameStr(*s), len); PG_RETURN_TEXT_P(result);}/* * textToQualifiedNameList - convert a text object to list of names * * This implements the input parsing needed by nextval() and other * functions that take a text parameter representing a qualified name. * We split the name at dots, downcase if not double-quoted, and * truncate names if they're too long. */List *textToQualifiedNameList(text *textval){ char *rawname; List *result = NIL; List *namelist; ListCell *l; /* Convert to C string (handles possible detoasting). */ /* Note we rely on being able to modify rawname below. */ rawname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textval))); if (!SplitIdentifierString(rawname, '.', &namelist)) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); if (namelist == NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); foreach(l, namelist) { char *curname = (char *) lfirst(l); result = lappend(result, makeString(pstrdup(curname))); } pfree(rawname); list_free(namelist); return result;}/* * SplitIdentifierString --- parse a string containing identifiers * * This is the guts of textToQualifiedNameList, and is exported for use in * other situations such as parsing GUC variables. In the GUC case, it's * important to avoid memory leaks, so the API is designed to minimize the * amount of stuff that needs to be allocated and freed. * * Inputs: * rawstring: the input string; must be overwritable! On return, it's * been modified to contain the separated identifiers. * separator: the separator punctuation expected between identifiers * (typically '.' or ','). Whitespace may also appear around * identifiers. * Outputs: * namelist: filled with a palloc'd list of pointers to identifiers within * rawstring. Caller should list_free() this even on error return. * * Returns TRUE if okay, FALSE if there is a syntax error in the string. * * Note that an empty string is considered okay here, though not in * textToQualifiedNameList. */boolSplitIdentifierString(char *rawstring, char separator, List **namelist){ char *nextp = rawstring; bool done = false; *namelist = NIL; while (isspace((unsigned char) *nextp)) nextp++; /* skip leading whitespace */ if (*nextp == '\0') return true; /* allow empty string */ /* At the top of the loop, we are at start of a new identifier. */ do { char *curname; char *endp; if (*nextp == '\"') { /* Quoted name --- collapse quote-quote pairs, no downcasing */ curname = nextp + 1; for (;;) { endp = strchr(nextp + 1, '\"'); if (endp == NULL) return false; /* mismatched quotes */ if (endp[1] != '\"') break; /* found end of quoted name */ /* Collapse adjacent quotes into one quote, and look again */ memmove(endp, endp + 1, strlen(endp)); nextp = endp; } /* endp now points at the terminating quote */ nextp = endp + 1; } else { /* Unquoted name --- extends to separator or whitespace */ char *downname; int len; curname = nextp; while (*nextp && *nextp != separator && !isspace((unsigned char) *nextp)) nextp++; endp = nextp; if (curname == nextp) return false; /* empty unquoted name not allowed */ /* * Downcase the identifier, using same code as main lexer does. * * XXX because we want to overwrite the input in-place, we cannot * support a downcasing transformation that increases the string * length. This is not a problem given the current implementation * of downcase_truncate_identifier, but we'll probably have to do * something about this someday. */ len = endp - curname; downname = downcase_truncate_identifier(curname, len, false); Assert(strlen(downname) <= len); strncpy(curname, downname, len); pfree(downname); } while (isspace((unsigned char) *nextp)) nextp++; /* skip trailing whitespace */ if (*nextp == separator) { nextp++; while (isspace((unsigned char) *nextp)) nextp++; /* skip leading whitespace for next */ /* we expect another name, so done remains false */ } else if (*nextp == '\0') done = true; else return false; /* invalid syntax */ /* Now safe to overwrite separator with a null */ *endp = '\0'; /* Truncate name if it's overlength */ truncate_identifier(curname, strlen(curname), false); /* * Finished isolating current name --- add it to list */ *namelist = lappend(*namelist, curname); /* Loop back if we didn't reach end of string */ } while (!done); return true;}/***************************************************************************** * Comparison Functions used for bytea * * Note: btree indexes need these routines not to leak memory; therefore, * be careful to free working copies of toasted datums. Most places don't * need to be so careful. *****************************************************************************/Datumbyteaeq(PG_FUNCTION_ARGS){ bytea *arg1 = PG_GETARG_BYTEA_P(0); bytea *arg2 = PG_GETARG_BYTEA_P(1); int len1, len2; bool result; len1 = VARSIZE(arg1) - VARHDRSZ; len2 = VARSIZE(arg2) - VARHDRSZ; /* fast path for different-length inputs */ if (len1 != len2) result = false; else result = (memcmp(VARDATA(arg1), VARDATA(arg2), len1) == 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_BOOL(result);}Datumbyteane(PG_FUNCTION_ARGS){ bytea *arg1 = PG_GETARG_BYTEA_P(0); bytea *arg2 = PG_GETARG_BYTEA_P(1); int len1, len2; bool result; len1 = VARSIZE(arg1) - VARHDRSZ; len2 = VARSIZE(arg2) - VARHDRSZ; /* fast path for different-length inputs */ if (len1 != len2) result = true; else result = (memcmp(VARDATA(arg1), VARDATA(arg2), len1) != 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_BOOL(result);}Datumbytealt(PG_FUNCTION_ARGS){ bytea *arg1 = PG_GETARG_BYTEA_P(0); bytea *arg2 = PG_GETARG_BYTEA_P(1); int len1, len2; int cmp; len1 = VARSIZE(arg1) - VARHDRSZ; len2 = VARSIZE(arg2) - VARHDRSZ; cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 < len2)));}Datumbyteale(PG_FUNCTION_ARGS){ bytea *arg1 = PG_GETARG_BYTEA_P(0); bytea *arg2 = PG_GETARG_BYTEA_P(1); int len1, len2; int cmp; len1 = VARSIZE(arg1) - VARHDRSZ; len2 = VARSIZE(arg2) - VARHDRSZ; cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_BOOL((cmp < 0) || ((cmp == 0) && (len1 <= len2)));}Datumbyteagt(PG_FUNCTION_ARGS){ bytea *arg1 = PG_GETARG_BYTEA_P(0); bytea *arg2 = PG_GETARG_BYTEA_P(1); int len1, len2; int cmp; len1 = VARSIZE(arg1) - VARHDRSZ; len2 = VARSIZE(arg2) - VARHDRSZ; cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 > len2)));}Datumbyteage(PG_FUNCTION_ARGS){ bytea *arg1 = PG_GETARG_BYTEA_P(0); bytea *arg2 = PG_GETARG_BYTEA_P(1); int len1, len2; int cmp; len1 = VARSIZE(arg1) - VARHDRSZ; len2 = VARSIZE(arg2) - VARHDRSZ; cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_BOOL((cmp > 0) || ((cmp == 0) && (len1 >= len2)));}Datumbyteacmp(PG_FUNCTION_ARGS){ bytea *arg1 = PG_GETARG_BYTEA_P(0); bytea *arg2 = PG_GETARG_BYTEA_P(1); int len1, len2; int cmp; len1 = VARSIZE(arg1) - VARHDRSZ; len2 = VARSIZE(arg2) - VARHDRSZ; cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); if ((cmp == 0) && (len1 != len2)) cmp = (len1 < len2) ? -1 : 1; PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); PG_RETURN_INT32(cmp);}/* * appendStringInfoText * * Append a text to str. * Like appendStringInfoString(str, PG_TEXT_GET_STR(s)) but faster. */static voidappendStringInfoText(StringInfo str, const text *t){ appendBinaryStringInfo(str, VARDATA(t), VARSIZE(t) - VARHDRSZ);}/* * replace_text * replace all occurrences of 'old_sub_str' in 'orig_str' * with 'new_sub_str' to form 'new_str' * * returns 'orig_str' if 'old_sub_str' == '' or 'orig_str' == '' * otherwise returns 'new_str' */Datumreplace_text(PG_FUNCTION_ARGS){ text *src_text = PG_GETARG_TEXT_P(0); text *from_sub_text = PG_GETARG_TEXT_P(1); text *to_sub_text = PG_GETARG_TEXT_P(2); int src_text_len = TEXTLEN(src_text); int from_sub_text_len = TEXTLEN(from_sub_text); text *left_text; text *right_text; text *buf_text; text *ret_text; int curr_posn; StringInfo str; if (src_text_len == 0 || from_sub_text_len == 0) PG_RETURN_TEXT_P(src_text); curr_posn = TEXTPOS(src_text, from_sub_text); /* When the from_sub_text is not found, there is nothing to do. */ if (curr_posn == 0) PG_RETURN_TEXT_P(src_text); str = makeStringInfo(); buf_text = src_text; while (curr_posn > 0) { left_text = text_substring(PointerGetDatum(buf_text), 1, curr_posn - 1, false); right_text = text_substring(PointerGetDatum(buf_text), curr_posn + from_sub_text_len, -1, true); appendStringInfoText(str, left_text); appendStringInfoText(str, to_sub_text); if (buf_text != src_text) pfree(buf_text); pfree(left_text); buf_text = right_text; curr_posn = TEXTPOS(buf_text, from_sub_text); } appendStringInfoText(str, buf_text); if (buf_text != src_text) pfree(buf_text); ret_text = PG_STR_GET_TEXT(str->data); pfree(str->data); pfree(str); PG_RETURN_TEXT_P(ret_text);}/* * check_replace_text_has_escape_char * * check whether replace_text contains escape char. */static boolcheck_replace_text_has_escape_char(const text *replace_text){ const char *p = VARDATA(replace_text); const char *p_end = p + (VARSIZE(replace_text) - VARHDRSZ); if (pg_database_encoding_max_length() == 1) { for (; p < p_end; p++) { if (*p == '\\') return true; } } else { for (; p < p_end; p += pg_mblen(p)) { if (*p == '\\') return true; } } return false;}/* * appendStringInfoRegexpSubstr * * Append replace_text to str, substituting regexp back references for * \n escapes. */static voidappendStringInfoRegexpSubstr(StringInfo str, text *replace_text, regmatch_t *pmatch, text *src_text){ const char *p = VARDATA(replace_text); const char *p_end = p + (VARSIZE(replace_text) - VARHDRSZ); int eml = pg_database_encoding_max_length(); for (;;) { const char *chunk_start = p; int so; int eo; /* Find next escape char. */ if (eml == 1) { for (; p < p_end && *p != '\\'; p++) /* nothing */ ; } else { for (; p < p_end && *p != '\\'; p += pg_mblen(p)) /* nothing */ ; } /* Copy the text we just scanned over, if any. */ if (p > chunk_start) appendBinaryStringInfo(str, chunk_start, p - chunk_start); /* Done if at end of string, else advance over escape char. */ if (p >= p_end) break; p++; if (p >= p_end) { /* Escape at very end of input. Treat same as unexpected char */ appendStringInfoChar(str, '\\'); break; } if (*p >= '1' && *p <= '9') { /* Use the back reference of regexp. */ int idx = *p - '0'; so = pmatch[idx].rm_so; eo = pmatch[idx].rm_eo; p++; } else if (*p == '&') { /* Use the entire matched string. */ so = pmatch[0].rm_so; eo = pmatch[0].rm_eo; p++; } else if (*p == '\\') { /* \\ means transfer one \ to output. */ appendStringInfoChar(str, '\\'); p++; continue; } else { /* * If escape char is not followed by any expected char, just treat * it as ordinary data to copy. (XXX would it be better to throw * an error?)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -