/* * execTuplesHashPrepare * Look up the equality and hashing functions needed for a TupleHashTable. * * This is similar to execTuplesMatchPrepare, but we also need to find the * hash functions associated with the equality operators. *eqfunctions and * *hashfunctions receive the palloc'd result arrays. */ void execTuplesHashPrepare(TupleDesc tupdesc, int numCols, AttrNumber *matchColIdx, FmgrInfo **eqfunctions, FmgrInfo **hashfunctions) { int i; *eqfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo)); *hashfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo)); for (i = 0; i < numCols; i++) { AttrNumber att = matchColIdx[i]; Oid typid = tupdesc->attrs[att - 1]->atttypid; Operator optup; Oid eq_opr; Oid eq_function; Oid hash_function; optup = equality_oper(typid, false); eq_opr = oprid(optup); eq_function = oprfuncid(optup); ReleaseSysCache(optup); hash_function = get_op_hash_function(eq_opr); if (!OidIsValid(hash_function)) /* should not happen */ elog(ERROR, "could not find hash function for hash operator %u", eq_opr); fmgr_info(eq_function, &(*eqfunctions)[i]); fmgr_info(hash_function, &(*hashfunctions)[i]); } }
/* * execTuplesHashPrepare * Look up the equality and hashing functions needed for a TupleHashTable. * * This is similar to execTuplesMatchPrepare, but we also need to find the * hash functions associated with the equality operators. *eqfunctions and * *hashfunctions receive the palloc'd result arrays. */ void execTuplesHashPrepareSGB(TupleDesc tupdesc, int numCols, AttrNumber *matchColIdx, FmgrInfo **eqfunctions, FmgrInfo **hashfunctions, FmgrInfo **ltfunctions, FmgrInfo **minusfunctions) { int i; *eqfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo)); *hashfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo)); *ltfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo)); *minusfunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo)); for (i = 0; i < numCols; i++) { AttrNumber att = matchColIdx[i]; Oid typid = tupdesc->attrs[att - 1]->atttypid; Operator optup; Oid eq_opr; Oid eq_function; Oid hash_function; Oid lt_function; Oid minus_function; /*GIVEN A TYPE GET THE = FUNCTION*/ /*eq_function = equality_oper_funcid(typid);*/ optup = equality_oper(typid, false); eq_opr = oprid(optup); eq_function = oprfuncid(optup); ReleaseSysCache(optup); /*GIVEN A TYPE GET THE HASH FUNCTION*/ hash_function = get_op_hash_function(eq_opr); if (!OidIsValid(hash_function)) /* should not happen */ elog(ERROR, "could not find hash function for hash operator %u", eq_opr); /*GIVEN A TYPE GET THE < FUNCTION*/ optup = ordering_oper(typid, false); lt_function = oprfuncid(optup); ReleaseSysCache(optup); /*GIVEN A TYPE GET THE - FUNCTION*/ optup = minus_oper(typid, false); /*minus_oper WAS ADDED BY YASIN*/ minus_function = oprfuncid(optup); /*get the function from the operator tuple*/ ReleaseSysCache(optup); fmgr_info(eq_function, &(*eqfunctions)[i]); fmgr_info(hash_function, &(*hashfunctions)[i]); fmgr_info(lt_function, &(*ltfunctions)[i]); fmgr_info(minus_function, &(*minusfunctions)[i]); } }
/* * reverse_ordering_oper_opid - convenience routine for oprid(reverse_ordering_oper()) */ Oid reverse_ordering_oper_opid(Oid argtype) { Operator optup; Oid result; optup = reverse_ordering_oper(argtype, false); result = oprid(optup); ReleaseSysCache(optup); return result; }
/* * ordering_oper_opid - convenience routine for oprid(ordering_oper()) * * This was formerly called any_ordering_op() */ Oid ordering_oper_opid(Oid argtype) { Operator optup; Oid result; optup = ordering_oper(argtype, false); result = oprid(optup); ReleaseOperator(optup); return result; }
/* * ordering_oper_opid - convenience routine for oprid(equality_oper()) */ Oid equality_oper_opid(Oid argtype) { Operator optup; Oid result; optup = equality_oper(argtype, false); result = oprid(optup); ReleaseOperator(optup); return result; }
/* compatible_oper_opid() -- get OID of a binary operator * * This is a convenience routine that extracts only the operator OID * from the result of compatible_oper(). InvalidOid is returned if the * lookup fails and noError is true. */ Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError) { Operator optup; Oid result; optup = compatible_oper(NULL, op, arg1, arg2, noError, -1); if (optup != NULL) { result = oprid(optup); ReleaseSysCache(optup); return result; } return InvalidOid; }
/* * make_scalar_array_op() * Build expression tree for "scalar op ANY/ALL (array)" construct. */ Expr * make_scalar_array_op(ParseState *pstate, List *opname, bool useOr, Node *ltree, Node *rtree, int location) { Oid ltypeId, rtypeId, atypeId, res_atypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; List *args; Oid rettype; ScalarArrayOpExpr *result; ltypeId = exprType(ltree); atypeId = exprType(rtree); /* * The right-hand input of the operator will be the element type of the * array. However, if we currently have just an untyped literal on the * right, stay with that and hope we can resolve the operator. */ if (atypeId == UNKNOWNOID) rtypeId = UNKNOWNOID; else { rtypeId = get_base_element_type(atypeId); if (!OidIsValid(rtypeId)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires array on right side"), parser_errposition(pstate, location))); } /* Now resolve the operator */ tup = oper(pstate, opname, ltypeId, rtypeId, false, location); opform = (Form_pg_operator) GETSTRUCT(tup); /* Check it's not a shell */ if (!RegProcedureIsValid(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator is only a shell: %s", op_signature_string(opname, opform->oprkind, opform->oprleft, opform->oprright)), parser_errposition(pstate, location))); args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; /* * enforce consistency with polymorphic argument and return types, * possibly adjusting return type or declared_arg_types (which will be * used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, 2, opform->oprresult, false); /* * Check that operator result is boolean */ if (rettype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator to yield boolean"), parser_errposition(pstate, location))); if (get_func_retset(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator not to return a set"), parser_errposition(pstate, location))); /* * Now switch back to the array type on the right, arranging for any * needed cast to be applied. Beware of polymorphic operators here; * enforce_generic_type_consistency may or may not have replaced a * polymorphic type with a real one. */ if (IsPolymorphicType(declared_arg_types[1])) { /* assume the actual array type is OK */ res_atypeId = atypeId; } else { res_atypeId = get_array_type(declared_arg_types[1]); if (!OidIsValid(res_atypeId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(declared_arg_types[1])), parser_errposition(pstate, location))); } actual_arg_types[1] = atypeId; declared_arg_types[1] = res_atypeId; /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(ScalarArrayOpExpr); result->opno = oprid(tup); result->opfuncid = opform->oprcode; result->useOr = useOr; /* inputcollid will be set by parse_collate.c */ result->args = args; result->location = location; ReleaseSysCache(tup); return (Expr *) result; }
/* * make_op() * Operator expression construction. * * Transform operator expression ensuring type compatibility. * This is where some type conversion happens. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */ Expr * make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, int location) { Oid ltypeId, rtypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; int nargs; List *args; Oid rettype; OpExpr *result; /* Select the operator */ if (rtree == NULL) { /* right operator */ ltypeId = exprType(ltree); rtypeId = InvalidOid; tup = right_oper(pstate, opname, ltypeId, false, location); } else if (ltree == NULL) { /* left operator */ rtypeId = exprType(rtree); ltypeId = InvalidOid; tup = left_oper(pstate, opname, rtypeId, false, location); } else { /* otherwise, binary operator */ ltypeId = exprType(ltree); rtypeId = exprType(rtree); tup = oper(pstate, opname, ltypeId, rtypeId, false, location); } opform = (Form_pg_operator) GETSTRUCT(tup); /* Check it's not a shell */ if (!RegProcedureIsValid(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator is only a shell: %s", op_signature_string(opname, opform->oprkind, opform->oprleft, opform->oprright)), parser_errposition(pstate, location))); /* Do typecasting and build the expression tree */ if (rtree == NULL) { /* right operator */ args = list_make1(ltree); actual_arg_types[0] = ltypeId; declared_arg_types[0] = opform->oprleft; nargs = 1; } else if (ltree == NULL) { /* left operator */ args = list_make1(rtree); actual_arg_types[0] = rtypeId; declared_arg_types[0] = opform->oprright; nargs = 1; } else { /* otherwise, binary operator */ args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; nargs = 2; } /* * enforce consistency with polymorphic argument and return types, * possibly adjusting return type or declared_arg_types (which will be * used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, nargs, opform->oprresult, false); /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(OpExpr); result->opno = oprid(tup); result->opfuncid = opform->oprcode; result->opresulttype = rettype; result->opretset = get_func_retset(opform->oprcode); /* opcollid and inputcollid will be set by parse_collate.c */ result->args = args; result->location = location; ReleaseSysCache(tup); return (Expr *) result; }
/* * make_op_expr() * Build operator expression using an already-looked-up operator. * * As with coerce_type, pstate may be NULL if no special unknown-Param * processing is wanted. */ static Expr * make_op_expr(ParseState *pstate, Operator op, Node *ltree, Node *rtree, Oid ltypeId, Oid rtypeId) { Form_pg_operator opform = (Form_pg_operator) GETSTRUCT(op); Oid actual_arg_types[2]; Oid declared_arg_types[2]; int nargs; List *args; Oid rettype; OpExpr *result; if (rtree == NULL) { /* right operator */ args = list_make1(ltree); actual_arg_types[0] = ltypeId; declared_arg_types[0] = opform->oprleft; nargs = 1; } else if (ltree == NULL) { /* left operator */ args = list_make1(rtree); actual_arg_types[0] = rtypeId; declared_arg_types[0] = opform->oprright; nargs = 1; } else { /* otherwise, binary operator */ args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; nargs = 2; } /* * enforce consistency with ANYARRAY and ANYELEMENT argument and return * types, possibly adjusting return type or declared_arg_types (which will * be used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, nargs, opform->oprresult); /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(OpExpr); result->opno = oprid(op); result->opfuncid = InvalidOid; result->opresulttype = rettype; result->opretset = get_func_retset(opform->oprcode); result->args = args; return (Expr *) result; }
/* * _bitmap_init_buildstate() -- initialize the build state before building * a bitmap index. */ void _bitmap_init_buildstate(Relation index, BMBuildState *bmstate) { MIRROREDLOCK_BUFMGR_DECLARE; BMMetaPage mp; HASHCTL hash_ctl; int hash_flags; int i; Buffer metabuf; /* initialize the build state */ bmstate->bm_tupDesc = RelationGetDescr(index); bmstate->bm_tidLocsBuffer = (BMTidBuildBuf *) palloc(sizeof(BMTidBuildBuf)); bmstate->bm_tidLocsBuffer->byte_size = 0; bmstate->bm_tidLocsBuffer->lov_blocks = NIL; bmstate->bm_tidLocsBuffer->max_lov_block = InvalidBlockNumber; // -------- MirroredLock ---------- MIRROREDLOCK_BUFMGR_LOCK; metabuf = _bitmap_getbuf(index, BM_METAPAGE, BM_READ); mp = _bitmap_get_metapage_data(index, metabuf); _bitmap_open_lov_heapandindex(index, mp, &(bmstate->bm_lov_heap), &(bmstate->bm_lov_index), RowExclusiveLock); _bitmap_relbuf(metabuf); MIRROREDLOCK_BUFMGR_UNLOCK; // -------- MirroredLock ---------- cur_bmbuild = (BMBuildHashData *)palloc(sizeof(BMBuildHashData)); cur_bmbuild->hash_funcs = (FmgrInfo *) palloc(sizeof(FmgrInfo) * bmstate->bm_tupDesc->natts); cur_bmbuild->eq_funcs = (FmgrInfo *) palloc(sizeof(FmgrInfo) * bmstate->bm_tupDesc->natts); cur_bmbuild->hash_func_is_strict = (bool *) palloc(sizeof(bool) * bmstate->bm_tupDesc->natts); for (i = 0; i < bmstate->bm_tupDesc->natts; i++) { Oid typid = bmstate->bm_tupDesc->attrs[i]->atttypid; Operator optup; Oid eq_opr; Oid eq_function; Oid left_hash_function; Oid right_hash_function; optup = equality_oper(typid, false); eq_opr = oprid(optup); eq_function = oprfuncid(optup); ReleaseOperator(optup); if (!get_op_hash_functions(eq_opr, &left_hash_function, &right_hash_function)) { pfree(cur_bmbuild); cur_bmbuild = NULL; break; } Assert(left_hash_function == right_hash_function); fmgr_info(eq_function, &cur_bmbuild->eq_funcs[i]); fmgr_info(right_hash_function, &cur_bmbuild->hash_funcs[i]); cur_bmbuild->hash_func_is_strict[i] = func_strict(right_hash_function); } if (cur_bmbuild) { cur_bmbuild->natts = bmstate->bm_tupDesc->natts; cur_bmbuild->tmpcxt = AllocSetContextCreate(CurrentMemoryContext, "Bitmap build temp space", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* setup the hash table */ MemSet(&hash_ctl, 0, sizeof(hash_ctl)); /** * Reserve enough space for the hash key header and then the data segments (values followed by nulls) */ hash_ctl.keysize = MAXALIGN(sizeof(BMBuildHashKey)) + MAXALIGN(sizeof(Datum) * cur_bmbuild->natts) + MAXALIGN(sizeof(bool) * cur_bmbuild->natts); hash_ctl.entrysize = hash_ctl.keysize + sizeof(BMBuildLovData) + 200; hash_ctl.hash = build_hash_key; hash_ctl.match = build_match_key; hash_ctl.keycopy = build_keycopy; hash_ctl.hcxt = AllocSetContextCreate(CurrentMemoryContext, "Bitmap build hash table", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); cur_bmbuild->hash_cxt = hash_ctl.hcxt; hash_flags = HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT | HASH_KEYCOPY; bmstate->lovitem_hash = hash_create("Bitmap index build lov item hash", 100, &hash_ctl, hash_flags); bmstate->lovitem_hashKeySize = hash_ctl.keysize; } else { int attno; bmstate->lovitem_hash = NULL; bmstate->lovitem_hashKeySize = 0; bmstate->bm_lov_scanKeys = (ScanKey)palloc0(bmstate->bm_tupDesc->natts * sizeof(ScanKeyData)); for (attno = 0; attno < bmstate->bm_tupDesc->natts; attno++) { RegProcedure opfuncid; Oid atttypid; atttypid = bmstate->bm_tupDesc->attrs[attno]->atttypid; opfuncid = equality_oper_funcid(atttypid); ScanKeyEntryInitialize(&(bmstate->bm_lov_scanKeys[attno]), SK_ISNULL, attno + 1, BTEqualStrategyNumber, InvalidOid, opfuncid, 0); } bmstate->bm_lov_scanDesc = index_beginscan(bmstate->bm_lov_heap, bmstate->bm_lov_index, ActiveSnapshot, bmstate->bm_tupDesc->natts, bmstate->bm_lov_scanKeys); } /* * We need to log index creation in WAL iff WAL archiving is enabled * AND it's not a temp index. Currently, since building an index * writes page to the shared buffer, we can't disable WAL archiving. * We will add this shortly. */ bmstate->use_wal = !XLog_UnconvertedCanBypassWal() && !index->rd_istemp; }
/* * make_scalar_array_op() * Build expression tree for "scalar op ANY/ALL (array)" construct. */ Expr * make_scalar_array_op(ParseState *pstate, List *opname, bool useOr, Node *ltree, Node *rtree, int location) { Oid ltypeId, rtypeId, atypeId, res_atypeId; Operator tup; Form_pg_operator opform; Oid actual_arg_types[2]; Oid declared_arg_types[2]; List *args; Oid rettype; ScalarArrayOpExpr *result; ltypeId = exprType(ltree); atypeId = exprType(rtree); /* * The right-hand input of the operator will be the element type of the * array. However, if we currently have just an untyped literal on the * right, stay with that and hope we can resolve the operator. */ if (atypeId == UNKNOWNOID) rtypeId = UNKNOWNOID; else { rtypeId = get_element_type(atypeId); if (!OidIsValid(rtypeId)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires array on right side"), errOmitLocation(true), parser_errposition(pstate, location))); } /* Now resolve the operator */ tup = oper(pstate, opname, ltypeId, rtypeId, false, location); opform = (Form_pg_operator) GETSTRUCT(tup); args = list_make2(ltree, rtree); actual_arg_types[0] = ltypeId; actual_arg_types[1] = rtypeId; declared_arg_types[0] = opform->oprleft; declared_arg_types[1] = opform->oprright; /* * enforce consistency with ANYARRAY and ANYELEMENT argument and return * types, possibly adjusting return type or declared_arg_types (which will * be used as the cast destination by make_fn_arguments) */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, 2, opform->oprresult); /* * Check that operator result is boolean */ if (rettype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator to yield boolean"), errOmitLocation(true), parser_errposition(pstate, location))); if (get_func_retset(opform->oprcode)) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("op ANY/ALL (array) requires operator not to return a set"), errOmitLocation(true), parser_errposition(pstate, location))); /* * Now switch back to the array type on the right, arranging for any * needed cast to be applied. */ res_atypeId = get_array_type(declared_arg_types[1]); if (!OidIsValid(res_atypeId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(declared_arg_types[1])), errOmitLocation(true), parser_errposition(pstate, location))); actual_arg_types[1] = atypeId; declared_arg_types[1] = res_atypeId; /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(ScalarArrayOpExpr); result->opno = oprid(tup); result->opfuncid = InvalidOid; result->useOr = useOr; result->args = args; ReleaseOperator(tup); return (Expr *) result; }