static void handle_gps_data(stlv_packet pack, element_handle handle) { char type_buf[MAX_ELEMENT_TYPE_BUFSIZE]; uint16_t gps_spd = 0xffff; uint16_t gps_alt = 0xffff; uint32_t gps_dis = 0; element_handle element = get_first_sub_element(pack, handle); while (IS_VALID_STLV_HANDLE(element)) { int type_len = get_element_type(pack, element, type_buf, sizeof(type_buf)); switch (type_buf[0]) { case SUB_TYPE_ACTIVITY_ALT: { uint8_t* data = get_element_data_buffer(pack, element, type_buf, type_len); uint8_t data_size = get_element_data_size(pack, element, type_buf, type_len); log_info("gps.alt=%d:%02x %02x\n", data_size, data[0], data[1]); //gps_alt = *((uint16_t*)data); //gps_alt = htons(gps_alt); gps_alt = READ_NET_16(data, 0); } break; case SUB_TYPE_ACTIVITY_SPD: { uint8_t* data = get_element_data_buffer(pack, element, type_buf, type_len); uint8_t data_size = get_element_data_size(pack, element, type_buf, type_len); log_info("gps.spd=%d:%02x %02x\n", data_size, data[0], data[1]); //gps_spd = *((uint16_t*)data); //gps_spd = htons(gps_spd); gps_spd = READ_NET_16(data, 0); } break; case SUB_TYPE_ACTIVITY_DIS: { uint8_t* data = get_element_data_buffer(pack, element, type_buf, type_len); uint8_t data_size = get_element_data_size(pack, element, type_buf, type_len); log_info("gps.dis=%d:%02x %02x %02x %02x\n", data_size, data[0], data[1], data[2], data[3]); gps_dis = READ_NET_32(data, 0); } break; } element = get_next_sub_element(pack, handle, element); } handle_gps_info(gps_spd, gps_alt, gps_dis); }
/* * equality_oper - identify a suitable equality operator for a datatype * * On failure, return NULL if noError, else report a standard error */ Operator equality_oper(Oid argtype, bool noError) { TypeCacheEntry *typentry; Oid oproid; Operator optup; /* * Look for an "=" operator for the datatype. We require it to be an * exact or binary-compatible match, since most callers are not prepared * to cope with adding any run-time type coercion steps. */ typentry = lookup_type_cache(argtype, TYPECACHE_EQ_OPR); oproid = typentry->eq_opr; /* * If the datatype is an array, then we can use array_eq ... but only if * there is a suitable equality operator for the element type. (This check * is not in the raw typcache.c code ... should it be?) */ if (oproid == ARRAY_EQ_OP) { Oid elem_type = get_element_type(argtype); if (OidIsValid(elem_type)) { optup = equality_oper(elem_type, true); if (optup != NULL) ReleaseOperator(optup); else oproid = InvalidOid; /* element type has no "=" */ } else oproid = InvalidOid; /* bogus array type? */ } if (OidIsValid(oproid)) { optup = fetch_op_tup(oproid, true); return optup; } if (!noError) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not identify an equality operator for type %s", format_type_be(argtype)), errOmitLocation(true))); return NULL; }
bool is_type_subarray(const type &subarray_tp) const { // Uniform dimensions can share one implementation intptr_t this_ndim = get_ndim(), stp_ndim = subarray_tp.get_ndim(); if (this_ndim > stp_ndim) { return get_element_type().is_type_subarray(subarray_tp); } else if (this_ndim == stp_ndim) { return (*this) == (*subarray_tp.extended()); } else { return false; } }
Datum array_agg_distinct_type_by_array(PG_FUNCTION_ARGS) { /* get element type for the dummy second parameter (anyarray item) */ Oid input_type = get_fn_expr_argtype(fcinfo->flinfo, 1), element_type = get_element_type(input_type); CHECK_AGG_CONTEXT("count_distinct", fcinfo); /* return empty array if the state was not initialized */ if (PG_ARGISNULL(0)) PG_RETURN_DATUM(PointerGetDatum(construct_empty_array(element_type))); return build_array((element_set_t *)PG_GETARG_POINTER(0), element_type); }
void single_star::first_roche_lobe_contact_story(stellar_type accretor) { char info_line[MAX_STORY_LINE_LENGTH]; real time = get_current_time(); sprintf(info_line, "%s_%s_%s_RLOF_to_%s_at_time = %6.2f", type_string(get_element_type()), type_string(get_spectral_class(temperature())), type_string(get_luminosity_class(temperature(), luminosity)), type_string(accretor), time); add_story_line(get_node()->get_log_story(), info_line); }
void query_handler::handle() { ::odata::utility::string_t media_type = U("application/json"); auto target = m_request_context->get_query_target(); shared_ptr<mongo_task> ds_task = make_shared<mongo_query_task>(m_request_context); const std::vector<::mongo::BSONObj> &result = ds_task->run(); auto value_builder = make_shared<odata_value_builder>(); auto target_value = value_builder->build_odata_value(target->target_edm_type(), result); uri context_url; odata_context_url_builder context_url_builder(m_model, U("http://localhost:4789")); if (target->target_edm_type()->get_type_kind() == edm_type_kind_t::Collection) { auto collection_type = std::dynamic_pointer_cast<edm_collection_type>(target->target_edm_type()); auto element_type = collection_type->get_element_type(); if (element_type->get_type_kind() == edm_type_kind_t::Entity) { auto target_entity_set = std::dynamic_pointer_cast<edm_entity_set>(target->target_navigation_source()); context_url = context_url_builder.get_context_uri_for_collection_of_entities(target_entity_set); } } else if (target->target_edm_type()->get_type_kind() == edm_type_kind_t::Entity) { auto entity_type = std::dynamic_pointer_cast<edm_entity_type>(target->target_edm_type()); auto target_entity_set = std::dynamic_pointer_cast<edm_entity_set>(target->target_navigation_source()); context_url = context_url_builder.get_context_uri_for_entity(target_entity_set); } if (!context_url.is_empty()) { target_value->set_context_url(context_url); } odata_message_writer writer(m_model, U("http://localhost:4789")); auto content = writer.write_odata_value(target_value); http_response response(status_codes::OK); response.set_body(content, media_type); m_request->reply(response).get(); }
static Datum PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv) { ArrayType *array; int i; Datum *elems; bool *nulls; int len; int lbs; Assert(plrv != Py_None); if (!PySequence_Check(plrv)) PLy_elog(ERROR, "return value of function with array return type is not a Python sequence"); len = PySequence_Length(plrv); elems = palloc(sizeof(*elems) * len); nulls = palloc(sizeof(*nulls) * len); for (i = 0; i < len; i++) { PyObject *obj = PySequence_GetItem(plrv, i); if (obj == Py_None) nulls[i] = true; else { nulls[i] = false; /* * We don't support arrays of row types yet, so the first argument * can be NULL. */ elems[i] = arg->elm->func(arg->elm, -1, obj); } Py_XDECREF(obj); } lbs = 1; array = construct_md_array(elems, nulls, 1, &len, &lbs, get_element_type(arg->typoid), arg->elm->typlen, arg->elm->typbyval, arg->elm->typalign); return PointerGetDatum(array); }
static void handle_file(stlv_packet pack, element_handle handle) { static int s_file_handle = -1; char type_buf[MAX_ELEMENT_TYPE_BUFSIZE]; element_handle element = get_first_sub_element(pack, handle); while (IS_VALID_STLV_HANDLE(element)) { int type_len = get_element_type(pack, element, type_buf, sizeof(type_buf)); switch (type_buf[0]) { case SUB_TYPE_FILE_NAME: { uint8_t* file_name_data = get_element_data_buffer(pack, element, type_buf, type_len); uint8_t file_name_size = get_element_data_size(pack, element, type_buf, type_len); uint8_t temp = file_name_data[file_name_size]; file_name_data[file_name_size] = '\0'; char* file_name = (char*)file_name_data; s_file_handle = handle_file_begin(file_name); log_info("handle_file_begin(%s) return %d\n", file_name, s_file_handle); file_name_data[file_name_size] = temp; } break; case SUB_TYPE_FILE_DATA: { uint8_t* file_data = get_element_data_buffer(pack, element, type_buf, type_len); uint8_t data_size = get_element_data_size(pack, element, type_buf, type_len); log_info("handle_file_data(fd=%d, %d bytes)\n", s_file_handle, data_size); handle_file_data(s_file_handle, file_data, data_size); } break; case SUB_TYPE_FILE_END: log_info("handle_file_end(fd=%d)\n", s_file_handle); handle_file_end(s_file_handle); s_file_handle = 0; break; } element = get_next_sub_element(pack, handle, element); } }
real hyper_giant::add_mass_to_accretor(real mdot, const real dt) { real m_tot = get_total_mass(); if (mdot<0) { /* error << "hyper_giant::add_mass_to_accretor(mdot=" << mdot << ")"<<endl; error << "mdot (" << mdot << ") smaller than zero!" << endl; error << "Action: proceed!" << endl; */ } mdot = accretion_limit(mdot, dt); adjust_accretor_age(mdot); if (relative_mass<get_total_mass() + mdot) relative_mass = get_total_mass() + mdot; envelope_mass += mdot; // Wind mass loss for massive stars (SPZ:July 1998) if (relative_mass >= cnsts.parameters(massive_star_mass_limit)) { // Mass loss constant in time. wind_constant = envelope_mass/(next_update_age-relative_age); wind_constant = max(wind_constant, 0.); cerr << type_string(get_element_type()) << " wind treatment for stars with M >=" << cnsts.parameters(massive_star_mass_limit) << " for " << identity << endl << " M = " << get_total_mass() << " [Msun] " << " Mdot = " << wind_constant << " [Msun/Myr] " << endl; } set_spec_type(Accreting); return mdot; }
void mark (Object *obj) { if (obj == JNULL) return; #ifdef VERIFY_GC assert (is_allocated (obj), GC0); #endif if (is_gc_marked (obj)) return; set_gc_marked (obj); if (is_array (obj)) { if (get_element_type (obj) == T_REFERENCE) { unsigned short i; unsigned short length = get_array_length (obj); REFERENCE *refarr = ref_array (obj); for (i = 0; i < length; i++) mark (refarr[i]); } } else { ClassRecord *classRecord; byte classIndex; classIndex = get_na_class_index (obj); for (;;) { classRecord = get_class_record (classIndex); // Mark fields of type REFERENCE. mark_reference_fields (obj, classRecord); if (classIndex == JAVA_LANG_OBJECT) break; classIndex = classRecord -> parentClass; } } }
/* * moveArrayTypeName * - try to reassign an array type name that the user wants to use. * * The given type name has been discovered to already exist (with the given * OID). If it is an autogenerated array type, change the array type's name * to not conflict. This allows the user to create type "foo" followed by * type "_foo" without problems. (Of course, there are race conditions if * two backends try to create similarly-named types concurrently, but the * worst that can happen is an unnecessary failure --- anything we do here * will be rolled back if the type creation fails due to conflicting names.) * * Note that this must be called *before* calling makeArrayTypeName to * determine the new type's own array type name; else the latter will * certainly pick the same name. * * Returns TRUE if successfully moved the type, FALSE if not. * * We also return TRUE if the given type is a shell type. In this case * the type has not been renamed out of the way, but nonetheless it can * be expected that TypeCreate will succeed. This behavior is convenient * for most callers --- those that need to distinguish the shell-type case * must do their own typisdefined test. */ bool moveArrayTypeName(Oid typeOid, const char *typeName, Oid typeNamespace) { Oid elemOid; char *newname; /* We need do nothing if it's a shell type. */ if (!get_typisdefined(typeOid)) return true; /* Can't change it if it's not an autogenerated array type. */ elemOid = get_element_type(typeOid); if (!OidIsValid(elemOid) || get_array_type(elemOid) != typeOid) return false; /* * OK, use makeArrayTypeName to pick an unused modification of the name. * Note that since makeArrayTypeName is an iterative process, this will * produce a name that it might have produced the first time, had the * conflicting type we are about to create already existed. */ newname = makeArrayTypeName(typeName, typeNamespace); /* Apply the rename */ RenameTypeInternal(typeOid, newname, typeNamespace); /* * We must bump the command counter so that any subsequent use of * makeArrayTypeName sees what we just did and doesn't pick the same name. */ CommandCounterIncrement(); pfree(newname); return true; }
void single_star::star_transformation_story(stellar_type new_type) { char info_line[MAX_STORY_LINE_LENGTH]; stellar_type old_type = get_element_type(); real time = get_current_time(); sprintf(info_line, "%s_to_%s_at_time = %6.2f", type_string(old_type), type_string(new_type), time); add_story_line(get_node()->get_log_story(), info_line); // cerr output for debugging! cerr << endl << get_node()->format_label() << " " << info_line << " Myr (old mass = " << get_total_mass() << ")" << endl; if(is_binary_component()) { #if 0 // This should be fixed some time SPZ:26/02/03 if(get_binary()->obtain_binary_type() == Merged) { cerr << "binary is merged." << endl; } else if(get_binary()->obtain_binary_type() == Disrupted) { cerr << "binary is disrupted, other component: " << endl << type_string(get_companion()->get_element_type()) << endl; } else { cerr << "binary companion: " << type_string(get_companion()->get_element_type()) << endl; } #endif cerr << "binary companion: " << type_string(get_companion()->get_element_type()) << endl; cerr << "parent: " << get_node()->get_parent()->format_label() << endl; } }
Datum transform_eeg(PG_FUNCTION_ARGS) { //the size of the array we are trying to transform int arraySize; // a Datum for the constructred and deconstructed input arrays Datum *intermResult; Datum *input_data; // the final result to return and the input to the function ArrayType *result, *input; Oid element_type, return_type, input_type; //next 6 variables are inputted into get_typlenbyvalalign() and are used for construct and deconstruct array //small int in postgreSQL is int16 int16 return_typelen, input_typelen; bool return_typbyval, input_typbyval; char return_typalign, input_typalign; //the arrays we are transforming. Transforming array in[] into array out[] //fftw_complex, a data structure with real (in[i].re) and imaginary (in[i].im) floating-point components. fftw_complex *in, *out; fftw_plan my_plan; // get input row input = PG_GETARG_ARRAYTYPE_P(0); // get input array element type input_type = ARR_ELEMTYPE(input); //get needed variabels get_typlenbyvalalign(input_type, &input_typelen, &input_typbyval, &input_typalign); // deconstruct inupt array and save the array as Datum input_data deconstruct_array(input, input_type, input_typelen, input_typbyval, input_typalign, &input_data, NULL, &arraySize); // get element type of return vale (Complex[]) element_type = get_fn_expr_rettype(fcinfo->flinfo); // get element type of an element in the return value (Complex) return_type = get_element_type(element_type); //get needed variabels get_typlenbyvalalign(return_type, &return_typelen, &return_typbyval, &return_typalign); // in and out array and plan declarations in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*arraySize); out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex)*arraySize); my_plan = fftw_plan_dft_1d(arraySize, in, out, FFTW_FORWARD, FFTW_ESTIMATE); // set the in variable to the array we got as input. // the real parts are from the input_data array // the imaginary part is set to 0 for (int i = 0; i < arraySize; i++) { in[i][0] = (double) DatumGetInt16(input_data[i]); in[i][1] = 0; } // run the plan fftw_execute(my_plan); // array to store the out array (the transformed in array) intermResult = palloc(sizeof(Datum)*arraySize); // for each variable in the out array. // Create a complex variable then set its real and imaginary party from the processed array // get the datum from the pointer and save it in the result array for(int32 i = 0; i < arraySize; i++) { Complex *temp = palloc(sizeof(Complex)); temp->x = out[i][0]; temp->y = out[i][1]; intermResult[i] = PointerGetDatum(temp); } // construct a result array result = construct_array(intermResult, arraySize, return_type, return_typelen, return_typbyval, return_typalign); // free memory fftw_destroy_plan(my_plan); fftw_free(in); fftw_free(out); pfree(input_data); pfree(intermResult); // return result PG_RETURN_POINTER(result); }
/* * Interpret the function parameter list of a CREATE FUNCTION or * CREATE AGGREGATE statement. * * Input parameters: * parameters: list of FunctionParameter structs * languageOid: OID of function language (InvalidOid if it's CREATE AGGREGATE) * is_aggregate: needed only to determine error handling * queryString: likewise, needed only for error handling * * Results are stored into output parameters. parameterTypes must always * be created, but the other arrays are set to NULL if not needed. * variadicArgType is set to the variadic array type if there's a VARIADIC * parameter (there can be only one); or to InvalidOid if not. * requiredResultType is set to InvalidOid if there are no OUT parameters, * else it is set to the OID of the implied result type. */ void interpret_function_parameter_list(List *parameters, Oid languageOid, bool is_aggregate, const char *queryString, oidvector **parameterTypes, ArrayType **allParameterTypes, ArrayType **parameterModes, ArrayType **parameterNames, List **parameterDefaults, Oid *variadicArgType, Oid *requiredResultType) { int parameterCount = list_length(parameters); Oid *inTypes; int inCount = 0; Datum *allTypes; Datum *paramModes; Datum *paramNames; int outCount = 0; int varCount = 0; bool have_names = false; bool have_defaults = false; ListCell *x; int i; ParseState *pstate; *variadicArgType = InvalidOid; /* default result */ *requiredResultType = InvalidOid; /* default result */ inTypes = (Oid *) palloc(parameterCount * sizeof(Oid)); allTypes = (Datum *) palloc(parameterCount * sizeof(Datum)); paramModes = (Datum *) palloc(parameterCount * sizeof(Datum)); paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum)); *parameterDefaults = NIL; /* may need a pstate for parse analysis of default exprs */ pstate = make_parsestate(NULL); pstate->p_sourcetext = queryString; /* Scan the list and extract data into work arrays */ i = 0; foreach(x, parameters) { FunctionParameter *fp = (FunctionParameter *) lfirst(x); TypeName *t = fp->argType; bool isinput = false; Oid toid; Type typtup; AclResult aclresult; typtup = LookupTypeName(NULL, t, NULL, false); if (typtup) { if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) { /* As above, hard error if language is SQL */ if (languageOid == SQLlanguageId) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL function cannot accept shell type %s", TypeNameToString(t)))); /* We don't allow creating aggregates on shell types either */ else if (is_aggregate) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregate cannot accept shell type %s", TypeNameToString(t)))); else ereport(NOTICE, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("argument type %s is only a shell", TypeNameToString(t)))); } toid = typeTypeId(typtup); ReleaseSysCache(typtup); } else { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type %s does not exist", TypeNameToString(t)))); toid = InvalidOid; /* keep compiler quiet */ } aclresult = pg_type_aclcheck(toid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error_type(aclresult, toid); if (t->setof) { if (is_aggregate) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("aggregates cannot accept set arguments"))); else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("functions cannot accept set arguments"))); } /* handle input parameters */ if (fp->mode != FUNC_PARAM_OUT && fp->mode != FUNC_PARAM_TABLE) { /* other input parameters can't follow a VARIADIC parameter */ if (varCount > 0) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("VARIADIC parameter must be the last input parameter"))); inTypes[inCount++] = toid; isinput = true; } /* handle output parameters */ if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_VARIADIC) { if (outCount == 0) /* save first output param's type */ *requiredResultType = toid; outCount++; } if (fp->mode == FUNC_PARAM_VARIADIC) { *variadicArgType = toid; varCount++; /* validate variadic parameter type */ switch (toid) { case ANYARRAYOID: case ANYOID: /* okay */ break; default: if (!OidIsValid(get_element_type(toid))) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("VARIADIC parameter must be an array"))); break; } } allTypes[i] = ObjectIdGetDatum(toid); paramModes[i] = CharGetDatum(fp->mode); if (fp->name && fp->name[0]) { ListCell *px; /* * As of Postgres 9.0 we disallow using the same name for two * input or two output function parameters. Depending on the * function's language, conflicting input and output names might * be bad too, but we leave it to the PL to complain if so. */ foreach(px, parameters) { FunctionParameter *prevfp = (FunctionParameter *) lfirst(px); if (prevfp == fp) break; /* pure in doesn't conflict with pure out */ if ((fp->mode == FUNC_PARAM_IN || fp->mode == FUNC_PARAM_VARIADIC) && (prevfp->mode == FUNC_PARAM_OUT || prevfp->mode == FUNC_PARAM_TABLE)) continue; if ((prevfp->mode == FUNC_PARAM_IN || prevfp->mode == FUNC_PARAM_VARIADIC) && (fp->mode == FUNC_PARAM_OUT || fp->mode == FUNC_PARAM_TABLE)) continue; if (prevfp->name && prevfp->name[0] && strcmp(prevfp->name, fp->name) == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("parameter name \"%s\" used more than once", fp->name))); }
/* * Verify lvalue - actually this not compare lvalue against rvalue - that should * be next improvent, other improvent should be checking a result type of subscripts * expressions. */ static void check_target(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt, int varno, TupleDesc tupdesc) { PLpgSQL_datum *target = estate->datums[varno]; switch (target->dtype) { case PLPGSQL_DTYPE_VAR: break; case PLPGSQL_DTYPE_REC: break; case PLPGSQL_DTYPE_ROW: { check_row_or_rec(estate, stmt, (PLpgSQL_row *) target, NULL, tupdesc); } break; case PLPGSQL_DTYPE_RECFIELD: { PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target; PLpgSQL_rec *rec; int fno; rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]); /* * Check that there is already a tuple in the record. We need * that because records don't have any predefined field * structure. */ if (!HeapTupleIsValid(rec->tup)) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned yet", rec->refname), errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); /* * Get the number of the records field to change and the * number of attributes in the tuple. Note: disallow system * column names because the code below won't cope. */ fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); if (fno <= 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("record \"%s\" has no field \"%s\"", rec->refname, recfield->fieldname))); } break; case PLPGSQL_DTYPE_ARRAYELEM: { /* * Target is an element of an array */ int nsubscripts; Oid arrayelemtypeid; /* * To handle constructs like x[1][2] := something, we have to * be prepared to deal with a chain of arrayelem datums. Chase * back to find the base array datum, and save the subscript * expressions as we go. (We are scanning right to left here, * but want to evaluate the subscripts left-to-right to * minimize surprises.) */ nsubscripts = 0; do { PLpgSQL_arrayelem *arrayelem = (PLpgSQL_arrayelem *) target; if (nsubscripts++ >= MAXDIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", nsubscripts + 1, MAXDIM))); simple_check_expr(estate, stmt, arrayelem->subscript); target = estate->datums[arrayelem->arrayparentno]; } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM); arrayelemtypeid = get_element_type(exec_get_datum_type(estate, target)); if (!OidIsValid(arrayelemtypeid)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("subscripted object is not an array"))); } break; } return; }
/* * ApplicableOpExpressionList walks over all filter clauses that relate to this * foreign table, and chooses applicable clauses that we know we can translate * into Mongo queries. Currently, these clauses include comparison expressions * that have a column and a constant as arguments. For example, "o_orderdate >= * date '1994-01-01' + interval '1' year" is an applicable expression. */ List * ApplicableOpExpressionList(RelOptInfo *baserel) { List *opExpressionList = NIL; List *restrictInfoList = baserel->baserestrictinfo; ListCell *restrictInfoCell = NULL; foreach(restrictInfoCell, restrictInfoList) { RestrictInfo *restrictInfo = (RestrictInfo *) lfirst(restrictInfoCell); Expr *expression = restrictInfo->clause; NodeTag expressionType = 0; OpExpr *opExpression = NULL; char *operatorName = NULL; char *mongoOperatorName = NULL; List *argumentList = NIL; Var *column = NULL; Const *constant = NULL; bool equalsOperator = false; bool constantIsArray = false; /* we only support operator expressions */ expressionType = nodeTag(expression); if (expressionType != T_OpExpr) { continue; } opExpression = (OpExpr *) expression; operatorName = get_opname(opExpression->opno); /* we only support =, <, >, <=, >=, and <> operators */ if (strncmp(operatorName, EQUALITY_OPERATOR_NAME, NAMEDATALEN) == 0) { equalsOperator = true; } mongoOperatorName = MongoOperatorName(operatorName); if (!equalsOperator && mongoOperatorName == NULL) { continue; } /* * We only support simple binary operators that compare a column against * a constant. If the expression is a tree, we don't recurse into it. */ argumentList = opExpression->args; column = (Var *) FindArgumentOfType(argumentList, T_Var); constant = (Const *) FindArgumentOfType(argumentList, T_Const); /* * We don't push down operators where the constant is an array, since * conditional operators for arrays in MongoDB aren't properly defined. * For example, {similar_products : [ "B0009S4IJW", "6301964144" ]} * finds results that are equal to the array, but {similar_products: * {$gte: [ "B0009S4IJW", "6301964144" ]}} returns an empty set. */ if (constant != NULL) { Oid constantArrayTypeId = get_element_type(constant->consttype); if (constantArrayTypeId != InvalidOid) { constantIsArray = true; } } if (column != NULL && constant != NULL && !constantIsArray) { opExpressionList = lappend(opExpressionList, opExpression); } }
/* * 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"), 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"), 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. */ 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 = InvalidOid; result->useOr = useOr; result->args = args; ReleaseSysCache(tup); return (Expr *) result; }
Datum get_power_spectrum(PG_FUNCTION_ARGS) { //the size of the array we are trying to transform int arraySize; int *signals; // a Datum for the constructred and deconstructed input arrays Datum *intermResult; Datum *input_data; // the final result to return and the input to the function ArrayType *result, *input; Oid element_type, return_type, input_type; //next 6 variables are inputted into get_typlenbyvalalign() and are used for construct and deconstruct array //small int in postgreSQL is int16 int16 return_typelen, input_typelen; bool return_typbyval, input_typbyval; char return_typalign, input_typalign; // get input row input = PG_GETARG_ARRAYTYPE_P(0); // get input array element type input_type = ARR_ELEMTYPE(input); //get needed variabels get_typlenbyvalalign(input_type, &input_typelen, &input_typbyval, &input_typalign); // deconstruct inupt array and save the array as Datum input_data deconstruct_array(input, input_type, input_typelen, input_typbyval, input_typalign, &input_data, NULL, &arraySize); // get element type of return vale (Complex[]) element_type = get_fn_expr_rettype(fcinfo->flinfo); // get element type of an element in the return value (Complex) return_type = get_element_type(element_type); //get needed variabels get_typlenbyvalalign(return_type, &return_typelen, &return_typbyval, &return_typalign); signals = palloc(sizeof(int)*arraySize); // set the in variable to the array we got as input. // the real parts are from the input_data array // the imaginary part is set to 0 for (int i = 0; i < arraySize; i++) { Complex *temp = (Complex*) DatumGetPointer(input_data[i]); signals[i] = temp->x*temp->x + temp->y*temp->y; } intermResult = palloc(sizeof(Datum)*arraySize); // for each variable in the out array. // Create a complex variable then set its real and imaginary party from the processed array // get the datum from the pointer and save it in the result array for(int i = 0; i < arraySize; i++) { intermResult[i] = PointerGetDatum(signals[i]); } // construct a result array result = construct_array(intermResult, arraySize, return_type, return_typelen, return_typbyval, return_typalign); // free memory pfree(input_data); pfree(intermResult); // return result PG_RETURN_POINTER(result); }
/* plphp_srf_htup_from_zval * Build a tuple from a zval and a TupleDesc, for a SRF. * * Like above, but we don't use the names of the array attributes; * rather we build the tuple in order. Also, we get a MemoryContext * from the caller and just clean it at return, rather than building it each * time. */ HeapTuple plphp_srf_htup_from_zval(zval *val, AttInMetadata *attinmeta, MemoryContext cxt) { MemoryContext oldcxt; HeapTuple ret; HashPosition pos; char **values; zval **element; int i = 0; oldcxt = MemoryContextSwitchTo(cxt); /* * Use palloc0 to initialize values to NULL, just in case the user does * not pass all needed attributes */ values = (char **) palloc0(attinmeta->tupdesc->natts * sizeof(char *)); /* * If the input zval is an array, build a tuple using each element as an * attribute. Exception: if the return tuple has a single element and * it's an array type, use the whole array as a single value. * * If the input zval is a scalar, use it as an element directly. */ if (Z_TYPE_P(val) == IS_ARRAY) { if (attinmeta->tupdesc->natts == 1) { /* Is it an array? */ if (attinmeta->tupdesc->attrs[0]->attndims != 0 || !OidIsValid(get_element_type(attinmeta->tupdesc->attrs[0]->atttypid))) { zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(val), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_P(val), (void **) &element, &pos); values[0] = plphp_zval_get_cstring(element[0], true, true); } else values[0] = plphp_zval_get_cstring(val, true, true); } else { /* * Ok, it's an array and the return tuple has more than one * attribute, so scan each array element. */ for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(val), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_P(val), (void **) &element, &pos) == SUCCESS; zend_hash_move_forward_ex(Z_ARRVAL_P(val), &pos)) { /* avoid overrunning the palloc'ed chunk */ if (i >= attinmeta->tupdesc->natts) { elog(WARNING, "more elements in array than attributes in return type"); break; } values[i++] = plphp_zval_get_cstring(element[0], true, true); } } } else { /* The passed zval is not an array -- use as the only attribute */ if (attinmeta->tupdesc->natts != 1) ereport(ERROR, (errmsg("returned array does not correspond to " "declared return value"))); values[0] = plphp_zval_get_cstring(val, true, true); } MemoryContextSwitchTo(oldcxt); ret = BuildTupleFromCStrings(attinmeta, values); MemoryContextReset(cxt); return ret; }
/*----------------------------------------------------------------------------- * array_push : * push an element onto either end of a one-dimensional array *---------------------------------------------------------------------------- */ Datum array_push(PG_FUNCTION_ARGS) { ArrayType *v; Datum newelem; bool isNull; int *dimv, *lb; ArrayType *result; int indx; Oid element_type; int16 typlen; bool typbyval; char typalign; Oid arg0_typeid = get_fn_expr_argtype(fcinfo->flinfo, 0); Oid arg1_typeid = get_fn_expr_argtype(fcinfo->flinfo, 1); Oid arg0_elemid; Oid arg1_elemid; ArrayMetaState *my_extra; if (arg0_typeid == InvalidOid || arg1_typeid == InvalidOid) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data types"))); arg0_elemid = get_element_type(arg0_typeid); arg1_elemid = get_element_type(arg1_typeid); if (arg0_elemid != InvalidOid) { if (PG_ARGISNULL(0)) v = construct_empty_array(arg0_elemid); else v = PG_GETARG_ARRAYTYPE_P(0); isNull = PG_ARGISNULL(1); if (isNull) newelem = (Datum) 0; else newelem = PG_GETARG_DATUM(1); } else if (arg1_elemid != InvalidOid) { if (PG_ARGISNULL(1)) v = construct_empty_array(arg1_elemid); else v = PG_GETARG_ARRAYTYPE_P(1); isNull = PG_ARGISNULL(0); if (isNull) newelem = (Datum) 0; else newelem = PG_GETARG_DATUM(0); } else { /* Shouldn't get here given proper type checking in parser */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("neither input type is an array"))); PG_RETURN_NULL(); /* keep compiler quiet */ } element_type = ARR_ELEMTYPE(v); if (ARR_NDIM(v) == 1) { lb = ARR_LBOUND(v); dimv = ARR_DIMS(v); if (arg0_elemid != InvalidOid) { /* append newelem */ int ub = dimv[0] + lb[0] - 1; indx = ub + 1; /* overflow? */ if (indx < ub) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); } else { /* prepend newelem */ indx = lb[0] - 1; /* overflow? */ if (indx > lb[0]) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); } } else if (ARR_NDIM(v) == 0) indx = 1; else ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("argument must be empty or one-dimensional array"))); /* * We arrange to look up info about element type only once per series of * calls, assuming the element type doesn't change underneath us. */ my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; if (my_extra == NULL) { fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(ArrayMetaState)); my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra; my_extra->element_type = ~element_type; } if (my_extra->element_type != element_type) { /* Get info about element type */ get_typlenbyvalalign(element_type, &my_extra->typlen, &my_extra->typbyval, &my_extra->typalign); my_extra->element_type = element_type; } typlen = my_extra->typlen; typbyval = my_extra->typbyval; typalign = my_extra->typalign; result = array_set(v, 1, &indx, newelem, isNull, -1, typlen, typbyval, typalign); /* * Readjust result's LB to match the input's. This does nothing in the * append case, but it's the simplest way to implement the prepend case. */ if (ARR_NDIM(v) == 1) ARR_LBOUND(result)[0] = ARR_LBOUND(v)[0]; PG_RETURN_ARRAYTYPE_P(result); }
/* ---------------------------------------------------------------- * ProcedureCreate * * Note: allParameterTypes, parameterModes, parameterNames, and proconfig * are either arrays of the proper types or NULL. We declare them Datum, * not "ArrayType *", to avoid importing array.h into pg_proc_fn.h. * ---------------------------------------------------------------- */ Oid ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, bool isAgg, bool isWindowFunc, bool security_definer, bool isStrict, char volatility, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum proconfig, float4 procost, float4 prorows) { Oid retval; int parameterCount; int allParamCount; Oid *allParams; bool genericInParam = false; bool genericOutParam = false; bool internalInParam = false; bool internalOutParam = false; Oid variadicType = InvalidOid; Oid proowner = GetUserId(); Relation rel; HeapTuple tup; HeapTuple oldtup; bool nulls[Natts_pg_proc]; Datum values[Natts_pg_proc]; bool replaces[Natts_pg_proc]; Oid relid; NameData procname; TupleDesc tupDesc; bool is_update; ObjectAddress myself, referenced; int i; /* * sanity checks */ Assert(PointerIsValid(prosrc)); parameterCount = parameterTypes->dim1; if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("functions cannot have more than %d argument", "functions cannot have more than %d arguments", FUNC_MAX_ARGS, FUNC_MAX_ARGS))); /* note: the above is correct, we do NOT count output arguments */ if (allParameterTypes != PointerGetDatum(NULL)) { /* * We expect the array to be a 1-D OID array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of OID values. */ ArrayType *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes); allParamCount = ARR_DIMS(allParamArray)[0]; if (ARR_NDIM(allParamArray) != 1 || allParamCount <= 0 || ARR_HASNULL(allParamArray) || ARR_ELEMTYPE(allParamArray) != OIDOID) elog(ERROR, "allParameterTypes is not a 1-D Oid array"); allParams = (Oid *) ARR_DATA_PTR(allParamArray); Assert(allParamCount >= parameterCount); /* we assume caller got the contents right */ } else { allParamCount = parameterCount; allParams = parameterTypes->values; } /* * Do not allow polymorphic return type unless at least one input argument * is polymorphic. Also, do not allow return type INTERNAL unless at * least one input argument is INTERNAL. */ for (i = 0; i < parameterCount; i++) { switch (parameterTypes->values[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericInParam = true; break; case INTERNALOID: internalInParam = true; break; } } if (allParameterTypes != PointerGetDatum(NULL)) { for (i = 0; i < allParamCount; i++) { /* * We don't bother to distinguish input and output params here, so * if there is, say, just an input INTERNAL param then we will * still set internalOutParam. This is OK since we don't really * care. */ switch (allParams[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericOutParam = true; break; case INTERNALOID: internalOutParam = true; break; } } } if ((IsPolymorphicType(returnType) || genericOutParam) && !genericInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning a polymorphic type must have at least one polymorphic argument."))); if ((returnType == INTERNALOID || internalOutParam) && !internalInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("unsafe use of pseudo-type \"internal\""), errdetail("A function returning \"internal\" must have at least one \"internal\" argument."))); /* * don't allow functions of complex types that have the same name as * existing attributes of the type */ if (parameterCount == 1 && OidIsValid(parameterTypes->values[0]) && (relid = typeidTypeRelid(parameterTypes->values[0])) != InvalidOid && get_attnum(relid, procedureName) != InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("\"%s\" is already an attribute of type %s", procedureName, format_type_be(parameterTypes->values[0])))); if (parameterModes != PointerGetDatum(NULL)) { /* * We expect the array to be a 1-D CHAR array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of char values. */ ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes); char *modes; if (ARR_NDIM(modesArray) != 1 || ARR_DIMS(modesArray)[0] != allParamCount || ARR_HASNULL(modesArray) || ARR_ELEMTYPE(modesArray) != CHAROID) elog(ERROR, "parameterModes is not a 1-D char array"); modes = (char *) ARR_DATA_PTR(modesArray); /* * Only the last input parameter can be variadic; if it is, save its * element type. Errors here are just elog since caller should have * checked this already. */ for (i = 0; i < allParamCount; i++) { switch (modes[i]) { case PROARGMODE_IN: case PROARGMODE_INOUT: if (OidIsValid(variadicType)) elog(ERROR, "variadic parameter must be last"); break; case PROARGMODE_OUT: case PROARGMODE_TABLE: /* okay */ break; case PROARGMODE_VARIADIC: if (OidIsValid(variadicType)) elog(ERROR, "variadic parameter must be last"); switch (allParams[i]) { case ANYOID: variadicType = ANYOID; break; case ANYARRAYOID: variadicType = ANYELEMENTOID; break; default: variadicType = get_element_type(allParams[i]); if (!OidIsValid(variadicType)) elog(ERROR, "variadic parameter is not an array"); break; } break; default: elog(ERROR, "invalid parameter mode '%c'", modes[i]); break; } } } /* * All seems OK; prepare the data to be inserted into pg_proc. */ for (i = 0; i < Natts_pg_proc; ++i) { nulls[i] = false; values[i] = (Datum) 0; replaces[i] = true; } namestrcpy(&procname, procedureName); values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname); values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace); values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner); values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId); values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost); values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows); values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType); values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg); values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc); values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer); values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict); values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet); values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility); values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount); values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults)); values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType); values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes); if (allParameterTypes != PointerGetDatum(NULL)) values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes; else nulls[Anum_pg_proc_proallargtypes - 1] = true; if (parameterModes != PointerGetDatum(NULL)) values[Anum_pg_proc_proargmodes - 1] = parameterModes; else nulls[Anum_pg_proc_proargmodes - 1] = true; if (parameterNames != PointerGetDatum(NULL)) values[Anum_pg_proc_proargnames - 1] = parameterNames; else nulls[Anum_pg_proc_proargnames - 1] = true; if (parameterDefaults != NIL) values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults)); else nulls[Anum_pg_proc_proargdefaults - 1] = true; values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); if (probin) values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin); else nulls[Anum_pg_proc_probin - 1] = true; if (proconfig != PointerGetDatum(NULL)) values[Anum_pg_proc_proconfig - 1] = proconfig; else nulls[Anum_pg_proc_proconfig - 1] = true; /* start out with empty permissions */ nulls[Anum_pg_proc_proacl - 1] = true; rel = heap_open(ProcedureRelationId, RowExclusiveLock); tupDesc = RelationGetDescr(rel); /* Check for pre-existing definition */ oldtup = SearchSysCache(PROCNAMEARGSNSP, PointerGetDatum(procedureName), PointerGetDatum(parameterTypes), ObjectIdGetDatum(procNamespace), 0); if (HeapTupleIsValid(oldtup)) { /* There is one; okay to replace it? */ Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup); if (!replace) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function \"%s\" already exists with same argument types", procedureName))); if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), proowner)) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, procedureName); /* * Not okay to change the return type of the existing proc, since * existing rules, views, etc may depend on the return type. */ if (returnType != oldproc->prorettype || returnsSet != oldproc->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change return type of existing function"), errhint("Use DROP FUNCTION first."))); /* * If it returns RECORD, check for possible change of record type * implied by OUT parameters */ if (returnType == RECORDOID) { TupleDesc olddesc; TupleDesc newdesc; olddesc = build_function_result_tupdesc_t(oldtup); newdesc = build_function_result_tupdesc_d(allParameterTypes, parameterModes, parameterNames); if (olddesc == NULL && newdesc == NULL) /* ok, both are runtime-defined RECORDs */ ; else if (olddesc == NULL || newdesc == NULL || !equalTupleDescs(olddesc, newdesc)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change return type of existing function"), errdetail("Row type defined by OUT parameters is different."), errhint("Use DROP FUNCTION first."))); } /* * If there are existing defaults, check compatibility: redefinition * must not remove any defaults nor change their types. (Removing a * default might cause a function to fail to satisfy an existing call. * Changing type would only be possible if the associated parameter is * polymorphic, and in such cases a change of default type might alter * the resolved output type of existing calls.) */ if (oldproc->pronargdefaults != 0) { Datum proargdefaults; bool isnull; List *oldDefaults; ListCell *oldlc; ListCell *newlc; if (list_length(parameterDefaults) < oldproc->pronargdefaults) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot remove parameter defaults from existing function"), errhint("Use DROP FUNCTION first."))); proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargdefaults, &isnull); Assert(!isnull); oldDefaults = (List *) stringToNode(TextDatumGetCString(proargdefaults)); Assert(IsA(oldDefaults, List)); Assert(list_length(oldDefaults) == oldproc->pronargdefaults); /* new list can have more defaults than old, advance over 'em */ newlc = list_head(parameterDefaults); for (i = list_length(parameterDefaults) - oldproc->pronargdefaults; i > 0; i--) newlc = lnext(newlc); foreach(oldlc, oldDefaults) { Node *oldDef = (Node *) lfirst(oldlc); Node *newDef = (Node *) lfirst(newlc); if (exprType(oldDef) != exprType(newDef)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change data type of existing parameter default value"), errhint("Use DROP FUNCTION first."))); newlc = lnext(newlc); } }
/* ---------------------------------------------------------------- * procedure_create * * Note: allParameterTypes, parameterModes, parameterNames, and proconfig * are either arrays of the proper types or NULL. We declare them Datum, * not "ArrayType *", to avoid importing array.h into pg_proc_fn.h. * ---------------------------------------------------------------- */ oid_t procedure_create( const char *procedureName, oid_t procNamespace, bool replace, bool returnsSet, oid_t returnType, oid_t languageObjectId, oid_t languageValidator, const char *prosrc, const char *probin, bool isAgg, bool isWindowFunc, bool security_definer, bool isStrict, char volatility, oid_vector_s *parameterTypes, datum_t allParameterTypes, datum_t parameterModes, datum_t parameterNames, struct list *parameterDefaults, datum_t proconfig, float4 procost, float4 prorows) { oid_t retval; int parameterCount; int allParamCount; oid_t* allParams; bool genericInParam = false; bool genericOutParam = false; bool internalInParam = false; bool internalOutParam = false; oid_t variadicType = INVALID_OID; oid_t proowner = get_uid(); acl_s* proacl = NULL; struct relation* rel; struct heap_tuple* tup; struct heap_tuple* oldtup; bool nulls[Natts_pg_proc]; datum_t values[Natts_pg_proc]; bool replaces[Natts_pg_proc]; oid_t relid; struct name procname; struct tuple* tupDesc; bool is_update; struct objaddr myself; struct objaddr referenced; int i; /* * sanity checks */ ASSERT(PTR_VALID(prosrc)); parameterCount = parameterTypes->dim1; if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS) { ereport(ERROR, ( errcode(E_TOO_MANY_ARGUMENTS), errmsg_plural("functions cannot have more than %d argument", "functions cannot have more than %d arguments", FUNC_MAX_ARGS, FUNC_MAX_ARGS))); } /* note: the above is correct, we do NOT count output arguments */ if (allParameterTypes != PTR_TO_D(NULL)) { /* * We expect the array to be a 1-D OID array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of OID values. */ array_s *allParamArray; allParamArray = (array_s*) D_TO_PTR(allParameterTypes); allParamCount = ARR_DIMS(allParamArray)[0]; if (ARR_NDIM(allParamArray) != 1 || allParamCount <= 0 || ARR_HASNULL(allParamArray) || ARR_ELEMTYPE(allParamArray) != OIDOID) elog(ERROR, "allParameterTypes is not a 1-D oid_t array"); allParams = (oid_t*) ARR_DATA_PTR(allParamArray); ASSERT(allParamCount >= parameterCount); /* we assume caller got the contents right */ } else { allParamCount = parameterCount; allParams = parameterTypes->values; } /* * Do not allow polymorphic return type unless at least one input argument * is polymorphic. Also, do not allow return type INTERNAL unless at * least one input argument is INTERNAL. */ for (i = 0; i < parameterCount; i++) { switch (parameterTypes->values[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericInParam = true; break; case INTERNALOID: internalInParam = true; break; } } if (allParameterTypes != PTR_TO_D(NULL)) { for (i = 0; i < allParamCount; i++) { /* * We don't bother to distinguish input and output params here, so * if there is, say, just an input INTERNAL param then we will * still set internalOutParam. This is OK since we don't really * care. */ switch (allParams[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericOutParam = true; break; case INTERNALOID: internalOutParam = true; break; } } } if ((is_polymorphic_type(returnType) || genericOutParam) && !genericInParam) { ereport(ERROR, ( errcode(E_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning a polymorphic type must have" " at least one polymorphic argument."))); } if ((returnType == INTERNALOID || internalOutParam) && !internalInParam) { ereport(ERROR, ( errcode(E_INVALID_FUNCTION_DEFINITION), errmsg("unsafe use of pseudo-type \"internal\""), errdetail("A function returning \"internal\" must have at" " least one \"internal\" argument."))); } /* * don't allow functions of complex types that have the same name as * existing attributes of the type */ if (parameterCount == 1 && OID_VALID(parameterTypes->values[0]) && (relid = typeid_to_relid(parameterTypes->values[0])) != INVALID_OID && get_attnum(relid, procedureName) != INVALID_ATTR_NR) { ereport(ERROR, ( errcode(E_DUPLICATE_COLUMN), errmsg("\"%s\" is already an attribute of type %s", procedureName, format_type_be(parameterTypes->values[0])))); } if (parameterModes != PTR_TO_D(NULL)) { /* * We expect the array to be a 1-D CHAR array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of char values. */ array_s* modesArray; char* modes; modesArray = (array_s *) D_TO_PTR(parameterModes); if (ARR_NDIM(modesArray) != 1 || ARR_DIMS(modesArray)[0] != allParamCount || ARR_HASNULL(modesArray) || ARR_ELEMTYPE(modesArray) != CHAROID) elog(ERROR, "parameterModes is not a 1-D char array"); modes = (char*) ARR_DATA_PTR(modesArray); /* * Only the last input parameter can be variadic; if it is, save its * element type. Errors here are just elog since caller should have * checked this already. */ for (i = 0; i < allParamCount; i++) { switch (modes[i]) { case PROARGMODE_IN: case PROARGMODE_INOUT: if (OID_VALID(variadicType)) elog(ERROR, "variadic parameter must be last"); break; case PROARGMODE_OUT: case PROARGMODE_TABLE: /* okay */ break; case PROARGMODE_VARIADIC: if (OID_VALID(variadicType)) elog(ERROR, "variadic parameter must be last"); switch (allParams[i]) { case ANYOID: variadicType = ANYOID; break; case ANYARRAYOID: variadicType = ANYELEMENTOID; break; default: variadicType = get_element_type(allParams[i]); if (!OID_VALID(variadicType)) elog(ERROR, "variadic parameter is not an array"); break; } break; default: elog(ERROR, "invalid parameter mode '%c'", modes[i]); break; } } } /* * All seems OK; prepare the data to be inserted into pg_proc. */ for (i = 0; i < Natts_pg_proc; ++i) { nulls[i] = false; values[i] = (datum_t) 0; replaces[i] = true; } namestrcpy(&procname, procedureName); values[Anum_pg_proc_proname - 1] = NAME_TO_D(&procname); values[Anum_pg_proc_pronamespace - 1] = OID_TO_D(procNamespace); values[Anum_pg_proc_proowner - 1] = OID_TO_D(proowner); values[Anum_pg_proc_prolang - 1] = OID_TO_D(languageObjectId); values[Anum_pg_proc_procost - 1] = FLOAT4_TO_D(procost); values[Anum_pg_proc_prorows - 1] = FLOAT4_TO_D(prorows); values[Anum_pg_proc_provariadic - 1] = OID_TO_D(variadicType); values[Anum_pg_proc_proisagg - 1] = BOOL_TO_D(isAgg); values[Anum_pg_proc_proiswindow - 1] = BOOL_TO_D(isWindowFunc); values[Anum_pg_proc_prosecdef - 1] = BOOL_TO_D(security_definer); values[Anum_pg_proc_proisstrict - 1] = BOOL_TO_D(isStrict); values[Anum_pg_proc_proretset - 1] = BOOL_TO_D(returnsSet); values[Anum_pg_proc_provolatile - 1] = CHAR_TO_D(volatility); values[Anum_pg_proc_pronargs - 1] = UINT16_TO_D(parameterCount); values[Anum_pg_proc_pronargdefaults - 1] = UINT16_TO_D(list_length(parameterDefaults)); values[Anum_pg_proc_prorettype - 1] = OID_TO_D(returnType); values[Anum_pg_proc_proargtypes - 1] = PTR_TO_D(parameterTypes); if (allParameterTypes != PTR_TO_D(NULL)) values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes; else nulls[Anum_pg_proc_proallargtypes - 1] = true; if (parameterModes != PTR_TO_D(NULL)) values[Anum_pg_proc_proargmodes - 1] = parameterModes; else nulls[Anum_pg_proc_proargmodes - 1] = true; if (parameterNames != PTR_TO_D(NULL)) values[Anum_pg_proc_proargnames - 1] = parameterNames; else nulls[Anum_pg_proc_proargnames - 1] = true; if (parameterDefaults != NIL) values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum( node_to_string(parameterDefaults)); else nulls[Anum_pg_proc_proargdefaults - 1] = true; values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); if (probin) values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin); else nulls[Anum_pg_proc_probin - 1] = true; if (proconfig != PTR_TO_D(NULL)) values[Anum_pg_proc_proconfig - 1] = proconfig; else nulls[Anum_pg_proc_proconfig - 1] = true; /* * proacl will be determined later */ rel = heap_open(ProcedureRelationId, ROW_EXCL_LOCK); tupDesc = REL_DESC(rel); /* Check for pre-existing definition */ oldtup = search_syscache3( PROCNAMEARGSNSP, PTR_TO_D(procedureName), PTR_TO_D(parameterTypes), OID_TO_D(procNamespace)); if (HT_VALID(oldtup)) { /* There is one; okay to replace it? */ Form_pg_proc oldproc; datum_t proargnames; bool isnull; oldproc = (Form_pg_proc) GET_STRUCT(oldtup); if (!replace) { ereport(ERROR, ( errcode(E_DUPLICATE_FUNCTION), errmsg("function \"%s\" already exists with same argument types", procedureName))); } if (!pg_proc_ownercheck(HEAPTUP_OID(oldtup), proowner)) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, procedureName); /* * Not okay to change the return type of the existing proc, since * existing rules, views, etc may depend on the return type. */ if (returnType != oldproc->prorettype || returnsSet != oldproc->proretset) { ereport(ERROR, ( errcode(E_INVALID_FUNCTION_DEFINITION), errmsg("cannot change return type of existing function"), errhint("Use DROP FUNCTION first."))); } /* * If it returns RECORD, check for possible change of record type * implied by OUT parameters */ if (returnType == RECORDOID) { struct tuple* olddesc; struct tuple* newdesc; olddesc = build_function_result_tupdesc_t(oldtup); newdesc = build_function_result_tupdesc_d( allParameterTypes, parameterModes, parameterNames); if (olddesc == NULL && newdesc == NULL) { /* ok, both are runtime-defined RECORDs */ ; } else if (olddesc == NULL || newdesc == NULL || !tupdesc_equal(olddesc, newdesc)) { ereport(ERROR, ( errcode(E_INVALID_FUNCTION_DEFINITION), errmsg("cannot change return type of existing function"), errdetail("Row type defined by OUT parameters is different."), errhint("Use DROP FUNCTION first."))); } } /* * If there were any named input parameters, check to make sure the * names have not been changed, as this could break existing calls. We * allow adding names to formerly unnamed parameters, though. */ proargnames = syscache_attr( PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargnames, &isnull); if (!isnull) { datum_t proargmodes; char** old_arg_names; char** new_arg_names; int n_old_arg_names; int n_new_arg_names; int j; proargmodes = syscache_attr( PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargmodes, &isnull); if (isnull) proargmodes = PTR_TO_D(NULL); /* just to be sure */ n_old_arg_names = get_func_input_arg_names( proargnames, proargmodes, &old_arg_names); n_new_arg_names = get_func_input_arg_names( parameterNames, parameterModes, &new_arg_names); for (j = 0; j < n_old_arg_names; j++) { if (old_arg_names[j] == NULL) continue; if (j >= n_new_arg_names || new_arg_names[j] == NULL || strcmp(old_arg_names[j], new_arg_names[j]) != 0) { ereport(ERROR,( errcode(E_INVALID_FUNCTION_DEFINITION), errmsg("cannot change name of input parameter \"%s\"", old_arg_names[j]), errhint("Use DROP FUNCTION first."))); } } } /* * If there are existing defaults, check compatibility: redefinition * must not remove any defaults nor change their types. (Removing a * default might cause a function to fail to satisfy an existing call. * Changing type would only be possible if the associated parameter is * polymorphic, and in such cases a change of default type might alter * the resolved output type of existing calls.) */ if (oldproc->pronargdefaults != 0) { datum_t proargdefaults; struct list* oldDefaults; struct list_cell* oldlc; struct list_cell* newlc; if (list_length(parameterDefaults) < oldproc->pronargdefaults) { ereport(ERROR, ( errcode(E_INVALID_FUNCTION_DEFINITION), errmsg("cannot remove parameter defaults from existing function"), errhint("Use DROP FUNCTION first."))); } proargdefaults = syscache_attr( PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargdefaults, &isnull); ASSERT(!isnull); oldDefaults = (struct list*) string_to_node( TextD_TO_CSTRING(proargdefaults)); ASSERT(IS_A(oldDefaults, List)); ASSERT(list_length(oldDefaults) == oldproc->pronargdefaults); /* new list can have more defaults than old, advance over 'em */ newlc = list_head(parameterDefaults); for (i = list_length(parameterDefaults) - oldproc->pronargdefaults; i > 0; i--) newlc = lnext(newlc); foreach(oldlc, oldDefaults) { node_n* oldDef; node_n* newDef; oldDef = (node_n*) lfirst(oldlc); newDef = (node_n*) lfirst(newlc); if (expr_type(oldDef) != expr_type(newDef)) { ereport(ERROR,( errcode(E_INVALID_FUNCTION_DEFINITION), errmsg("cannot change data type of existing" " parameter default value"), errhint("Use DROP FUNCTION first."))); } newlc = lnext(newlc); } }
static void PLy_output_datum_func2(PLyObToDatum *arg, HeapTuple typeTup) { Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); Oid element_type; perm_fmgr_info(typeStruct->typinput, &arg->typfunc); arg->typoid = HeapTupleGetOid(typeTup); arg->typmod = -1; arg->typioparam = getTypeIOParam(typeTup); arg->typbyval = typeStruct->typbyval; element_type = get_element_type(arg->typoid); /* * Select a conversion function to convert Python objects to PostgreSQL * datums. Most data types can go through the generic function. */ switch (getBaseType(element_type ? element_type : arg->typoid)) { case BOOLOID: arg->func = PLyObject_ToBool; break; case BYTEAOID: arg->func = PLyObject_ToBytea; break; default: arg->func = PLyObject_ToDatum; break; } /* Composite types need their own input routine, though */ if (typeStruct->typtype == TYPTYPE_COMPOSITE) { arg->func = PLyObject_ToComposite; } if (element_type) { char dummy_delim; Oid funcid; if (type_is_rowtype(element_type)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Python functions cannot return type %s", format_type_be(arg->typoid)), errdetail("PL/Python does not support conversion to arrays of row types."))); arg->elm = PLy_malloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->func = PLySequence_ToArray; arg->elm->typoid = element_type; arg->elm->typmod = -1; get_type_io_data(element_type, IOFunc_input, &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim, &arg->elm->typioparam, &funcid); perm_fmgr_info(funcid, &arg->elm->typfunc); } }
static void PLy_input_datum_func2(PLyDatumToOb *arg, Oid typeOid, HeapTuple typeTup) { Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); Oid element_type = get_element_type(typeOid); /* Get the type's conversion information */ perm_fmgr_info(typeStruct->typoutput, &arg->typfunc); arg->typoid = HeapTupleGetOid(typeTup); arg->typmod = -1; arg->typioparam = getTypeIOParam(typeTup); arg->typbyval = typeStruct->typbyval; arg->typlen = typeStruct->typlen; arg->typalign = typeStruct->typalign; /* Determine which kind of Python object we will convert to */ switch (getBaseType(element_type ? element_type : typeOid)) { case BOOLOID: arg->func = PLyBool_FromBool; break; case FLOAT4OID: arg->func = PLyFloat_FromFloat4; break; case FLOAT8OID: arg->func = PLyFloat_FromFloat8; break; case NUMERICOID: arg->func = PLyFloat_FromNumeric; break; case INT2OID: arg->func = PLyInt_FromInt16; break; case INT4OID: arg->func = PLyInt_FromInt32; break; case INT8OID: arg->func = PLyLong_FromInt64; break; case BYTEAOID: arg->func = PLyBytes_FromBytea; break; default: arg->func = PLyString_FromDatum; break; } if (element_type) { char dummy_delim; Oid funcid; arg->elm = PLy_malloc0(sizeof(*arg->elm)); arg->elm->func = arg->func; arg->func = PLyList_FromArray; arg->elm->typoid = element_type; arg->elm->typmod = -1; get_type_io_data(element_type, IOFunc_output, &arg->elm->typlen, &arg->elm->typbyval, &arg->elm->typalign, &dummy_delim, &arg->elm->typioparam, &funcid); perm_fmgr_info(funcid, &arg->elm->typfunc); } }
/// \return The default value for Convolution. virtual std::shared_ptr<Node> get_default_value() const override { return ngraph::make_constant_from_string("0", get_element_type(), get_shape()); }
void handle_stlv_packet(unsigned char* packet) { stlv_packet pack = packet; char type_buf[MAX_ELEMENT_TYPE_BUFSIZE]; element_handle handle = get_first_element(pack); while (IS_VALID_STLV_HANDLE(handle)) { int type_len = get_element_type(pack, handle, type_buf, sizeof(type_buf)); log_info("Read Element: %x\n", type_buf[0]); switch (type_buf[0]) { case ELEMENT_TYPE_ECHO: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); unsigned char* data = get_element_data_buffer(pack, handle, type_buf, type_len); log_info("echo: "); print_stlv_string(data, data_len); log_info("\n"); handle_echo(data, data_len); } break; case ELEMENT_TYPE_CLOCK: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); unsigned char* data = get_element_data_buffer(pack, handle, type_buf, type_len); log_info("clock: %d/%d/%d %d:%d:%d\n", (int)data[0], (int)data[1], (int)data[2], (int)data[3], (int)data[4], (int)data[5]); handle_clock(data[0], data[1], data[2], data[3], data[4], data[5]); if (data_len >= 8) handle_phone_info(data[6], data[7]); } break; case ELEMENT_TYPE_MESSAGE: if (type_len == 2) { switch (type_buf[1]) { case ELEMENT_TYPE_MESSAGE_SMS: log_info("notification(SMS):\n"); break; case ELEMENT_TYPE_MESSAGE_FB: log_info("notification(Facebook):\n"); break; case ELEMENT_TYPE_MESSAGE_TW: log_info("notification(Twitter):\n"); break; default: break; } handle_msg_element(type_buf[1], pack, handle); } break; case ELEMENT_TYPE_FILE: handle_file(pack, handle); break; case ELEMENT_TYPE_GET_FILE: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len); STLV_BUF_BEGIN_TEMP_STRING(data, data_len); handle_get_file((char*)data); STLV_BUF_END_TEMP_STRING(data, data_len); } break; case ELEMENT_TYPE_ACTIVITY_DATA: handle_get_activity(); break; case ELEMENT_TYPE_LIST_FILES: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len); STLV_BUF_BEGIN_TEMP_STRING(data, data_len); handle_list_file((char*)data); STLV_BUF_END_TEMP_STRING(data, data_len); } break; case ELEMENT_TYPE_REMOVE_FILE: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len); STLV_BUF_BEGIN_TEMP_STRING(data, data_len); uint8_t file_name_pos = 0; for (uint8_t i = 0; i < data_len; ++i) { if (data[i] == ';') data[i] = '\0'; if (data[i] == '\0') { handle_remove_file((char*)(&data[file_name_pos])); file_name_pos = i + 1; } } STLV_BUF_END_TEMP_STRING(data, data_len); } break; #if 0 case ELEMENT_TYPE_SPORT_HEARTBEAT: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len); STLV_BUF_BEGIN_TEMP_STRING(data, data_len); handle_sports_heartbeat((char*)data); STLV_BUF_END_TEMP_STRING(data, data_len); } break; case ELEMENT_TYPE_SPORTS_DATA: handle_get_sports_data(); break; #endif case ELEMENT_TYPE_SPORTS_GRID: log_info("Get Sports Grid Request\n"); handle_get_sports_grid(); break; case ELEMENT_TYPE_ALARM: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len); if (data_len != sizeof(alarm_conf_t)) { log_info("Alarm element decode failed: length mismatch (%d/%d)", data_len, sizeof(alarm_conf_t)); } else { handle_alarm((alarm_conf_t*)data); } } break; case ELEMENT_TYPE_SN: handle_get_device_id(); break; case ELEMENT_TYPE_ACTIVITY: handle_gps_data(pack, handle); break; case ELEMENT_TYPE_GESTURE_CONTROL: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len); if (data_len != 5) { log_info("gesture control decode failed: length mismatch (%d/1)", data_len); } else { handle_gesture_control(*data, data + 1); } } break; case ELEMENT_TYPE_WATCHCONFIG: { int data_len = get_element_data_size(pack, handle, type_buf, type_len); uint8_t* data = get_element_data_buffer(pack, handle, type_buf, type_len); log_info("Set Watch UI Config %d/%d", data_len, (int)sizeof(ui_config)); //if (data_len >= (int)sizeof(ui_config)) handle_set_watch_config((ui_config*)(data + 1)); } break; case ELEMENT_TYPE_UNLOCK_WATCH: handle_unlock_watch(); break; case ELEMENT_TYPE_DAILY_ACTIVITY: handle_daily_activity(); break; } handle = get_next_element(pack, handle); } }
/* * Verify lvalue It doesn't repeat a checks that are done. Checks a subscript * expressions, verify a validity of record's fields. */ void plpgsql_check_target(PLpgSQL_checkstate *cstate, int varno, Oid *expected_typoid, int *expected_typmod) { PLpgSQL_datum *target = cstate->estate->datums[varno]; plpgsql_check_record_variable_usage(cstate, varno, true); switch (target->dtype) { case PLPGSQL_DTYPE_VAR: { PLpgSQL_var *var = (PLpgSQL_var *) target; PLpgSQL_type *tp = var->datatype; if (expected_typoid != NULL) *expected_typoid = tp->typoid; if (expected_typmod != NULL) *expected_typmod = tp->atttypmod; } break; case PLPGSQL_DTYPE_REC: { PLpgSQL_rec *rec = (PLpgSQL_rec *) target; #if PG_VERSION_NUM >= 110000 if (rec->rectypeid != RECORDOID) { if (expected_typoid != NULL) *expected_typoid = rec->rectypeid; if (expected_typmod != NULL) *expected_typmod = -1; } else #endif if (recvar_tupdesc(rec) != NULL) { if (expected_typoid != NULL) *expected_typoid = recvar_tupdesc(rec)->tdtypeid; if (expected_typmod != NULL) *expected_typmod = recvar_tupdesc(rec)->tdtypmod; } else { if (expected_typoid != NULL) *expected_typoid = RECORDOID; if (expected_typmod != NULL) *expected_typmod = -1; } } break; case PLPGSQL_DTYPE_ROW: { PLpgSQL_row *row = (PLpgSQL_row *) target; if (row->rowtupdesc != NULL) { if (expected_typoid != NULL) *expected_typoid = row->rowtupdesc->tdtypeid; if (expected_typmod != NULL) *expected_typmod = row->rowtupdesc->tdtypmod; } else { if (expected_typoid != NULL) *expected_typoid = RECORDOID; if (expected_typmod != NULL) *expected_typmod = -1; } plpgsql_check_row_or_rec(cstate, row, NULL); } break; case PLPGSQL_DTYPE_RECFIELD: { PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target; PLpgSQL_rec *rec; int fno; rec = (PLpgSQL_rec *) (cstate->estate->datums[recfield->recparentno]); /* * Check that there is already a tuple in the record. We need * that because records don't have any predefined field * structure. */ if (!HeapTupleIsValid(recvar_tuple(rec))) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("record \"%s\" is not assigned to tuple structure", rec->refname))); /* * Get the number of the records field to change and the * number of attributes in the tuple. Note: disallow system * column names because the code below won't cope. */ fno = SPI_fnumber(recvar_tupdesc(rec), recfield->fieldname); if (fno <= 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("record \"%s\" has no field \"%s\"", rec->refname, recfield->fieldname))); if (expected_typoid) *expected_typoid = SPI_gettypeid(recvar_tupdesc(rec), fno); if (expected_typmod) *expected_typmod = TupleDescAttr(recvar_tupdesc(rec), fno - 1)->atttypmod; } break; case PLPGSQL_DTYPE_ARRAYELEM: { /* * Target is an element of an array */ int nsubscripts; Oid arrayelemtypeid; Oid arraytypeid; /* * To handle constructs like x[1][2] := something, we have to * be prepared to deal with a chain of arrayelem datums. Chase * back to find the base array datum, and save the subscript * expressions as we go. (We are scanning right to left here, * but want to evaluate the subscripts left-to-right to * minimize surprises.) */ nsubscripts = 0; do { PLpgSQL_arrayelem *arrayelem = (PLpgSQL_arrayelem *) target; if (nsubscripts++ >= MAXDIM) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)", nsubscripts + 1, MAXDIM))); plpgsql_check_expr(cstate, arrayelem->subscript); target = cstate->estate->datums[arrayelem->arrayparentno]; } while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM); /* * If target is domain over array, reduce to base type */ #if PG_VERSION_NUM >= 90600 arraytypeid = plpgsql_exec_get_datum_type(cstate->estate, target); #else arraytypeid = exec_get_datum_type(cstate->estate, target); #endif arraytypeid = getBaseType(arraytypeid); arrayelemtypeid = get_element_type(arraytypeid); if (!OidIsValid(arrayelemtypeid)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("subscripted object is not an array"))); if (expected_typoid) *expected_typoid = arrayelemtypeid; if (expected_typmod) *expected_typmod = ((PLpgSQL_var *) target)->datatype->atttypmod; plpgsql_check_record_variable_usage(cstate, target->dno, true); } break; default: ; /* nope */ } }
/* * get_sort_group_operators - get default sorting/grouping operators for type * * We fetch the "<", "=", and ">" operators all at once to reduce lookup * overhead (knowing that most callers will be interested in at least two). * However, a given datatype might have only an "=" operator, if it is * hashable but not sortable. (Other combinations of present and missing * operators shouldn't happen, unless the system catalogs are messed up.) * * If an operator is missing and the corresponding needXX flag is true, * throw a standard error message, else return InvalidOid. * * Callers can pass NULL pointers for any results they don't care to get. * * Note: the results are guaranteed to be exact or binary-compatible matches, * since most callers are not prepared to cope with adding any run-time type * coercion steps. */ void get_sort_group_operators(Oid argtype, bool needLT, bool needEQ, bool needGT, Oid *ltOpr, Oid *eqOpr, Oid *gtOpr) { TypeCacheEntry *typentry; Oid lt_opr; Oid eq_opr; Oid gt_opr; /* * Look up the operators using the type cache. * * Note: the search algorithm used by typcache.c ensures that the results * are consistent, ie all from the same opclass. */ typentry = lookup_type_cache(argtype, TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR); lt_opr = typentry->lt_opr; eq_opr = typentry->eq_opr; gt_opr = typentry->gt_opr; /* * If the datatype is an array, then we can use array_lt and friends ... * but only if there are suitable operators for the element type. (This * check is not in the raw typcache.c code ... should it be?) Testing all * three operator IDs here should be redundant, but let's do it anyway. */ if (lt_opr == ARRAY_LT_OP || eq_opr == ARRAY_EQ_OP || gt_opr == ARRAY_GT_OP) { Oid elem_type = get_element_type(argtype); if (OidIsValid(elem_type)) { typentry = lookup_type_cache(elem_type, TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR); #ifdef NOT_USED /* We should do this ... */ if (!OidIsValid(typentry->eq_opr)) { /* element type is neither sortable nor hashable */ lt_opr = eq_opr = gt_opr = InvalidOid; } else if (!OidIsValid(typentry->lt_opr) || !OidIsValid(typentry->gt_opr)) { /* element type is hashable but not sortable */ lt_opr = gt_opr = InvalidOid; } #else /* * ... but for the moment we have to do this. This is because * anyarray has sorting but not hashing support. So, if the * element type is only hashable, there is nothing we can do * with the array type. */ if (!OidIsValid(typentry->lt_opr) || !OidIsValid(typentry->eq_opr) || !OidIsValid(typentry->gt_opr)) lt_opr = eq_opr = gt_opr = InvalidOid; /* not sortable */ #endif } else lt_opr = eq_opr = gt_opr = InvalidOid; /* bogus array type? */ } /* Report errors if needed */ if ((needLT && !OidIsValid(lt_opr)) || (needGT && !OidIsValid(gt_opr))) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not identify an ordering operator for type %s", format_type_be(argtype)), errhint("Use an explicit ordering operator or modify the query."))); if (needEQ && !OidIsValid(eq_opr)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("could not identify an equality operator for type %s", format_type_be(argtype)))); /* Return results as needed */ if (ltOpr) *ltOpr = lt_opr; if (eqOpr) *eqOpr = eq_opr; if (gtOpr) *gtOpr = gt_opr; }
/* ---------------------------------------------------------------- * ProcedureCreate * * Note: allParameterTypes, parameterModes, parameterNames, trftypes, and proconfig * are either arrays of the proper types or NULL. We declare them Datum, * not "ArrayType *", to avoid importing array.h into pg_proc.h. * ---------------------------------------------------------------- */ ObjectAddress ProcedureCreate(const char *procedureName, Oid procNamespace, bool replace, bool returnsSet, Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char *prosrc, const char *probin, char prokind, bool security_definer, bool isLeakProof, bool isStrict, char volatility, char parallel, oidvector *parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames, List *parameterDefaults, Datum trftypes, Datum proconfig, float4 procost, float4 prorows) { Oid retval; int parameterCount; int allParamCount; Oid *allParams; char *paramModes = NULL; bool genericInParam = false; bool genericOutParam = false; bool anyrangeInParam = false; bool anyrangeOutParam = false; bool internalInParam = false; bool internalOutParam = false; Oid variadicType = InvalidOid; Acl *proacl = NULL; Relation rel; HeapTuple tup; HeapTuple oldtup; bool nulls[Natts_pg_proc]; Datum values[Natts_pg_proc]; bool replaces[Natts_pg_proc]; NameData procname; TupleDesc tupDesc; bool is_update; ObjectAddress myself, referenced; int i; Oid trfid; /* * sanity checks */ Assert(PointerIsValid(prosrc)); parameterCount = parameterTypes->dim1; if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("functions cannot have more than %d argument", "functions cannot have more than %d arguments", FUNC_MAX_ARGS, FUNC_MAX_ARGS))); /* note: the above is correct, we do NOT count output arguments */ /* Deconstruct array inputs */ if (allParameterTypes != PointerGetDatum(NULL)) { /* * We expect the array to be a 1-D OID array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of OID values. */ ArrayType *allParamArray = (ArrayType *) DatumGetPointer(allParameterTypes); allParamCount = ARR_DIMS(allParamArray)[0]; if (ARR_NDIM(allParamArray) != 1 || allParamCount <= 0 || ARR_HASNULL(allParamArray) || ARR_ELEMTYPE(allParamArray) != OIDOID) elog(ERROR, "allParameterTypes is not a 1-D Oid array"); allParams = (Oid *) ARR_DATA_PTR(allParamArray); Assert(allParamCount >= parameterCount); /* we assume caller got the contents right */ } else { allParamCount = parameterCount; allParams = parameterTypes->values; } if (parameterModes != PointerGetDatum(NULL)) { /* * We expect the array to be a 1-D CHAR array; verify that. We don't * need to use deconstruct_array() since the array data is just going * to look like a C array of char values. */ ArrayType *modesArray = (ArrayType *) DatumGetPointer(parameterModes); if (ARR_NDIM(modesArray) != 1 || ARR_DIMS(modesArray)[0] != allParamCount || ARR_HASNULL(modesArray) || ARR_ELEMTYPE(modesArray) != CHAROID) elog(ERROR, "parameterModes is not a 1-D char array"); paramModes = (char *) ARR_DATA_PTR(modesArray); } /* * Detect whether we have polymorphic or INTERNAL arguments. The first * loop checks input arguments, the second output arguments. */ for (i = 0; i < parameterCount; i++) { switch (parameterTypes->values[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericInParam = true; break; case ANYRANGEOID: genericInParam = true; anyrangeInParam = true; break; case INTERNALOID: internalInParam = true; break; } } if (allParameterTypes != PointerGetDatum(NULL)) { for (i = 0; i < allParamCount; i++) { if (paramModes == NULL || paramModes[i] == PROARGMODE_IN || paramModes[i] == PROARGMODE_VARIADIC) continue; /* ignore input-only params */ switch (allParams[i]) { case ANYARRAYOID: case ANYELEMENTOID: case ANYNONARRAYOID: case ANYENUMOID: genericOutParam = true; break; case ANYRANGEOID: genericOutParam = true; anyrangeOutParam = true; break; case INTERNALOID: internalOutParam = true; break; } } } /* * Do not allow polymorphic return type unless at least one input argument * is polymorphic. ANYRANGE return type is even stricter: must have an * ANYRANGE input (since we can't deduce the specific range type from * ANYELEMENT). Also, do not allow return type INTERNAL unless at least * one input argument is INTERNAL. */ if ((IsPolymorphicType(returnType) || genericOutParam) && !genericInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning a polymorphic type must have at least one polymorphic argument."))); if ((returnType == ANYRANGEOID || anyrangeOutParam) && !anyrangeInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot determine result data type"), errdetail("A function returning \"anyrange\" must have at least one \"anyrange\" argument."))); if ((returnType == INTERNALOID || internalOutParam) && !internalInParam) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("unsafe use of pseudo-type \"internal\""), errdetail("A function returning \"internal\" must have at least one \"internal\" argument."))); if (paramModes != NULL) { /* * Only the last input parameter can be variadic; if it is, save its * element type. Errors here are just elog since caller should have * checked this already. */ for (i = 0; i < allParamCount; i++) { switch (paramModes[i]) { case PROARGMODE_IN: case PROARGMODE_INOUT: if (OidIsValid(variadicType)) elog(ERROR, "variadic parameter must be last"); break; case PROARGMODE_OUT: case PROARGMODE_TABLE: /* okay */ break; case PROARGMODE_VARIADIC: if (OidIsValid(variadicType)) elog(ERROR, "variadic parameter must be last"); switch (allParams[i]) { case ANYOID: variadicType = ANYOID; break; case ANYARRAYOID: variadicType = ANYELEMENTOID; break; default: variadicType = get_element_type(allParams[i]); if (!OidIsValid(variadicType)) elog(ERROR, "variadic parameter is not an array"); break; } break; default: elog(ERROR, "invalid parameter mode '%c'", paramModes[i]); break; } } } /* * All seems OK; prepare the data to be inserted into pg_proc. */ for (i = 0; i < Natts_pg_proc; ++i) { nulls[i] = false; values[i] = (Datum) 0; replaces[i] = true; } namestrcpy(&procname, procedureName); values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname); values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace); values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(proowner); values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId); values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost); values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows); values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType); values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid); values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind); values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer); values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof); values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict); values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet); values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility); values[Anum_pg_proc_proparallel - 1] = CharGetDatum(parallel); values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount); values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults)); values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType); values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes); if (allParameterTypes != PointerGetDatum(NULL)) values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes; else nulls[Anum_pg_proc_proallargtypes - 1] = true; if (parameterModes != PointerGetDatum(NULL)) values[Anum_pg_proc_proargmodes - 1] = parameterModes; else nulls[Anum_pg_proc_proargmodes - 1] = true; if (parameterNames != PointerGetDatum(NULL)) values[Anum_pg_proc_proargnames - 1] = parameterNames; else nulls[Anum_pg_proc_proargnames - 1] = true; if (parameterDefaults != NIL) values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults)); else nulls[Anum_pg_proc_proargdefaults - 1] = true; if (trftypes != PointerGetDatum(NULL)) values[Anum_pg_proc_protrftypes - 1] = trftypes; else nulls[Anum_pg_proc_protrftypes - 1] = true; values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc); if (probin) values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin); else nulls[Anum_pg_proc_probin - 1] = true; if (proconfig != PointerGetDatum(NULL)) values[Anum_pg_proc_proconfig - 1] = proconfig; else nulls[Anum_pg_proc_proconfig - 1] = true; /* proacl will be determined later */ rel = table_open(ProcedureRelationId, RowExclusiveLock); tupDesc = RelationGetDescr(rel); /* Check for pre-existing definition */ oldtup = SearchSysCache3(PROCNAMEARGSNSP, PointerGetDatum(procedureName), PointerGetDatum(parameterTypes), ObjectIdGetDatum(procNamespace)); if (HeapTupleIsValid(oldtup)) { /* There is one; okay to replace it? */ Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup); Datum proargnames; bool isnull; const char *dropcmd; if (!replace) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function \"%s\" already exists with same argument types", procedureName))); if (!pg_proc_ownercheck(oldproc->oid, proowner)) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION, procedureName); /* Not okay to change routine kind */ if (oldproc->prokind != prokind) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot change routine kind"), (oldproc->prokind == PROKIND_AGGREGATE ? errdetail("\"%s\" is an aggregate function.", procedureName) : oldproc->prokind == PROKIND_FUNCTION ? errdetail("\"%s\" is a function.", procedureName) : oldproc->prokind == PROKIND_PROCEDURE ? errdetail("\"%s\" is a procedure.", procedureName) : oldproc->prokind == PROKIND_WINDOW ? errdetail("\"%s\" is a window function.", procedureName) : 0))); dropcmd = (prokind == PROKIND_PROCEDURE ? "DROP PROCEDURE" : "DROP FUNCTION"); /* * Not okay to change the return type of the existing proc, since * existing rules, views, etc may depend on the return type. * * In case of a procedure, a changing return type means that whether * the procedure has output parameters was changed. Since there is no * user visible return type, we produce a more specific error message. */ if (returnType != oldproc->prorettype || returnsSet != oldproc->proretset) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), prokind == PROKIND_PROCEDURE ? errmsg("cannot change whether a procedure has output parameters") : errmsg("cannot change return type of existing function"), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); /* * If it returns RECORD, check for possible change of record type * implied by OUT parameters */ if (returnType == RECORDOID) { TupleDesc olddesc; TupleDesc newdesc; olddesc = build_function_result_tupdesc_t(oldtup); newdesc = build_function_result_tupdesc_d(prokind, allParameterTypes, parameterModes, parameterNames); if (olddesc == NULL && newdesc == NULL) /* ok, both are runtime-defined RECORDs */ ; else if (olddesc == NULL || newdesc == NULL || !equalTupleDescs(olddesc, newdesc)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change return type of existing function"), errdetail("Row type defined by OUT parameters is different."), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); } /* * If there were any named input parameters, check to make sure the * names have not been changed, as this could break existing calls. We * allow adding names to formerly unnamed parameters, though. */ proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargnames, &isnull); if (!isnull) { Datum proargmodes; char **old_arg_names; char **new_arg_names; int n_old_arg_names; int n_new_arg_names; int j; proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargmodes, &isnull); if (isnull) proargmodes = PointerGetDatum(NULL); /* just to be sure */ n_old_arg_names = get_func_input_arg_names(proargnames, proargmodes, &old_arg_names); n_new_arg_names = get_func_input_arg_names(parameterNames, parameterModes, &new_arg_names); for (j = 0; j < n_old_arg_names; j++) { if (old_arg_names[j] == NULL) continue; if (j >= n_new_arg_names || new_arg_names[j] == NULL || strcmp(old_arg_names[j], new_arg_names[j]) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change name of input parameter \"%s\"", old_arg_names[j]), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); } } /* * If there are existing defaults, check compatibility: redefinition * must not remove any defaults nor change their types. (Removing a * default might cause a function to fail to satisfy an existing call. * Changing type would only be possible if the associated parameter is * polymorphic, and in such cases a change of default type might alter * the resolved output type of existing calls.) */ if (oldproc->pronargdefaults != 0) { Datum proargdefaults; List *oldDefaults; ListCell *oldlc; ListCell *newlc; if (list_length(parameterDefaults) < oldproc->pronargdefaults) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot remove parameter defaults from existing function"), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); proargdefaults = SysCacheGetAttr(PROCNAMEARGSNSP, oldtup, Anum_pg_proc_proargdefaults, &isnull); Assert(!isnull); oldDefaults = castNode(List, stringToNode(TextDatumGetCString(proargdefaults))); Assert(list_length(oldDefaults) == oldproc->pronargdefaults); /* new list can have more defaults than old, advance over 'em */ newlc = list_head(parameterDefaults); for (i = list_length(parameterDefaults) - oldproc->pronargdefaults; i > 0; i--) newlc = lnext(newlc); foreach(oldlc, oldDefaults) { Node *oldDef = (Node *) lfirst(oldlc); Node *newDef = (Node *) lfirst(newlc); if (exprType(oldDef) != exprType(newDef)) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("cannot change data type of existing parameter default value"), /* translator: first %s is DROP FUNCTION or DROP PROCEDURE */ errhint("Use %s %s first.", dropcmd, format_procedure(oldproc->oid)))); newlc = lnext(newlc); } }
/* * Determine how we want to render values of a given type in datum_to_jsonb. * * Given the datatype OID, return its JsonbTypeCategory, as well as the type's * output function OID. If the returned category is JSONBTYPE_JSONCAST, * we return the OID of the relevant cast function instead. */ static void jsonb_categorize_type(Oid typoid, JsonbTypeCategory *tcategory, Oid *outfuncoid) { bool typisvarlena; /* Look through any domain */ typoid = getBaseType(typoid); *outfuncoid = InvalidOid; /* * We need to get the output function for everything except date and * timestamp types, booleans, array and composite types, json and jsonb, * and non-builtin types where there's a cast to json. In this last case * we return the oid of the cast function instead. */ switch (typoid) { case BOOLOID: *tcategory = JSONBTYPE_BOOL; break; case INT2OID: case INT4OID: case INT8OID: case FLOAT4OID: case FLOAT8OID: case NUMERICOID: getTypeOutputInfo(typoid, outfuncoid, &typisvarlena); *tcategory = JSONBTYPE_NUMERIC; break; case DATEOID: *tcategory = JSONBTYPE_DATE; break; case TIMESTAMPOID: *tcategory = JSONBTYPE_TIMESTAMP; break; case TIMESTAMPTZOID: *tcategory = JSONBTYPE_TIMESTAMPTZ; break; case JSONBOID: *tcategory = JSONBTYPE_JSONB; break; case JSONOID: *tcategory = JSONBTYPE_JSON; break; default: /* Check for arrays and composites */ if (OidIsValid(get_element_type(typoid))) *tcategory = JSONBTYPE_ARRAY; else if (type_is_rowtype(typoid)) *tcategory = JSONBTYPE_COMPOSITE; else { /* It's probably the general case ... */ *tcategory = JSONBTYPE_OTHER; /* * but first let's look for a cast to json (note: not to * jsonb) if it's not built-in. */ if (typoid >= FirstNormalObjectId) { Oid castfunc; CoercionPathType ctype; ctype = find_coercion_pathway(JSONOID, typoid, COERCION_EXPLICIT, &castfunc); if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc)) { *tcategory = JSONBTYPE_JSONCAST; *outfuncoid = castfunc; } else { /* not a cast type, so just get the usual output func */ getTypeOutputInfo(typoid, outfuncoid, &typisvarlena); } } else { /* any other builtin type */ getTypeOutputInfo(typoid, outfuncoid, &typisvarlena); } break; } } }