/* check whether the content in the given bytea is safe for mfvtransval */ void check_mfvtransval(bytea *storage) { size_t left_len = VARSIZE(storage); size_t cur_size = 0; size_t cur_capacity = 0; Oid outFuncOid; bool typIsVarLen; mfvtransval *mfv = NULL; if (left_len < VARHDRSZ + sizeof(mfvtransval)) { elog(ERROR, "invalid transition state for mfvsketch"); } mfv = (mfvtransval*)VARDATA(storage); left_len -= VARHDRSZ + sizeof(mfvtransval); if (mfv->next_mfv > mfv->max_mfvs) { elog(ERROR, "invalid transition state for mfvsketch"); } if (mfv->next_offset + VARHDRSZ > VARSIZE(storage)) { elog(ERROR, "invalid transition state for mfvsketch"); } if (InvalidOid == mfv->typOid) { elog(ERROR, "invalid transition state for mfvsketch"); } getTypeOutputInfo(mfv->typOid, &outFuncOid, &typIsVarLen); if (mfv->outFuncOid != outFuncOid || mfv->typLen != get_typlen(mfv->typOid) || mfv->typByVal != get_typbyval(mfv->typOid)) { elog(ERROR, "invalid transition state for mfvsketch"); } if (left_len < sizeof(offsetcnt)*mfv->max_mfvs) { elog(ERROR, "invalid transition state for mfvsketch"); } /* offset is relative to mfvtransval */ left_len = VARSIZE(storage) - VARHDRSZ; /* * the following checking may be inefficiency, but by doing this centrally, * we can avoid spreading the checking code everywhere. */ for (unsigned i = 0; i < mfv->next_mfv; i ++) { cur_capacity = left_len - mfv->mfvs[i].offset; if (mfv->mfvs[i].offset > left_len) { elog(ERROR, "invalid transition state for mfvsketch"); } cur_size = ExtractDatumLen(PointerGetDatum(MFV_DATA(mfv) + mfv->mfvs[i].offset), mfv->typLen, mfv->typByVal, cur_capacity); if (cur_size > cur_capacity) { elog(ERROR, "invalid transition state for mfvsketch"); } } }
/*! * Initialize an mfv sketch * \param max_mfvs the number of "bins" in the histogram * \param typOid the type ID for the column */ bytea *mfv_init_transval(int max_mfvs, Oid typOid) { int initial_size; bool typIsVarLen; bytea * transblob; mfvtransval *transval; /* * initialize mfvtransval, using palloc0 to zero it out. * if typlen is positive (fixed), size chosen accurately. * Else we'll do a conservative estimate of 16 bytes, and repalloc as needed. */ if ((initial_size = get_typlen(typOid)) > 0) initial_size *= max_mfvs*get_typlen(typOid); else /* guess */ initial_size = max_mfvs*16; transblob = (bytea *)palloc0(MFV_TRANSVAL_SZ(max_mfvs) + initial_size); SET_VARSIZE(transblob, MFV_TRANSVAL_SZ(max_mfvs) + initial_size); transval = (mfvtransval *)VARDATA(transblob); transval->max_mfvs = max_mfvs; transval->next_mfv = 0; transval->next_offset = MFV_TRANSVAL_SZ(max_mfvs)-VARHDRSZ; transval->typOid = typOid; getTypeOutputInfo(transval->typOid, &(transval->outFuncOid), &(typIsVarLen)); transval->typLen = get_typlen(transval->typOid); transval->typByVal = get_typbyval(transval->typOid); if (!transval->outFuncOid) { /* no outFunc for this type! */ elog(ERROR, "no outFunc for type %d", transval->typOid); } return(transblob); }
/* * create_tl_element-- * Creates a target list entry node and its associated (resdom var) pair * with its resdom number equal to 'resdomno' and the joinlist field set * to 'joinlist'. * * RETURNS: newly created tlist-entry * CREATES: new targetlist entry (always). */ TargetEntry* create_tl_element(Var *var, int resdomno) { TargetEntry *tlelement= makeNode(TargetEntry); tlelement->resdom = makeResdom(resdomno, var->vartype, get_typlen(var->vartype), NULL, (Index)0, (Oid)0, 0); tlelement->expr = (Node*)var; return(tlelement); }
/* * get_typavgwidth * * Given a type OID and a typmod value (pass -1 if typmod is unknown), * estimate the average width of values of the type. This is used by * the planner, which doesn't require absolutely correct results; * it's OK (and expected) to guess if we don't know for sure. */ int32 get_typavgwidth(Oid typid, int32 typmod) { int typlen = get_typlen(typid); int32 maxwidth; /* * Easy if it's a fixed-width type */ if (typlen > 0) return typlen; /* * type_maximum_size knows the encoding of typmod for some datatypes; * don't duplicate that knowledge here. */ maxwidth = type_maximum_size(typid, typmod); if (maxwidth > 0) { /* * For BPCHAR, the max width is also the only width. Otherwise we * need to guess about the typical data width given the max. A sliding * scale for percentage of max width seems reasonable. */ if (typid == BPCHAROID) return maxwidth; if (maxwidth <= 32) return maxwidth; /* assume full width */ if (maxwidth < 1000) return 32 + (maxwidth - 32) / 2; /* assume 50% */ /* * Beyond 1000, assume we're looking at something like * "varchar(10000)" where the limit isn't actually reached often, and * use a fixed estimate. */ return 32 + (1000 - 32) / 2; } /* * Ooops, we have no idea ... wild guess time. */ return 32; }
/* check whether the content in the given bytea is safe for mfvtransval */ void check_mfvtransval(bytea *storage) { size_t left_len = VARSIZE(storage); Oid outFuncOid; bool typIsVarLen; mfvtransval *mfv = NULL; if (left_len < VARHDRSZ + sizeof(mfvtransval)) { elog(ERROR, "invalid transition state for mfvsketch"); } mfv = (mfvtransval*)VARDATA(storage); left_len -= VARHDRSZ + sizeof(mfvtransval); if (mfv->next_mfv > mfv->max_mfvs) { elog(ERROR, "invalid transition state for mfvsketch"); } if (mfv->next_offset + VARHDRSZ > VARSIZE(storage)) { elog(ERROR, "invalid transition state for mfvsketch"); } if (InvalidOid == mfv->typOid) { elog(ERROR, "invalid transition state for mfvsketch"); } getTypeOutputInfo(mfv->typOid, &outFuncOid, &typIsVarLen); if (mfv->outFuncOid != outFuncOid || mfv->typLen != get_typlen(mfv->typOid) || mfv->typByVal != get_typbyval(mfv->typOid)) { elog(ERROR, "invalid transition state for mfvsketch"); } if (left_len < sizeof(offsetcnt)*mfv->max_mfvs) { elog(ERROR, "invalid transition state for mfvsketch"); } }
Datum xmlelement(PG_FUNCTION_ARGS) { Datum nameText; ArrayType *attrs = NULL; char *elName; unsigned int nameLen, resSizeMax; unsigned int childSize = 0; char *c, *result, *resData, *resCursor, *nameDst; XMLCompNodeHdr element; XMLNodeOffset *rootOffPtr; bool nameFirstChar = true; char **attrNames = NULL; char **attrValues = NULL; char *attrValFlags = NULL; XMLNodeHdr *attrNodes = NULL; XMLNodeHdr child = NULL; char **newNds = NULL; char *newNd = NULL; unsigned int attrCount = 0; unsigned int attrsSizeTotal = 0; unsigned short childCount = 0; if (PG_ARGISNULL(0)) { elog(ERROR, "invalid element name"); } nameText = PG_GETARG_DATUM(0); elName = TextDatumGetCString(nameText); nameLen = strlen(elName); if (nameLen == 0) { elog(ERROR, "invalid element name"); } if (!PG_ARGISNULL(1)) { int *dims; Oid elType, arrType; int16 arrLen, elLen; bool elByVal, elIsNull; char elAlign; unsigned int i; attrs = PG_GETARG_ARRAYTYPE_P(1); if (ARR_NDIM(attrs) != 2) { elog(ERROR, "attributes must be passed in 2 dimensional array"); } dims = ARR_DIMS(attrs); if (dims[1] != 2) { elog(ERROR, "the second dimension of attribute array must be 2"); } attrCount = dims[0]; Assert(attrCount > 0); elType = attrs->elemtype; arrType = get_array_type(elType); arrLen = get_typlen(arrType); Assert(arrType != InvalidOid); get_typlenbyvalalign(elType, &elLen, &elByVal, &elAlign); attrNames = (char **) palloc(attrCount * sizeof(char *)); attrValues = (char **) palloc(attrCount * sizeof(char *)); attrValFlags = (bool *) palloc(attrCount * sizeof(char)); for (i = 1; i <= attrCount; i++) { int subscrName[] = {i, 1}; int subscrValue[] = {i, 2}; Datum elDatum; char *nameStr, *valueStr; bool valueHasRefs = false; elDatum = array_ref(attrs, 2, subscrName, arrLen, elLen, elByVal, elAlign, &elIsNull); if (elIsNull) { elog(ERROR, "attribute name must not be null"); } nameStr = text_to_cstring(DatumGetTextP(elDatum)); if (strlen(nameStr) == 0) { elog(ERROR, "attribute name must be a string of non-zero length"); } else { /* Check validity of characters. */ char *c = nameStr; int cWidth = pg_utf_mblen((unsigned char *) c); if (!XNODE_VALID_NAME_START(c)) { elog(ERROR, "attribute name starts with invalid character"); } do { c += cWidth; cWidth = pg_utf_mblen((unsigned char *) c); } while (XNODE_VALID_NAME_CHAR(c)); if (*c != '\0') { elog(ERROR, "invalid character in attribute name"); } } /* Check uniqueness of the attribute name. */ if (i > 1) { unsigned short j; for (j = 0; j < (i - 1); j++) { if (strcmp(nameStr, attrNames[j]) == 0) { elog(ERROR, "attribute name '%s' is not unique", nameStr); } } } elDatum = array_ref(attrs, 2, subscrValue, arrLen, elLen, elByVal, elAlign, &elIsNull); if (elIsNull) { elog(ERROR, "attribute value must not be null"); } valueStr = text_to_cstring(DatumGetTextP(elDatum)); attrValFlags[i - 1] = 0; if (strlen(valueStr) > 0) { XMLNodeParserStateData state; char *valueStrOrig = valueStr; /* Parse the value and check validity. */ initXMLParserState(&state, valueStr, true); valueStr = readXMLAttValue(&state, true, &valueHasRefs); /* * If the value contains quotation mark, then apostrophe is * the delimiter. */ if (strchr(valueStr, XNODE_CHAR_QUOTMARK) != NULL) { attrValFlags[i - 1] |= XNODE_ATTR_APOSTROPHE; } finalizeXMLParserState(&state); pfree(valueStrOrig); } attrNames[i - 1] = nameStr; attrValues[i - 1] = valueStr; if (valueHasRefs) { attrValFlags[i - 1] |= XNODE_ATTR_CONTAINS_REF; } attrsSizeTotal += sizeof(XMLNodeHdrData) + strlen(nameStr) + strlen(valueStr) + 2; } } if (!PG_ARGISNULL(2)) { Datum childNodeDatum = PG_GETARG_DATUM(2); xmlnode childRaw = (xmlnode) PG_DETOAST_DATUM(childNodeDatum); child = XNODE_ROOT(childRaw); if (child->kind == XMLNODE_DOC_FRAGMENT) { childSize = getXMLNodeSize(child, true) - getXMLNodeSize(child, false); } else { childSize = getXMLNodeSize(child, true); } } /* Make sure the element name is valid. */ c = elName; while (*c != '\0') { if ((nameFirstChar && !XNODE_VALID_NAME_START(c)) || (!nameFirstChar && !XNODE_VALID_NAME_CHAR(c))) { elog(ERROR, "unrecognized character '%c' in element name", *c); } if (nameFirstChar) { nameFirstChar = false; } c += pg_utf_mblen((unsigned char *) c); }; if (child != NULL) { if (child->kind == XMLNODE_DOC_FRAGMENT) { childCount = ((XMLCompNodeHdr) child)->children; } else { childCount = 1; } } /* * It's hard to determine the byte width of references until the copying * has finished. Therefore we assume the worst case: 4 bytes per * reference. */ resSizeMax = VARHDRSZ + attrsSizeTotal + childSize + (attrCount + childCount) * 4 + sizeof(XMLCompNodeHdrData) + nameLen + 1 + sizeof(XMLNodeOffset); result = (char *) palloc(resSizeMax); resCursor = resData = VARDATA(result); if (attrCount > 0) { /* Copy attributes. */ unsigned short i; Assert(attrNames != NULL && attrValues != NULL && attrValFlags != NULL); attrNodes = (XMLNodeHdr *) palloc(attrCount * sizeof(XMLNodeHdr)); for (i = 0; i < attrCount; i++) { XMLNodeHdr attrNode = (XMLNodeHdr) resCursor; char *name = attrNames[i]; unsigned int nameLen = strlen(name); char *value = attrValues[i]; unsigned int valueLen = strlen(value); attrNodes[i] = attrNode; attrNode->kind = XMLNODE_ATTRIBUTE; attrNode->flags = attrValFlags[i]; if (xmlAttrValueIsNumber(value)) { attrNode->flags |= XNODE_ATTR_NUMBER; } resCursor = XNODE_CONTENT(attrNode); memcpy(resCursor, name, nameLen); resCursor += nameLen; *(resCursor++) = '\0'; pfree(name); memcpy(resCursor, value, valueLen); resCursor += valueLen; *(resCursor++) = '\0'; pfree(value); } pfree(attrNames); pfree(attrValues); pfree(attrValFlags); } if (child != NULL) { XMLNodeKind k = child->kind; /* * Check if the node to be inserted is of a valid kind. If the node is * document fragment, its assumed that invalid node kinds are never * added. Otherwise we'd have to check the node fragment (recursively) * not only here. */ if (k != XMLNODE_DOC_FRAGMENT) { if (k == XMLNODE_DOC || k == XMLNODE_DTD || k == XMLNODE_ATTRIBUTE) { elog(ERROR, "the nested node must not be %s", getXMLNodeKindStr(k)); } } copyXMLNodeOrDocFragment(child, childSize, &resCursor, &newNd, &newNds); } element = (XMLCompNodeHdr) resCursor; element->common.kind = XMLNODE_ELEMENT; element->common.flags = (child == NULL) ? XNODE_EMPTY : 0; element->children = attrCount + childCount; if (childCount > 0 || attrCount > 0) { XMLNodeOffset childOff, childOffMax; char bwidth; char *refPtr; /* Save relative offset(s) of the child node(s). */ if (attrCount > 0) { childOffMax = (char *) element - resData; } else if (childCount > 0) { if (child->kind == XMLNODE_DOC_FRAGMENT) { Assert(newNds != NULL); childOffMax = (char *) element - newNds[0]; } else { childOffMax = (char *) element - newNd; } } else { childOffMax = 0; } bwidth = getXMLNodeOffsetByteWidth(childOffMax); XNODE_SET_REF_BWIDTH(element, bwidth); refPtr = XNODE_FIRST_REF(element); if (attrCount > 0) { unsigned short i; /* The attribute references first... */ for (i = 0; i < attrCount; i++) { XMLNodeHdr node = attrNodes[i]; childOff = (char *) element - (char *) node; writeXMLNodeOffset(childOff, &refPtr, bwidth, true); } pfree(attrNodes); } if (childCount > 0) { /* ...followed by those of the other children. */ if (child->kind == XMLNODE_DOC_FRAGMENT) { unsigned short i; for (i = 0; i < childCount; i++) { childOff = (char *) element - newNds[i]; writeXMLNodeOffset(childOff, &refPtr, bwidth, true); } pfree(newNds); } else { childOff = (char *) element - newNd; writeXMLNodeOffset(childOff, &refPtr, bwidth, true); } } } /* And finally set the element name. */ nameDst = XNODE_ELEMENT_NAME(element); memcpy(nameDst, elName, nameLen); nameDst[nameLen] = '\0'; resCursor = nameDst + strlen(elName) + 1; SET_VARSIZE(result, (char *) resCursor - result + sizeof(XMLNodeOffset)); rootOffPtr = XNODE_ROOT_OFFSET_PTR(result); *rootOffPtr = (char *) element - resData; PG_RETURN_POINTER(result); }
/* * pgstrom_create_param_buffer * * It construct a param-buffer on the shared memory segment, according to * the supplied Const/Param list. Its initial reference counter is 1, so * this buffer can be released using pgstrom_put_param_buffer(). */ kern_parambuf * pgstrom_create_kern_parambuf(List *used_params, ExprContext *econtext) { StringInfoData str; kern_parambuf *kpbuf; char padding[STROMALIGN_LEN]; ListCell *cell; Size offset; int index = 0; int nparams = list_length(used_params); /* seek to the head of variable length field */ offset = STROMALIGN(offsetof(kern_parambuf, poffset[nparams])); initStringInfo(&str); enlargeStringInfo(&str, offset); memset(str.data, 0, offset); str.len = offset; /* walks on the Para/Const list */ foreach (cell, used_params) { Node *node = lfirst(cell); if (IsA(node, Const)) { Const *con = (Const *) node; kpbuf = (kern_parambuf *)str.data; if (con->constisnull) kpbuf->poffset[index] = 0; /* null */ else { kpbuf->poffset[index] = str.len; if (con->constlen > 0) appendBinaryStringInfo(&str, (char *)&con->constvalue, con->constlen); else appendBinaryStringInfo(&str, DatumGetPointer(con->constvalue), VARSIZE(con->constvalue)); } } else if (IsA(node, Param)) { ParamListInfo param_info = econtext->ecxt_param_list_info; Param *param = (Param *) node; if (param_info && param->paramid > 0 && param->paramid <= param_info->numParams) { ParamExternData *prm = ¶m_info->params[param->paramid - 1]; /* give hook a chance in case parameter is dynamic */ if (!OidIsValid(prm->ptype) && param_info->paramFetch != NULL) (*param_info->paramFetch) (param_info, param->paramid); kpbuf = (kern_parambuf *)str.data; if (!OidIsValid(prm->ptype)) { elog(INFO, "debug: Param has no particular data type"); kpbuf->poffset[index++] = 0; /* null */ continue; } /* safety check in case hook did something unexpected */ if (prm->ptype != param->paramtype) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)", param->paramid, format_type_be(prm->ptype), format_type_be(param->paramtype)))); if (prm->isnull) kpbuf->poffset[index] = 0; /* null */ else { int typlen = get_typlen(prm->ptype); if (typlen == 0) elog(ERROR, "cache lookup failed for type %u", prm->ptype); if (typlen > 0) appendBinaryStringInfo(&str, (char *)&prm->value, typlen); else appendBinaryStringInfo(&str, DatumGetPointer(prm->value), VARSIZE(prm->value)); } } } else elog(ERROR, "unexpected node: %s", nodeToString(node)); /* alignment */ if (STROMALIGN(str.len) != str.len) appendBinaryStringInfo(&str, padding, STROMALIGN(str.len) - str.len); index++; }