bool Variant::toString(std::string &retVal) { switch (type()) { case VT_Undefined: retVal = "undefined"; return false; case VT_Null: case VT_Type: case VT_Persistent: retVal = "null"; return false; case VT_Boolean: retVal = m_Val.boolVal ? "true" : "false"; return true; case VT_Integer: { char str[STRING_BUF_SIZE]; sprintf(str, "%d", m_Val.intVal); retVal = str; return true; } case VT_Long: { char str[STRING_BUF_SIZE]; #ifdef _WIN32 sprintf(str, "%lld", m_Val.longVal); #else sprintf(str, "%lld", (long long) m_Val.longVal); #endif retVal = str; return true; } case VT_Number: { char str[STRING_BUF_SIZE]; sprintf(str, "%.16g", m_Val.dblVal); retVal = str; return true; } case VT_Date: dateVal().toGMTString(retVal); return true; case VT_Object: return false; case VT_String: retVal = strVal(); return true; case VT_JSValue: return false; } return false; }
/* * intorel_startup --- executor startup */ static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo) { DR_intorel *myState = (DR_intorel *) self; IntoClause *into = myState->into; bool is_matview; char relkind; CreateStmt *create; Oid intoRelationId; Relation intoRelationDesc; RangeTblEntry *rte; Datum toast_options; ListCell *lc; int attnum; static char *validnsps[] = HEAP_RELOPT_NAMESPACES; Assert(into != NULL); /* else somebody forgot to set it */ /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */ is_matview = (into->viewQuery != NULL); relkind = is_matview ? RELKIND_MATVIEW : RELKIND_RELATION; /* * Create the target relation by faking up a CREATE TABLE parsetree and * passing it to DefineRelation. */ create = makeNode(CreateStmt); create->relation = into->rel; create->tableElts = NIL; /* will fill below */ create->inhRelations = NIL; create->ofTypename = NULL; create->constraints = NIL; create->options = into->options; create->oncommit = into->onCommit; create->tablespacename = into->tableSpaceName; create->if_not_exists = false; /* * Build column definitions using "pre-cooked" type and collation info. If * a column name list was specified in CREATE TABLE AS, override the * column names derived from the query. (Too few column names are OK, too * many are not.) */ lc = list_head(into->colNames); for (attnum = 0; attnum < typeinfo->natts; attnum++) { Form_pg_attribute attribute = typeinfo->attrs[attnum]; ColumnDef *col = makeNode(ColumnDef); TypeName *coltype = makeNode(TypeName); if (lc) { col->colname = strVal(lfirst(lc)); lc = lnext(lc); } else col->colname = NameStr(attribute->attname); col->typeName = coltype; col->inhcount = 0; col->is_local = true; col->is_not_null = false; col->is_from_type = false; col->storage = 0; col->raw_default = NULL; col->cooked_default = NULL; col->collClause = NULL; col->collOid = attribute->attcollation; col->constraints = NIL; col->fdwoptions = NIL; coltype->names = NIL; coltype->typeOid = attribute->atttypid; coltype->setof = false; coltype->pct_type = false; coltype->typmods = NIL; coltype->typemod = attribute->atttypmod; coltype->arrayBounds = NIL; coltype->location = -1; /* * It's possible that the column is of a collatable type but the * collation could not be resolved, so double-check. (We must check * this here because DefineRelation would adopt the type's default * collation rather than complaining.) */ if (!OidIsValid(col->collOid) && type_is_collatable(coltype->typeOid)) ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("no collation was derived for column \"%s\" with collatable type %s", col->colname, format_type_be(coltype->typeOid)), errhint("Use the COLLATE clause to set the collation explicitly."))); create->tableElts = lappend(create->tableElts, col); } if (lc != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("too many column names were specified"))); /* * Actually create the target table */ intoRelationId = DefineRelation(create, relkind, InvalidOid); /* * If necessary, create a TOAST table for the target table. Note that * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that * the TOAST table will be visible for insertion. */ CommandCounterIncrement(); /* parse and validate reloptions for the toast table */ toast_options = transformRelOptions((Datum) 0, create->options, "toast", validnsps, true, false); (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true); AlterTableCreateToastTable(intoRelationId, toast_options); /* Create the "view" part of a materialized view. */ if (is_matview) { /* StoreViewQuery scribbles on tree, so make a copy */ Query *query = (Query *) copyObject(into->viewQuery); StoreViewQuery(intoRelationId, query, false); CommandCounterIncrement(); } /* * Finally we can open the target table */ intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock); /* * Check INSERT permission on the constructed table. * * XXX: It would arguably make sense to skip this check if into->skipData * is true. */ rte = makeNode(RangeTblEntry); rte->rtekind = RTE_RELATION; rte->relid = intoRelationId; rte->relkind = relkind; rte->requiredPerms = ACL_INSERT; for (attnum = 1; attnum <= intoRelationDesc->rd_att->natts; attnum++) rte->modifiedCols = bms_add_member(rte->modifiedCols, attnum - FirstLowInvalidHeapAttributeNumber); ExecCheckRTPerms(list_make1(rte), true); /* * Tentatively mark the target as populated, if it's a matview and we're * going to fill it; otherwise, no change needed. */ if (is_matview && !into->skipData) SetMatViewPopulatedState(intoRelationDesc, true); /* * Fill private fields of myState for use by later routines */ myState->rel = intoRelationDesc; myState->output_cid = GetCurrentCommandId(true); /* * We can skip WAL-logging the insertions, unless PITR or streaming * replication is in use. We can skip the FSM in any case. */ myState->hi_options = HEAP_INSERT_SKIP_FSM | (XLogIsNeeded() ? 0 : HEAP_INSERT_SKIP_WAL); myState->bistate = GetBulkInsertState(); /* Not using WAL requires smgr_targblock be initially invalid */ Assert(RelationGetTargetBlock(intoRelationDesc) == InvalidBlockNumber); }
/* * EnumValuesCreate * Create an entry in pg_enum for each of the supplied enum values. * * vals is a list of Value strings. */ void EnumValuesCreate(Oid enumTypeOid, List *vals) { Relation pg_enum; NameData enumlabel; Oid *oids; int elemno, num_elems; Datum values[Natts_pg_enum]; bool nulls[Natts_pg_enum]; ListCell *lc; HeapTuple tup; num_elems = list_length(vals); /* * We do not bother to check the list of values for duplicates --- if you * have any, you'll get a less-than-friendly unique-index violation. It is * probably not worth trying harder. */ pg_enum = heap_open(EnumRelationId, RowExclusiveLock); /* * Allocate OIDs for the enum's members. * * While this method does not absolutely guarantee that we generate no * duplicate OIDs (since we haven't entered each oid into the table before * allocating the next), trouble could only occur if the OID counter wraps * all the way around before we finish. Which seems unlikely. */ oids = (Oid *) palloc(num_elems * sizeof(Oid)); for (elemno = 0; elemno < num_elems; elemno++) { /* * We assign even-numbered OIDs to all the new enum labels. This * tells the comparison functions the OIDs are in the correct sort * order and can be compared directly. */ Oid new_oid; do { new_oid = GetNewOid(pg_enum); } while (new_oid & 1); oids[elemno] = new_oid; } /* sort them, just in case OID counter wrapped from high to low */ qsort(oids, num_elems, sizeof(Oid), oid_cmp); /* and make the entries */ memset(nulls, false, sizeof(nulls)); elemno = 0; foreach(lc, vals) { char *lab = strVal(lfirst(lc)); /* * labels are stored in a name field, for easier syscache lookup, so * check the length to make sure it's within range. */ if (strlen(lab) > (NAMEDATALEN - 1)) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid enum label \"%s\"", lab), errdetail("Labels must be %d characters or less.", NAMEDATALEN - 1))); values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); values[Anum_pg_enum_enumsortorder - 1] = Float4GetDatum(elemno + 1); namestrcpy(&enumlabel, lab); values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); tup = heap_form_tuple(RelationGetDescr(pg_enum), values, nulls); HeapTupleSetOid(tup, oids[elemno]); simple_heap_insert(pg_enum, tup); CatalogUpdateIndexes(pg_enum, tup); heap_freetuple(tup); elemno++; }
/* * GpPolicyFetch * * Looks up the distribution policy of given relation from * gp_distribution_policy table (or by implicit rules for external tables) * Returns an GpPolicy object, allocated in the specified context, containing * the information. * * The caller is responsible for passing in a valid relation oid. This * function does not check, and assigns a policy of type POLICYTYPE_ENTRY * for any oid not found in gp_distribution_policy. */ GpPolicy * GpPolicyFetch(MemoryContext mcxt, Oid tbloid) { GpPolicy *policy = NULL; /* The result */ Relation gp_policy_rel; cqContext cqc; HeapTuple gp_policy_tuple = NULL; /* * Skip if qExec or utility mode. */ if (Gp_role != GP_ROLE_DISPATCH) { policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_ENTRY; policy->nattrs = 0; return policy; } /* * EXECUTE-type external tables have an "ON ..." specification, stored * in pg_exttable.location. See if it's "MASTER_ONLY". Other types of * external tables have a gp_distribution_policy row, like normal tables. */ if (get_rel_relstorage(tbloid) == RELSTORAGE_EXTERNAL) { /* * An external table really should have a pg_exttable entry, but * there's currently a transient state during creation of an external * table, where the pg_class entry has been created, and its loaded * into the relcache, before the pg_exttable entry has been created. * Silently ignore missing pg_exttable rows to cope with that. */ ExtTableEntry *e = GetExtTableEntryIfExists(tbloid); /* * Writeable external tables have gp_distribution_policy entries, * like regular tables. Readable external tables are implicitly * randomly distributed, except for "EXECUTE ... ON MASTER" ones. */ if (e && !e->iswritable) { if (e->command) { char *on_clause = (char *) strVal(linitial(e->locations)); if (strcmp(on_clause, "MASTER_ONLY") == 0) { policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_ENTRY; policy->nattrs = 0; return policy; } } policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_PARTITIONED; policy->nattrs = 0; return policy; } } /* * We need to read the gp_distribution_policy table */ gp_policy_rel = heap_open(GpPolicyRelationId, AccessShareLock); /* * Select by value of the localoid field */ gp_policy_tuple = caql_getfirst( caql_addrel(cqclr(&cqc), gp_policy_rel), cql("SELECT * FROM gp_distribution_policy " " WHERE localoid = :1 ", ObjectIdGetDatum(tbloid))); /* * Read first (and only) tuple */ if (HeapTupleIsValid(gp_policy_tuple)) { bool isNull; Datum attr; int i, nattrs = 0; int16 *attrnums = NULL; /* * Get the attributes on which to partition. */ attr = heap_getattr(gp_policy_tuple, Anum_gp_policy_attrnums, RelationGetDescr(gp_policy_rel), &isNull); /* * Get distribution keys only if this table has a policy. */ if(!isNull) { extract_INT2OID_array(attr, &nattrs, &attrnums); Assert(nattrs >= 0); } /* Create an GpPolicy object. */ policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(nattrs)); policy->ptype = POLICYTYPE_PARTITIONED; policy->nattrs = nattrs; for (i = 0; i < nattrs; i++) { policy->attrs[i] = attrnums[i]; } } /* * Cleanup the scan and relation objects. */ heap_close(gp_policy_rel, AccessShareLock); /* Interpret absence of a valid policy row as POLICYTYPE_ENTRY */ if (policy == NULL) { policy = (GpPolicy *) MemoryContextAlloc(mcxt, SizeOfGpPolicy(0)); policy->ptype = POLICYTYPE_ENTRY; policy->nattrs = 0; } return policy; } /* GpPolicyFetch */
/* ---------------------------------------------------------------- * ExecInitFunctionScan * ---------------------------------------------------------------- */ FunctionScanState * ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) { FunctionScanState *scanstate; RangeTblEntry *rte; Oid funcrettype; TypeFuncClass functypclass; TupleDesc tupdesc = NULL; /* * FunctionScan should not have any children. */ Assert(outerPlan(node) == NULL); Assert(innerPlan(node) == NULL); /* * create new ScanState for node */ scanstate = makeNode(FunctionScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; /* * Miscellaneous initialization * * create expression context for node */ ExecAssignExprContext(estate, &scanstate->ss.ps); #define FUNCTIONSCAN_NSLOTS 2 /* * tuple table initialization */ ExecInitResultTupleSlot(estate, &scanstate->ss.ps); ExecInitScanTupleSlot(estate, &scanstate->ss); /* * initialize child expressions */ scanstate->ss.ps.targetlist = (List *) ExecInitExpr((Expr *) node->scan.plan.targetlist, (PlanState *) scanstate); scanstate->ss.ps.qual = (List *) ExecInitExpr((Expr *) node->scan.plan.qual, (PlanState *) scanstate); /* Check if targetlist or qual contains a var node referencing the ctid column */ scanstate->cdb_want_ctid = contain_ctid_var_reference(&node->scan); ItemPointerSet(&scanstate->cdb_fake_ctid, 0, 0); ItemPointerSet(&scanstate->cdb_mark_ctid, 0, 0); /* * get info about function */ rte = rt_fetch(node->scan.scanrelid, estate->es_range_table); Assert(rte->rtekind == RTE_FUNCTION); /* * Now determine if the function returns a simple or composite type, and * build an appropriate tupdesc. */ functypclass = get_expr_result_type(rte->funcexpr, &funcrettype, &tupdesc); if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ Assert(tupdesc); /* Must copy it out of typcache for safety */ tupdesc = CreateTupleDescCopy(tupdesc); } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ char *attname = strVal(linitial(rte->eref->colnames)); tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, attname, funcrettype, -1, 0); } else if (functypclass == TYPEFUNC_RECORD) { tupdesc = BuildDescFromLists(rte->eref->colnames, rte->funccoltypes, rte->funccoltypmods); } else { /* crummy error message, but parser should have caught this */ elog(ERROR, "function in FROM has unsupported return type"); } /* * For RECORD results, make sure a typmod has been assigned. (The * function should do this for itself, but let's cover things in case it * doesn't.) */ BlessTupleDesc(tupdesc); scanstate->tupdesc = tupdesc; ExecAssignScanType(&scanstate->ss, tupdesc); /* * Other node-specific setup */ scanstate->tuplestorestate = NULL; scanstate->funcexpr = ExecInitExpr((Expr *) rte->funcexpr, (PlanState *) scanstate); /* * Initialize result tuple type and projection info. */ ExecAssignResultTypeFromTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); initGpmonPktForFunctionScan((Plan *)node, &scanstate->ss.ps.gpmon_pkt, estate); if (gp_resqueue_memory_policy != RESQUEUE_MEMORY_POLICY_NONE) { SPI_ReserveMemory(((Plan *)node)->operatorMemKB * 1024L); } return scanstate; }
/* * Drop a table space * * Be careful to check that the tablespace is empty. */ void RemoveTableSpace(List *names, DropBehavior behavior, bool missing_ok) { char *tablespacename; Relation rel; HeapTuple tuple; cqContext cqc; cqContext *pcqCtx; Oid tablespaceoid; int32 count; RelFileNode relfilenode; DbDirNode dbDirNode; PersistentFileSysState persistentState; ItemPointerData persistentTid; int64 persistentSerialNum; /* * General DROP (object) syntax allows fully qualified names, but * tablespaces are global objects that do not live in schemas, so * it is a syntax error if a fully qualified name was given. */ if (list_length(names) != 1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("tablespace name may not be qualified"))); tablespacename = strVal(linitial(names)); /* Disallow CASCADE */ if (behavior == DROP_CASCADE) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("syntax at or near \"cascade\""))); /* * Find the target tuple */ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); pcqCtx = caql_addrel(cqclr(&cqc), rel); tuple = caql_getfirst( pcqCtx, cql("SELECT * FROM pg_tablespace " " WHERE spcname = :1 " " FOR UPDATE ", CStringGetDatum(tablespacename))); if (!HeapTupleIsValid(tuple)) { /* No such tablespace, no need to hold the lock */ heap_close(rel, RowExclusiveLock); if (!missing_ok) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", tablespacename))); } else { ereport(NOTICE, (errmsg("tablespace \"%s\" does not exist, skipping", tablespacename))); } return; } tablespaceoid = HeapTupleGetOid(tuple); /* Must be tablespace owner */ if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespacename); /* Disallow drop of the standard tablespaces, even by superuser */ if (tablespaceoid == GLOBALTABLESPACE_OID || tablespaceoid == DEFAULTTABLESPACE_OID) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, tablespacename); /* * Check for any databases or relations defined in this tablespace, this * is logically the same as checkSharedDependencies, however we don't * actually track these in pg_shdepend, instead we lookup this information * in the gp_persistent_database/relation_node tables. */ /* ... */ /* * Remove the pg_tablespace tuple (this will roll back if we fail below) */ caql_delete_current(pcqCtx); /* * Remove any comments on this tablespace. */ DeleteSharedComments(tablespaceoid, TableSpaceRelationId); /* * Remove dependency on owner. * * If shared dependencies are added between filespace <=> tablespace * they will be deleted as well. */ deleteSharedDependencyRecordsFor(TableSpaceRelationId, tablespaceoid); /* MPP-6929: metadata tracking */ if (Gp_role == GP_ROLE_DISPATCH) MetaTrackDropObject(TableSpaceRelationId, tablespaceoid); /* * Acquire TablespaceCreateLock to ensure that no * MirroredFileSysObj_JustInTimeDbDirCreate is running concurrently. */ LWLockAcquire(TablespaceCreateLock, LW_EXCLUSIVE); /* * Check for any relations still defined in the tablespace. */ PersistentRelation_CheckTablespace(tablespaceoid, &count, &relfilenode); if (count > 0) { ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("tablespace \"%s\" is not empty", tablespacename))); } /* * Schedule the removal the physical infrastructure. * * Note: This only schedules the delete, the delete won't actually occur * until after the transaction has comitted. This should however do * everything it can to assure that the delete will occur sucessfully, * e.g. check permissions etc. */ /* * Schedule all persistent database directory removals for transaction commit. */ PersistentDatabase_DirIterateInit(); while (PersistentDatabase_DirIterateNext( &dbDirNode, &persistentState, &persistentTid, &persistentSerialNum)) { if (dbDirNode.tablespace != tablespaceoid) continue; /* * Database directory objects can linger in 'Drop Pending' state, etc, * when the mirror is down and needs drop work. So only pay attention * to 'Created' objects. */ if (persistentState != PersistentFileSysState_Created) continue; MirroredFileSysObj_ScheduleDropDbDir( &dbDirNode, &persistentTid, persistentSerialNum); } /* * Now schedule the tablespace directory removal. */ MirroredFileSysObj_ScheduleDropTablespaceDir(tablespaceoid); /* * Note: because we checked that the tablespace was empty, there should be * no need to worry about flushing shared buffers or free space map * entries for relations in the tablespace. * * CHECK THIS, also check if the lock makes any sense in this context. */ /* * Force synchronous commit, to minimize the window between removing the * files on-disk and marking the transaction committed. It's not great * that there is any window at all, but definitely we don't want to make * it larger than necessary. */ ForceSyncCommit(); /* * Allow MirroredFileSysObj_JustInTimeDbDirCreate again. */ LWLockRelease(TablespaceCreateLock); /* We keep the lock on the row in pg_tablespace until commit */ heap_close(rel, NoLock); /* Note: no need for dispatch, that is handled in utility.c */ return; }
/* ---------------------------------------------------------------- * ExecInitFunctionScan * ---------------------------------------------------------------- */ FunctionScanState * ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) { FunctionScanState *scanstate; Oid funcrettype; TypeFuncClass functypclass; TupleDesc tupdesc = NULL; /* check for unsupported flags */ Assert(!(eflags & EXEC_FLAG_MARK)); /* * FunctionScan should not have any children. */ Assert(outerPlan(node) == NULL); Assert(innerPlan(node) == NULL); /* * create new ScanState for node */ scanstate = makeNode(FunctionScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; scanstate->eflags = eflags; /* * Miscellaneous initialization * * create expression context for node */ ExecAssignExprContext(estate, &scanstate->ss.ps); /* * tuple table initialization */ ExecInitResultTupleSlot(estate, &scanstate->ss.ps); ExecInitScanTupleSlot(estate, &scanstate->ss); /* * initialize child expressions */ scanstate->ss.ps.targetlist = (List *) ExecInitExpr((Expr *) node->scan.plan.targetlist, (PlanState *) scanstate); scanstate->ss.ps.qual = (List *) ExecInitExpr((Expr *) node->scan.plan.qual, (PlanState *) scanstate); /* * Now determine if the function returns a simple or composite type, and * build an appropriate tupdesc. */ functypclass = get_expr_result_type(node->funcexpr, &funcrettype, &tupdesc); if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ Assert(tupdesc); /* Must copy it out of typcache for safety */ tupdesc = CreateTupleDescCopy(tupdesc); } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ char *attname = strVal(linitial(node->funccolnames)); tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, attname, funcrettype, -1, 0); } else if (functypclass == TYPEFUNC_RECORD) { tupdesc = BuildDescFromLists(node->funccolnames, node->funccoltypes, node->funccoltypmods); } else { /* crummy error message, but parser should have caught this */ elog(ERROR, "function in FROM has unsupported return type"); } /* * For RECORD results, make sure a typmod has been assigned. (The * function should do this for itself, but let's cover things in case it * doesn't.) */ BlessTupleDesc(tupdesc); scanstate->tupdesc = tupdesc; ExecAssignScanType(&scanstate->ss, tupdesc); /* * Other node-specific setup */ scanstate->tuplestorestate = NULL; scanstate->funcexpr = ExecInitExpr((Expr *) node->funcexpr, (PlanState *) scanstate); scanstate->ss.ps.ps_TupFromTlist = false; /* * Initialize result tuple type and projection info. */ ExecAssignResultTypeFromTL(&scanstate->ss.ps); ExecAssignScanProjectionInfo(&scanstate->ss); return scanstate; }
void OTVariable::Serialize(OTString & strAppend, bool bCalculatingID/*=false*/) { // --------------------------------------- std::string str_access(""); switch (m_Access) { case OTVariable::Var_Constant: // This cannot be changed from inside the script. str_access = "constant"; break; case OTVariable::Var_Persistent: // This can be changed without notifying the parties. str_access = "persistent"; break; case OTVariable::Var_Important: // This cannot be changed without notifying the parties. str_access = "important"; break; default: OTLog::Error("OTVariable::Serialize: ERROR: Bad variable type.\n"); break; } // --------------------------------------- std::string str_type; switch (m_Type) { case OTVariable::Var_String: { str_type = "string"; if ((false == bCalculatingID) && // we don't serialize the variable's value when calculating the (m_str_Value.size() > 0)) // owner OTScriptable's ID, since the value can change over time. { OTString strVal(m_str_Value.c_str()); OTASCIIArmor ascVal(strVal); strAppend.Concatenate("<variable\n name=\"%s\"\n" " value=\"%s\"\n" " type=\"%s\"\n" " access=\"%s\" >\n%s</variable>\n\n", m_strName.Get(), "exists", str_type.c_str(), str_access.c_str(), ascVal.Get()); } else { strAppend.Concatenate("<variable\n name=\"%s\"\n" " value=\"%s\"\n" " type=\"%s\"\n" " access=\"%s\" />\n\n", m_strName.Get(), "none", // value str_type.c_str(), str_access.c_str()); } } break; case OTVariable::Var_Integer: str_type = "integer"; strAppend.Concatenate("<variable\n name=\"%s\"\n" " value=\"%d\"\n" " type=\"%s\"\n" " access=\"%s\" />\n\n", m_strName.Get(), bCalculatingID ? 0 : m_nValue, // we don't serialize the variable's value when calculating the smart contract's ID. str_type.c_str(), str_access.c_str()); break; case OTVariable::Var_Bool: str_type = "bool"; strAppend.Concatenate("<variable\n name=\"%s\"\n" " value=\"%s\"\n" " type=\"%s\"\n" " access=\"%s\" />\n\n", m_strName.Get(), bCalculatingID ? "false" : (m_bValue ? "true" : "false"), // we don't serialize the variable's value when calculating the smart contract's ID. str_type.c_str(), str_access.c_str()); break; default: str_type = "ERROR_VARIABLE_TYPE"; OTLog::Error("OTVariable::Serialize: Error, Wrong Type -- not serializing.\n"); break; } // --------------------------------------- }
/* * DefineFileSystem */ void DefineFileSystem(List *name, List *parameters, Oid newOid, bool trusted) { char *fsysName; Oid fsysNamespace; AclResult aclresult; List *funcNames[FSYS_FUNC_TOTALNUM]; char *fsysLibFile = NULL; int funcNum = 0; ListCell *pl; Oid fsysOid; /* Convert list of names to a name and namespace */ fsysNamespace = QualifiedNameGetCreationNamespace(name, &fsysName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(fsysNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(fsysNamespace)); for(int i = 0; i < FSYS_FUNC_TOTALNUM; i++) funcNames[i] = NIL; foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); int funcType; if (pg_strcasecmp(defel->defname, fsysLibFileName) == 0) { if(fsysLibFile == NULL) { fsysLibFile = strVal(linitial(defGetQualifiedName(defel))); } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("filesystem attribute \"%s\" duplicated", defel->defname))); } continue; } for(funcType = 0; funcType < FSYS_FUNC_TOTALNUM; funcType++) { if(pg_strcasecmp(defel->defname, fsys_func_type_to_name(funcType)) == 0) break; } if (funcType >= FSYS_FUNC_TOTALNUM) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("filesystem attribute \"%s\" not recognized", defel->defname))); if(funcNames[funcType] == NIL) funcNames[funcType] = defGetQualifiedName(defel); else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("filesystem function \"%s\" duplicated", defel->defname))); funcNum++; }
void parseHwParameters(List *parameterList, HoltWintersModel *specificModel) { ListCell *cell; foreach(cell,parameterList) { AlgorithmParameter *param = lfirst(cell); /* Seasonflag*/ if(strcmp(param->key,"has_season") == 0) { if(IsA(&(param->value->val),Integer)) { specificModel->doseasonal = intVal(¶m->value->val); specificModel->optflag[2]=specificModel->doseasonal; } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an Integer value"), errposition(param->value->location))); } else if(strcmp(param->key,"has_trend") == 0) { if(IsA(&(param->value->val),Integer)) { specificModel->dotrend = intVal(¶m->value->val); specificModel->optflag[1]=specificModel->dotrend; } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an Integer value"), errposition(param->value->location))); } else if(strcmp(param->key,"seasontype") == 0) { if(IsA(&(param->value->val),Integer)) { specificModel->seasonType = intVal(¶m->value->val); } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an Integer value"), errposition(param->value->location))); } else if(strcmp(param->key,"alpha") == 0) { if(IsA(&(param->value->val),Float)) { specificModel->alpha = floatVal(¶m->value->val); specificModel->optflag[0]=0; } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an float value"), errposition(param->value->location))); }else if(strcmp(param->key,"beta") == 0) { if(IsA(&(param->value->val),Float)) { specificModel->beta = floatVal(¶m->value->val); specificModel->optflag[1]=0; specificModel->dotrend=1; } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an float value"), errposition(param->value->location))); }else if(strcmp(param->key,"gamma") == 0) { if(IsA(&(param->value->val),Float)) { specificModel->gamma = floatVal(¶m->value->val); specificModel->optflag[2]=0; specificModel->doseasonal=1; } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an float value"), errposition(param->value->location))); }else if(strcmp(param->key,"season") == 0) { if(IsA(&(param->value->val),Integer)) { specificModel->period = intVal(¶m->value->val); specificModel->doseasonal = 1; specificModel->optflag[2]=specificModel->doseasonal; } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an Integer value"), errposition(param->value->location))); } else if(strcmp(param->key,"error") == 0) { if(IsA(&(param->value->val),String)) { specificModel->errorfunction = palloc0((strlen(strVal(¶m->value->val))+1)*sizeof(char)); strcpy(specificModel->errorfunction,strVal(¶m->value->val)); } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter value has to be an String value"), errposition(param->value->location))); } else ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Parameter not known"), errposition(((A_Const *)param->value)->location))); }
/* * Executes an ALTER OBJECT / OWNER TO statement. Based on the object * type, the function appropriate to that type is executed. */ void ExecAlterOwnerStmt(AlterOwnerStmt *stmt) { Oid newowner = get_role_oid(stmt->newowner, false); switch (stmt->objectType) { case OBJECT_AGGREGATE: AlterAggregateOwner(stmt->object, stmt->objarg, newowner); break; case OBJECT_CONVERSION: AlterConversionOwner(stmt->object, newowner); break; case OBJECT_DATABASE: AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_FUNCTION: AlterFunctionOwner(stmt->object, stmt->objarg, newowner); break; case OBJECT_LANGUAGE: AlterLanguageOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_LARGEOBJECT: LargeObjectAlterOwner(oidparse(linitial(stmt->object)), newowner); break; case OBJECT_OPERATOR: Assert(list_length(stmt->objarg) == 2); AlterOperatorOwner(stmt->object, (TypeName *) linitial(stmt->objarg), (TypeName *) lsecond(stmt->objarg), newowner); break; case OBJECT_OPCLASS: AlterOpClassOwner(stmt->object, stmt->addname, newowner); break; case OBJECT_OPFAMILY: AlterOpFamilyOwner(stmt->object, stmt->addname, newowner); break; case OBJECT_SCHEMA: AlterSchemaOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_TABLESPACE: AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_TYPE: case OBJECT_DOMAIN: /* same as TYPE */ AlterTypeOwner(stmt->object, newowner); break; case OBJECT_TSDICTIONARY: AlterTSDictionaryOwner(stmt->object, newowner); break; case OBJECT_TSCONFIGURATION: AlterTSConfigurationOwner(stmt->object, newowner); break; case OBJECT_FDW: AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_FOREIGN_SERVER: AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner); break; default: elog(ERROR, "unrecognized AlterOwnerStmt type: %d", (int) stmt->objectType); } }
TEST(ExpandWalkerTests, All) { ValCase cases[] = { {"substitute string", "foo=bar boo=${foo}", "boo", "bar", hit::Field::Kind::String}, {"trailing space", "foo=bar boo=${foo} ", "boo", "bar", hit::Field::Kind::String}, {"substute number", "foo=42 boo=${foo}", "boo", "42", hit::Field::Kind::Int}, {"multiple replacements", "foo=42 boo='${foo} ${foo}'", "boo", "42 42", hit::Field::Kind::String}, {"nested", "foo=bar [hello] boo='${foo}' []", "hello/boo", "bar", hit::Field::Kind::String}, {"repl-header-before", "src=foo [src] bar='${src}' []", "src/bar", "foo", hit::Field::Kind::String}, {"repl-header-missing", "[src] bar='${src}' []", "src/bar", "${src}", hit::Field::Kind::None}, {"repl-header-shadow", "[src] bar='${src}' [] src=foo", "src/bar", "${src}", hit::Field::Kind::None}, {"nested shadow", "foo=bar [hello] foo=baz boo='${foo}' []", "hello/boo", "baz", hit::Field::Kind::String}, }; for (size_t i = 0; i < sizeof(cases) / sizeof(ValCase); i++) { auto test = cases[i]; hit::Node * root = nullptr; try { root = hit::parse("TEST", test.input); ExpandWalker exw("TEST"); root->walk(&exw); if (exw.errors.size() > 0 && test.kind != hit::Field::Kind::None) { for (auto & err : exw.errors) FAIL() << "case " << i + 1 << " unexpected error: " << err << "\n"; continue; } else if (exw.errors.size() == 0 && test.kind == hit::Field::Kind::None) { FAIL() << "case " << i + 1 << " missing expected error\n"; continue; } } catch (std::exception & err) { FAIL() << "case " << i + 1 << " unexpected error: " << err.what() << "\n"; continue; } auto n = root->find(test.key); if (!n) { FAIL() << "case " << i + 1 << " failed to find key '" << test.key << "'\n"; continue; } if (n->strVal() != test.val) { FAIL() << "case " << i + 1 << " wrong value (key=" << test.key << "): got '" << n->strVal() << "', want '" << test.val << "'\n"; continue; } auto f = dynamic_cast<hit::Field *>(n); if (!f) FAIL() << "case " << i + 1 << " node type is not NodeType::Field"; else if (test.kind != hit::Field::Kind::None && f->kind() != test.kind) FAIL() << "case " << i + 1 << " wrong kind (key=" << test.key << "): got '" << strkind(f->kind()) << "', want '" << strkind(test.kind) << "'\n"; } }
TEST(HitTests, ParseFields) { ValCase cases[] = { // types {"int", "foo=42", "foo", "42", hit::Field::Kind::Int}, {"float1", "foo=4.2", "foo", "4.2", hit::Field::Kind::Float}, {"float2", "foo=.42", "foo", ".42", hit::Field::Kind::Float}, {"float3", "foo=1e10", "foo", "1e10", hit::Field::Kind::Float}, {"float4", "foo=e-23", "foo", "e-23", hit::Field::Kind::Float}, {"float5", "foo=12.345e+67", "foo", "12.345e+67", hit::Field::Kind::Float}, {"bool-true1", "foo=true", "foo", "true", hit::Field::Kind::Bool}, {"bool-true2", "foo=yes", "foo", "yes", hit::Field::Kind::Bool}, {"bool-true3", "foo=on", "foo", "on", hit::Field::Kind::Bool}, {"bool-case1", "foo=TRUE", "foo", "TRUE", hit::Field::Kind::Bool}, {"bool-case2", "foo=ON", "foo", "ON", hit::Field::Kind::Bool}, {"bool-case3", "foo=YeS", "foo", "YeS", hit::Field::Kind::Bool}, {"bool-false1", "foo=false", "foo", "false", hit::Field::Kind::Bool}, {"bool-false2", "foo=no", "foo", "no", hit::Field::Kind::Bool}, {"bool-false3", "foo=off", "foo", "off", hit::Field::Kind::Bool}, {"string", "foo=bar", "foo", "bar", hit::Field::Kind::String}, {"string-almost-float1", "foo=1e23.3", "foo", "1e23.3", hit::Field::Kind::String}, {"string-almost-float2", "foo=1a23.3", "foo", "1a23.3", hit::Field::Kind::String}, {"string-almost-float3", "foo=1.2.3", "foo", "1.2.3", hit::Field::Kind::String}, {"string-almost-float4", "foo=1e2e3", "foo", "1e2e3", hit::Field::Kind::String}, // quotes and escaping {"quotes", "foo='bar'", "foo", "bar", hit::Field::Kind::String}, {"doublequotes", "foo=\"bar\"", "foo", "bar", hit::Field::Kind::String}, {"quotes_quotes", "foo='\\'bar\\''", "foo", "'bar'", hit::Field::Kind::String}, {"quotes_doublequotes", "foo='\"bar\"'", "foo", "\"bar\"", hit::Field::Kind::String}, {"doublequotes_doublequotes", "foo=\"\\\"bar\\\"\"", "foo", "\"bar\"", hit::Field::Kind::String}, // misc {"valid special field chars", "hello_./:<>-+world=foo", "hello_./:<>-+world", "foo", hit::Field::Kind::String}, {"left-bracket-after-number", "[hello]foo=42[]", "hello/foo", "42", hit::Field::Kind::Int}, {"ignore leading spaces 1", "foo= bar", "foo", "bar", hit::Field::Kind::String}, {"ignore leading spaces 2", "foo= \t42", "foo", "42", hit::Field::Kind::Int}, {"ignore trailing spaces", "foo=bar\t ", "foo", "bar", hit::Field::Kind::String}, {"ignore unknown escapes", "foo='hello \\my nam\\e is joe'", "foo", "hello \\my nam\\e is joe", hit::Field::Kind::String}, {"no escaped newline", "foo='hello\\nworld'", "foo", "hello\\nworld", hit::Field::Kind::String}, {"cosecutive string literal 1", "foo='bar''baz'", "foo", "barbaz", hit::Field::Kind::String}, {"cosecutive string literal 2", "foo='bar'\n\n'baz'", "foo", "barbaz", hit::Field::Kind::String}, }; for (size_t i = 0; i < sizeof(cases) / sizeof(ValCase); i++) { auto test = cases[i]; auto root = hit::parse("TEST", test.input); auto n = root->find(test.key); if (!n) { FAIL() << "case " << i + 1 << " (" << test.name << ") failed to find key '" << test.key << "'\n"; continue; } if (n->strVal() != test.val) { FAIL() << "case " << i + 1 << " (" << test.name << ") wrong value (key=" << test.key << "): got '" << n->strVal() << "', want '" << test.val << "'\n"; continue; } auto f = dynamic_cast<hit::Field *>(n); if (!f) FAIL() << "case " << i + 1 << " node type is not NodeType::Field"; else if (f->kind() != test.kind) FAIL() << "case " << i + 1 << " wrong kind (key=" << test.key << "): got '" << strkind(f->kind()) << "', want '" << strkind(test.kind) << "'\n"; } }
/* * EnumValuesCreate * Create an entry in pg_enum for each of the supplied enum values. * * vals is a list of Value strings. */ void EnumValuesCreate(Oid enumTypeOid, List *vals) { Relation pg_enum; TupleDesc tupDesc; NameData enumlabel; Oid *oids; int i, n; Datum values[Natts_pg_enum]; bool nulls[Natts_pg_enum]; ListCell *lc; HeapTuple tup; n = list_length(vals); /* * XXX we do not bother to check the list of values for duplicates --- if * you have any, you'll get a less-than-friendly unique-index violation. * Is it worth trying harder? */ pg_enum = heap_open(EnumRelationId, RowExclusiveLock); tupDesc = pg_enum->rd_att; /* * Allocate oids. While this method does not absolutely guarantee that we * generate no duplicate oids (since we haven't entered each oid into the * table before allocating the next), trouble could only occur if the oid * counter wraps all the way around before we finish. Which seems * unlikely. */ oids = (Oid *) palloc(n * sizeof(Oid)); for (i = 0; i < n; i++) { /* * In QE node, however, use the OIDs assigned by the master (they are delivered * out-of-band, see oid_dispatch.c. */ if (Gp_role == GP_ROLE_EXECUTE) oids[i] = InvalidOid; else oids[i] = GetNewOid(pg_enum); } /* sort them, just in case counter wrapped from high to low */ qsort(oids, n, sizeof(Oid), oid_cmp); /* and make the entries */ memset(nulls, false, sizeof(nulls)); i = 0; foreach(lc, vals) { char *lab = strVal(lfirst(lc)); /* * labels are stored in a name field, for easier syscache lookup, so * check the length to make sure it's within range. */ if (strlen(lab) > (NAMEDATALEN - 1)) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid enum label \"%s\"", lab), errdetail("Labels must be %d characters or less.", NAMEDATALEN - 1))); values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); namestrcpy(&enumlabel, lab); values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); tup = heap_form_tuple(tupDesc, values, nulls); HeapTupleSetOid(tup, oids[i]); simple_heap_insert(pg_enum, tup); CatalogUpdateIndexes(pg_enum, tup); heap_freetuple(tup); i++; }
/* * Find an ObjectAddress for a type of object that is identified by an * unqualified name. */ static ObjectAddress get_object_address_unqualified(ObjectType objtype, List *qualname) { const char *name; ObjectAddress address; /* * The types of names handled by this function are not permitted to be * schema-qualified or catalog-qualified. */ if (list_length(qualname) != 1) { const char *msg; switch (objtype) { case OBJECT_DATABASE: msg = gettext_noop("database name cannot be qualified"); break; case OBJECT_EXTENSION: msg = gettext_noop("extension name cannot be qualified"); break; case OBJECT_TABLESPACE: msg = gettext_noop("tablespace name cannot be qualified"); break; case OBJECT_ROLE: msg = gettext_noop("role name cannot be qualified"); break; case OBJECT_SCHEMA: msg = gettext_noop("schema name cannot be qualified"); break; case OBJECT_LANGUAGE: msg = gettext_noop("language name cannot be qualified"); break; case OBJECT_FDW: msg = gettext_noop("foreign-data wrapper name cannot be qualified"); break; case OBJECT_FOREIGN_SERVER: msg = gettext_noop("server name cannot be qualified"); break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); msg = NULL; /* placate compiler */ } ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s", _(msg)))); } /* Format is valid, extract the actual name. */ name = strVal(linitial(qualname)); /* Translate name to OID. */ switch (objtype) { case OBJECT_DATABASE: address.classId = DatabaseRelationId; address.objectId = get_database_oid(name, false); address.objectSubId = 0; break; case OBJECT_EXTENSION: address.classId = ExtensionRelationId; address.objectId = get_extension_oid(name, false); address.objectSubId = 0; break; case OBJECT_TABLESPACE: address.classId = TableSpaceRelationId; address.objectId = get_tablespace_oid(name, false); address.objectSubId = 0; break; case OBJECT_ROLE: address.classId = AuthIdRelationId; address.objectId = get_role_oid(name, false); address.objectSubId = 0; break; case OBJECT_SCHEMA: address.classId = NamespaceRelationId; address.objectId = get_namespace_oid(name, false); address.objectSubId = 0; break; case OBJECT_LANGUAGE: address.classId = LanguageRelationId; address.objectId = get_language_oid(name, false); address.objectSubId = 0; break; case OBJECT_FDW: address.classId = ForeignDataWrapperRelationId; address.objectId = get_foreign_data_wrapper_oid(name, false); address.objectSubId = 0; break; case OBJECT_FOREIGN_SERVER: address.classId = ForeignServerRelationId; address.objectId = get_foreign_server_oid(name, false); address.objectSubId = 0; break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, which doesn't know elog won't return */ address.classId = InvalidOid; address.objectId = InvalidOid; address.objectSubId = 0; } return address; }
/* * EnumValuesCreate * Create an entry in pg_enum for each of the supplied enum values. * * vals is a list of Value strings. */ void EnumValuesCreate(Oid enumTypeOid, List *vals, Oid binary_upgrade_next_pg_enum_oid) { Relation pg_enum; TupleDesc tupDesc; NameData enumlabel; Oid *oids; int elemno, num_elems; Datum values[Natts_pg_enum]; bool nulls[Natts_pg_enum]; ListCell *lc; HeapTuple tup; num_elems = list_length(vals); /* * XXX we do not bother to check the list of values for duplicates --- if * you have any, you'll get a less-than-friendly unique-index violation. * Is it worth trying harder? */ pg_enum = heap_open(EnumRelationId, RowExclusiveLock); tupDesc = pg_enum->rd_att; /* * Allocate oids */ oids = (Oid *) palloc(num_elems * sizeof(Oid)); if (OidIsValid(binary_upgrade_next_pg_enum_oid)) { if (num_elems != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("EnumValuesCreate() can only set a single OID"))); oids[0] = binary_upgrade_next_pg_enum_oid; binary_upgrade_next_pg_enum_oid = InvalidOid; } else { /* * While this method does not absolutely guarantee that we generate no * duplicate oids (since we haven't entered each oid into the table * before allocating the next), trouble could only occur if the oid * counter wraps all the way around before we finish. Which seems * unlikely. */ for (elemno = 0; elemno < num_elems; elemno++) { /* * The pg_enum.oid is stored in user tables. This oid must be * preserved by binary upgrades. */ oids[elemno] = GetNewOid(pg_enum); } /* sort them, just in case counter wrapped from high to low */ qsort(oids, num_elems, sizeof(Oid), oid_cmp); } /* and make the entries */ memset(nulls, false, sizeof(nulls)); elemno = 0; foreach(lc, vals) { char *lab = strVal(lfirst(lc)); /* * labels are stored in a name field, for easier syscache lookup, so * check the length to make sure it's within range. */ if (strlen(lab) > (NAMEDATALEN - 1)) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid enum label \"%s\"", lab), errdetail("Labels must be %d characters or less.", NAMEDATALEN - 1))); values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); namestrcpy(&enumlabel, lab); values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); tup = heap_form_tuple(tupDesc, values, nulls); HeapTupleSetOid(tup, oids[elemno]); simple_heap_insert(pg_enum, tup); CatalogUpdateIndexes(pg_enum, tup); heap_freetuple(tup); elemno++; }
/* * Find object address for an object that is attached to a relation. * * Note that we take only an AccessShareLock on the relation. We need not * pass down the LOCKMODE from get_object_address(), because that is the lock * mode for the object itself, not the relation to which it is attached. */ static ObjectAddress get_object_address_relobject(ObjectType objtype, List *objname, Relation *relp) { ObjectAddress address; Relation relation = NULL; int nnames; const char *depname; /* Extract name of dependent object. */ depname = strVal(lfirst(list_tail(objname))); /* Separate relation name from dependent object name. */ nnames = list_length(objname); if (nnames < 2) { Oid reloid; /* * For compatibility with very old releases, we sometimes allow users * to attempt to specify a rule without mentioning the relation name. * If there's only rule by that name in the entire database, this will * work. But objects other than rules don't get this special * treatment. */ if (objtype != OBJECT_RULE) elog(ERROR, "must specify relation and object name"); address.classId = RewriteRelationId; address.objectId = get_rewrite_oid_without_relid(depname, &reloid); address.objectSubId = 0; relation = heap_open(reloid, AccessShareLock); } else { List *relname; Oid reloid; /* Extract relation name and open relation. */ relname = list_truncate(list_copy(objname), nnames - 1); relation = heap_openrv(makeRangeVarFromNameList(relname), AccessShareLock); reloid = RelationGetRelid(relation); switch (objtype) { case OBJECT_RULE: address.classId = RewriteRelationId; address.objectId = get_rewrite_oid(reloid, depname, false); address.objectSubId = 0; break; case OBJECT_TRIGGER: address.classId = TriggerRelationId; address.objectId = get_trigger_oid(reloid, depname, false); address.objectSubId = 0; break; case OBJECT_CONSTRAINT: address.classId = ConstraintRelationId; address.objectId = get_constraint_oid(reloid, depname, false); address.objectSubId = 0; break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, which doesn't know elog won't return */ address.classId = InvalidOid; address.objectId = InvalidOid; address.objectSubId = 0; } } /* Done. */ *relp = relation; return address; }
/* * Walker function to find a function call which is supposed to write * database. */ static bool function_call_walker(Node *node, void *context) { SelectContext *ctx = (SelectContext *) context; if (node == NULL) return false; if (IsA(node, FuncCall)) { FuncCall *fcall = (FuncCall *) node; char *fname; int length = list_length(fcall->funcname); if (length > 0) { if (length == 1) /* no schema qualification? */ { fname = strVal(linitial(fcall->funcname)); } else { fname = strVal(lsecond(fcall->funcname)); /* with schema * qualification */ } ereport(DEBUG1, (errmsg("function call walker, function name: \"%s\"", fname))); if (ctx->pg_terminate_backend_pid == 0 && strcmp("pg_terminate_backend", fname) == 0) { if (list_length(fcall->args) == 1) { Node *arg = linitial(fcall->args); if (IsA(arg, A_Const) && ((A_Const *) arg)->val.type == T_Integer) { ctx->pg_terminate_backend_pid = ((A_Const *) arg)->val.val.ival; ereport(DEBUG1, (errmsg("pg_terminate_backend pid = %d", ctx->pg_terminate_backend_pid))); } } } /* * Check white list if any. */ if (pool_config->num_white_function_list > 0) { /* Search function in the white list regex patterns */ if (pattern_compare(fname, WHITELIST, "white_function_list") == 1) { /* * If the function is found in the white list, we can * ignore it */ return raw_expression_tree_walker(node, function_call_walker, context); } /* * Since the function was not found in white list, we have * found a writing function. */ ctx->has_function_call = true; return false; } /* * Check black list if any. */ if (pool_config->num_black_function_list > 0) { /* Search function in the black list regex patterns */ if (pattern_compare(fname, BLACKLIST, "black_function_list") == 1) { /* Found. */ ctx->has_function_call = true; return false; } } } } return raw_expression_tree_walker(node, function_call_walker, context); }
/* * CommentObject -- * * This routine is used to add the associated comment into * pg_description for the object specified by the given SQL command. */ void CommentObject(CommentStmt *stmt) { ObjectAddress address; Relation relation; /* * When loading a dump, we may see a COMMENT ON DATABASE for the old name * of the database. Erroring out would prevent pg_restore from completing * (which is really pg_restore's fault, but for now we will work around * the problem here). Consensus is that the best fix is to treat wrong * database name as a WARNING not an ERROR; hence, the following special * case. (If the length of stmt->objname is not 1, get_object_address will * throw an error below; that's OK.) */ if (stmt->objtype == OBJECT_DATABASE && list_length(stmt->objname) == 1) { char *database = strVal(linitial(stmt->objname)); if (!OidIsValid(get_database_oid(database, true))) { ereport(WARNING, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", database))); return; } } /* * Translate the parser representation which identifies this object into * an ObjectAddress. get_object_address() will throw an error if the * object does not exist, and will also acquire a lock on the target * to guard against concurrent DROP operations. */ address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs, &relation, ShareUpdateExclusiveLock); /* Privilege and integrity checks. */ switch (stmt->objtype) { case OBJECT_INDEX: case OBJECT_SEQUENCE: case OBJECT_TABLE: case OBJECT_VIEW: if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(relation)); break; case OBJECT_COLUMN: CheckAttributeComment(relation); break; case OBJECT_DATABASE: if (!pg_database_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, strVal(linitial(stmt->objname))); break; case OBJECT_TYPE: if (!pg_type_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, format_type_be(address.objectId)); break; case OBJECT_AGGREGATE: case OBJECT_FUNCTION: if (!pg_proc_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, NameListToString(stmt->objname)); break; case OBJECT_OPERATOR: if (!pg_oper_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, NameListToString(stmt->objname)); break; case OBJECT_RULE: case OBJECT_TRIGGER: case OBJECT_CONSTRAINT: if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(relation)); break; case OBJECT_SCHEMA: if (!pg_namespace_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, strVal(linitial(stmt->objname))); break; case OBJECT_CONVERSION: if (!pg_conversion_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, NameListToString(stmt->objname)); break; case OBJECT_LANGUAGE: if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to comment on procedural language"))); break; case OBJECT_OPCLASS: if (!pg_opclass_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, NameListToString(stmt->objname)); break; case OBJECT_OPFAMILY: if (!pg_opfamily_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, NameListToString(stmt->objname)); break; case OBJECT_LARGEOBJECT: if (!lo_compat_privileges && !pg_largeobject_ownercheck(address.objectId, GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be owner of large object %u", address.objectId))); break; case OBJECT_CAST: CheckCastComment(stmt->objname, stmt->objargs); break; case OBJECT_TABLESPACE: if (!pg_tablespace_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, strVal(linitial(stmt->objname))); break; case OBJECT_ROLE: if (!has_privs_of_role(GetUserId(), address.objectId)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be member of role \"%s\" to comment upon it", strVal(linitial(stmt->objname))))); break; case OBJECT_TSPARSER: if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to comment on text search parser"))); break; case OBJECT_TSDICTIONARY: if (!pg_ts_dict_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, NameListToString(stmt->objname)); break; case OBJECT_TSTEMPLATE: if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to comment on text search template"))); break; case OBJECT_TSCONFIGURATION: if (!pg_ts_config_ownercheck(address.objectId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, NameListToString(stmt->objname)); break; default: elog(ERROR, "unrecognized object type: %d", (int) stmt->objtype); } /* * Databases, tablespaces, and roles are cluster-wide objects, so any * comments on those objects are recorded in the shared pg_shdescription * catalog. Comments on all other objects are recorded in pg_description. */ if (stmt->objtype == OBJECT_DATABASE || stmt->objtype == OBJECT_TABLESPACE || stmt->objtype == OBJECT_ROLE) CreateSharedComments(address.objectId, address.classId, stmt->comment); else CreateComments(address.objectId, address.classId, address.objectSubId, stmt->comment); /* * If get_object_address() opened the relation for us, we close it to keep * the reference count correct - but we retain any locks acquired by * get_object_address() until commit time, to guard against concurrent * activity. */ if (relation != NULL) relation_close(relation, NoLock); }
/* * Copied from src/backend/commands/indexcmds.c, not exported. * Resolve possibly-defaulted operator class specification */ Oid GetIndexOpClass(List *opclass, Oid attrType, char *accessMethodName, Oid accessMethodId) { char *schemaname; char *opcname; HeapTuple tuple; Oid opClassId, opInputType; /* * Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so we * ignore those opclass names so the default *_ops is used. This can be * removed in some later release. bjm 2000/02/07 * * Release 7.1 removes lztext_ops, so suppress that too for a while. tgl * 2000/07/30 * * Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that * too for awhile. I'm starting to think we need a better approach. tgl * 2000/10/01 * * Release 8.0 removes bigbox_ops (which was dead code for a long while * anyway). tgl 2003/11/11 */ if (list_length(opclass) == 1) { char *claname = strVal(linitial(opclass)); if (strcmp(claname, "network_ops") == 0 || strcmp(claname, "timespan_ops") == 0 || strcmp(claname, "datetime_ops") == 0 || strcmp(claname, "lztext_ops") == 0 || strcmp(claname, "timestamp_ops") == 0 || strcmp(claname, "bigbox_ops") == 0) opclass = NIL; } if (opclass == NIL) { /* no operator class specified, so find the default */ opClassId = GetDefaultOpClass(attrType, accessMethodId); if (!OidIsValid(opClassId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("data type %s has no default operator class for access method \"%s\"", format_type_be(attrType), accessMethodName), errhint("You must specify an operator class for the index or define a default operator class for the data type."))); return opClassId; } /* * Specific opclass name given, so look up the opclass. */ /* deconstruct the name list */ DeconstructQualifiedName(opclass, &schemaname, &opcname); if (schemaname) { /* Look in specific schema only */ Oid namespaceId; #if PG_VERSION_NUM >= 90300 namespaceId = LookupExplicitNamespace(schemaname, false); #else namespaceId = LookupExplicitNamespace(schemaname); #endif tuple = SearchSysCache3(CLAAMNAMENSP, ObjectIdGetDatum(accessMethodId), PointerGetDatum(opcname), ObjectIdGetDatum(namespaceId)); } else { /* Unqualified opclass name, so search the search path */ opClassId = OpclassnameGetOpcid(accessMethodId, opcname); if (!OidIsValid(opClassId)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("operator class \"%s\" does not exist for access method \"%s\"", opcname, accessMethodName))); tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opClassId)); } if (!HeapTupleIsValid(tuple)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("operator class \"%s\" does not exist for access method \"%s\"", NameListToString(opclass), accessMethodName))); } /* * Verify that the index operator class accepts this datatype. Note we * will accept binary compatibility. */ opClassId = HeapTupleGetOid(tuple); opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype; if (!IsBinaryCoercible(attrType, opInputType)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("operator class \"%s\" does not accept data type %s", NameListToString(opclass), format_type_be(attrType)))); ReleaseSysCache(tuple); return opClassId; }
/* * Executes an ALTER OBJECT / OWNER TO statement. Based on the object * type, the function appropriate to that type is executed. */ void ExecAlterOwnerStmt(AlterOwnerStmt *stmt) { Oid newowner = get_roleid_checked(stmt->newowner); switch (stmt->objectType) { case OBJECT_AGGREGATE: AlterAggregateOwner(stmt->object, stmt->objarg, newowner); break; case OBJECT_CONVERSION: AlterConversionOwner(stmt->object, newowner); break; case OBJECT_DATABASE: AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_FUNCTION: AlterFunctionOwner(stmt->object, stmt->objarg, newowner); break; case OBJECT_OPERATOR: Assert(list_length(stmt->objarg) == 2); AlterOperatorOwner(stmt->object, (TypeName *) linitial(stmt->objarg), (TypeName *) lsecond(stmt->objarg), newowner); break; case OBJECT_OPCLASS: AlterOpClassOwner(stmt->object, stmt->addname, newowner); break; case OBJECT_OPFAMILY: AlterOpFamilyOwner(stmt->object, stmt->addname, newowner); break; case OBJECT_SCHEMA: AlterSchemaOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_TABLESPACE: AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner); break; case OBJECT_FILESPACE: AlterFileSpaceOwner(stmt->object, newowner); break; case OBJECT_TYPE: case OBJECT_DOMAIN: /* same as TYPE */ AlterTypeOwner(stmt->object, newowner); break; case OBJECT_EXTPROTOCOL: AlterExtProtocolOwner(strVal(linitial(stmt->object)), newowner); break; default: elog(ERROR, "unrecognized AlterOwnerStmt type: %d", (int) stmt->objectType); } if (Gp_role == GP_ROLE_DISPATCH) { CdbDispatchUtilityStatement((Node *) stmt, "ExecAlterOwnerStmt"); } }
/* * Parse a function call * * For historical reasons, Postgres tries to treat the notations tab.col * and col(tab) as equivalent: if a single-argument function call has an * argument of complex type and the (unqualified) function name matches * any attribute of the type, we take it as a column projection. Conversely * a function of a single complex-type argument can be written like a * column reference, allowing functions to act like computed columns. * * Hence, both cases come through here. The is_column parameter tells us * which syntactic construct is actually being dealt with, but this is * intended to be used only to deliver an appropriate error message, * not to affect the semantics. When is_column is true, we should have * a single argument (the putative table), unqualified function name * equal to the column name, and no aggregate or variadic decoration. * * The argument expressions (in fargs) must have been transformed already. */ Node * ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, bool agg_star, bool agg_distinct, bool func_variadic, WindowDef *over, bool is_column, int location) { Oid rettype; Oid funcid; ListCell *l; ListCell *nextl; Node *first_arg = NULL; int nargs; int nargsplusdefs; Oid actual_arg_types[FUNC_MAX_ARGS]; Oid *declared_arg_types; List *argdefaults; Node *retval; bool retset; int nvargs; FuncDetailCode fdresult; /* * Most of the rest of the parser just assumes that functions do not have * more than FUNC_MAX_ARGS parameters. We have to test here to protect * against array overruns, etc. Of course, this may not be a function, * but the test doesn't hurt. */ if (list_length(fargs) > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function", FUNC_MAX_ARGS, FUNC_MAX_ARGS), parser_errposition(pstate, location))); /* * Extract arg type info in preparation for function lookup. * * If any arguments are Param markers of type VOID, we discard them from * the parameter list. This is a hack to allow the JDBC driver to not * have to distinguish "input" and "output" parameter symbols while * parsing function-call constructs. We can't use foreach() because we * may modify the list ... */ nargs = 0; for (l = list_head(fargs); l != NULL; l = nextl) { Node *arg = lfirst(l); Oid argtype = exprType(arg); nextl = lnext(l); if (argtype == VOIDOID && IsA(arg, Param) &&!is_column) { fargs = list_delete_ptr(fargs, arg); continue; } actual_arg_types[nargs++] = argtype; } if (fargs) { first_arg = linitial(fargs); Assert(first_arg != NULL); } /* * Check for column projection: if function has one argument, and that * argument is of complex type, and function name is not qualified, then * the "function call" could be a projection. We also check that there * wasn't any aggregate or variadic decoration. */ if (nargs == 1 && !agg_star && !agg_distinct && over == NULL && !func_variadic && list_length(funcname) == 1) { Oid argtype = actual_arg_types[0]; if (argtype == RECORDOID || ISCOMPLEX(argtype)) { retval = ParseComplexProjection(pstate, strVal(linitial(funcname)), first_arg, location); if (retval) return retval; /* * If ParseComplexProjection doesn't recognize it as a projection, * just press on. */ } } /* * Okay, it's not a column projection, so it must really be a function. * func_get_detail looks up the function in the catalogs, does * disambiguation for polymorphic functions, handles inheritance, and * returns the funcid and type and set or singleton status of the * function's return value. It also returns the true argument types to * the function. In the case of a variadic function call, the reported * "true" types aren't really what is in pg_proc: the variadic argument is * replaced by a suitable number of copies of its element type. We'll fix * it up below. We may also have to deal with default arguments. */ fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types, !func_variadic, true, &funcid, &rettype, &retset, &nvargs, &declared_arg_types, &argdefaults); if (fdresult == FUNCDETAIL_COERCION) { /* * We interpreted it as a type coercion. coerce_type can handle these * cases, so why duplicate code... */ return coerce_type(pstate, linitial(fargs), actual_arg_types[0], rettype, -1, COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location); } else if (fdresult == FUNCDETAIL_NORMAL) { /* * Normal function found; was there anything indicating it must be an * aggregate? */ if (agg_star) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("%s(*) specified, but %s is not an aggregate function", NameListToString(funcname), NameListToString(funcname)), parser_errposition(pstate, location))); if (agg_distinct) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("DISTINCT specified, but %s is not an aggregate function", NameListToString(funcname)), parser_errposition(pstate, location))); if (over) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("OVER specified, but %s is not a window function nor an aggregate function", NameListToString(funcname)), parser_errposition(pstate, location))); } else if (!(fdresult == FUNCDETAIL_AGGREGATE || fdresult == FUNCDETAIL_WINDOWFUNC)) { /* * Oops. Time to die. * * If we are dealing with the attribute notation rel.function, give an * error message that is appropriate for that case. */ if (is_column) { Assert(nargs == 1); Assert(list_length(funcname) == 1); unknown_attribute(pstate, first_arg, strVal(linitial(funcname)), location); } /* * Else generate a detailed complaint for a function */ if (fdresult == FUNCDETAIL_MULTIPLE) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("function %s is not unique", func_signature_string(funcname, nargs, actual_arg_types)), errhint("Could not choose a best candidate function. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(funcname, nargs, actual_arg_types)), errhint("No function matches the given name and argument types. " "You might need to add explicit type casts."), parser_errposition(pstate, location))); } /* * If there are default arguments, we have to include their types in * actual_arg_types for the purpose of checking generic type consistency. * However, we do NOT put them into the generated parse node, because * their actual values might change before the query gets run. The * planner has to insert the up-to-date values at plan time. */ nargsplusdefs = nargs; foreach(l, argdefaults) { Node *expr = (Node *) lfirst(l); /* probably shouldn't happen ... */ if (nargsplusdefs >= FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg_plural("cannot pass more than %d argument to a function", "cannot pass more than %d arguments to a function", FUNC_MAX_ARGS, FUNC_MAX_ARGS), parser_errposition(pstate, location))); actual_arg_types[nargsplusdefs++] = exprType(expr); }
/* * TypeGetTupleDesc * * Given a type Oid, build a TupleDesc. (In most cases you should be * using get_call_result_type or one of its siblings instead of this * routine, so that you can handle OUT parameters, RECORD result type, * and polymorphic results.) * * If the type is composite, *and* a colaliases List is provided, *and* * the List is of natts length, use the aliases instead of the relation * attnames. (NB: this usage is deprecated since it may result in * creation of unnecessary transient record types.) * * If the type is a base type, a single item alias List is required. */ TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) { TypeFuncClass functypclass = get_type_func_class(typeoid); TupleDesc tupdesc = NULL; /* * Build a suitable tupledesc representing the output rows */ if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ tupdesc = lookup_rowtype_tupdesc_copy(typeoid, -1); if (colaliases != NIL) { int natts = tupdesc->natts; int varattno; /* does the list length match the number of attributes? */ if (list_length(colaliases) != natts) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("number of aliases does not match number of columns"))); /* OK, use the aliases instead */ for (varattno = 0; varattno < natts; varattno++) { char *label = strVal(list_nth(colaliases, varattno)); if (label != NULL) namestrcpy(&(tupdesc->attrs[varattno]->attname), label); } /* The tuple type is now an anonymous record type */ tupdesc->tdtypeid = RECORDOID; tupdesc->tdtypmod = -1; } } else if (functypclass == TYPEFUNC_SCALAR) { /* Base data type, i.e. scalar */ char *attname; /* the alias list is required for base types */ if (colaliases == NIL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("no column alias was provided"))); /* the alias list length must be 1 */ if (list_length(colaliases) != 1) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("number of aliases does not match number of columns"))); /* OK, get the column alias */ attname = strVal(linitial(colaliases)); tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, attname, typeoid, -1, 0); } else if (functypclass == TYPEFUNC_RECORD) { /* XXX can't support this because typmod wasn't passed in ... */ ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("could not determine row description for function returning record"))); } else { /* crummy error message, but parser should have caught this */ elog(ERROR, "function in FROM has unsupported return type"); } return tupdesc; }
/* * transformTargetList() * Turns a list of ResTarget's into a list of TargetEntry's. * * At this point, we don't care whether we are doing SELECT, INSERT, * or UPDATE; we just transform the given expressions (the "val" fields). */ List * transformTargetList(ParseState *pstate, List *targetlist) { List *p_target = NIL; ListCell *o_target; ParseStateBreadCrumb savebreadcrumb; /* CDB: Push error location stack. Must pop before return! */ Assert(pstate); savebreadcrumb = pstate->p_breadcrumb; pstate->p_breadcrumb.pop = &savebreadcrumb; foreach(o_target, targetlist) { ResTarget *res = (ResTarget *) lfirst(o_target); /* CDB: Drop a breadcrumb in case of error. */ pstate->p_breadcrumb.node = (Node *)res; /* * Check for "something.*". Depending on the complexity of the * "something", the star could appear as the last name in ColumnRef, * or as the last indirection item in A_Indirection. */ if (IsA(res->val, ColumnRef)) { ColumnRef *cref = (ColumnRef *) res->val; if (strcmp(strVal(llast(cref->fields)), "*") == 0) { /* It is something.*, expand into multiple items */ p_target = list_concat(p_target, ExpandColumnRefStar(pstate, cref, true)); continue; } } else if (IsA(res->val, A_Indirection)) { A_Indirection *ind = (A_Indirection *) res->val; Node *lastitem = llast(ind->indirection); if (IsA(lastitem, String) && strcmp(strVal(lastitem), "*") == 0) { /* It is something.*, expand into multiple items */ p_target = list_concat(p_target, ExpandIndirectionStar(pstate, ind, true)); continue; } } /* * Not "something.*", so transform as a single expression */ p_target = lappend(p_target, transformTargetEntry(pstate, res->val, NULL, res->name, false)); }
/** * @brief Parse function expression */ ParsedFunction ParseFunction(const char *value, bool argistype) { int i; ParsedFunction ret; char *buf; const char *nextp; bool done = false; List *names; ListCell *l; int nargs; FuncCandidateList candidates; FuncCandidateList find = NULL; int ncandidates = 0; HeapTuple ftup; Form_pg_proc pp; AclResult aclresult; buf = palloc(strlen(value) + 1); /* parse function name */ nextp = value; do { if (*nextp == '\"') { /* Quoted name */ for (;;) { nextp = strchr(nextp + 1, '\"'); /* mismatched quotes */ if (nextp == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("function call syntax error: %s", value))); if (nextp[1] != '\"') break; /* found end of quoted name */ } /* nextp now points at the terminating quote */ nextp = nextp + 1; } else if (IsIdentStart((unsigned char) *nextp)) { /* Unquoted name */ nextp++; while (IsIdentContent((unsigned char) *nextp)) nextp++; } else { /* invalid syntax */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("function call syntax error: %s", value))); } while (isspace((unsigned char) *nextp)) nextp++; /* skip trailing whitespace */ if (*nextp == '.') { nextp++; while (isspace((unsigned char) *nextp)) nextp++; /* skip leading whitespace for next */ /* we expect another name, so done remains false */ } else if (*nextp == '\0' || *nextp == '(') done = true; else { /* invalid syntax */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("function call syntax error: %s", value))); } /* Loop back if we didn't reach end of function name */ } while (!done); strncpy(buf, value, nextp - value); buf[nextp - value] = '\0'; names = stringToQualifiedNameList(buf); pfree(buf); if (*nextp == '\0') { if (!argistype) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("function call syntax error: %s", value))); nargs = -1; /* Get list of possible candidates from namespace search */ candidates = FuncnameGetCandidates(names, nargs, NIL, false, false); } else { /* parse function arguments */ nargs = 0; while (GetNextArgument(nextp, &ret.args[nargs], &ret.argtypes[nargs], &nextp, value, argistype)) { nargs++; if (nargs > FUNC_MAX_ARGS) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("functions cannot have more than %d arguments", FUNC_MAX_ARGS))); } /* Get list of possible candidates from namespace search */ candidates = FuncnameGetCandidates(names, nargs, NIL, true, true); } /* so now try to match up candidates */ if (!argistype) { FuncCandidateList current_candidates; ncandidates = func_match_argtypes(nargs, ret.argtypes, candidates, ¤t_candidates); /* one match only? then run with it... */ if (ncandidates == 1) find = current_candidates; /* multiple candidates? then better decide or throw an error... */ else if (ncandidates > 1) { find = func_select_candidate(nargs, ret.argtypes, current_candidates); } } else if (nargs > 0) { /* Quickly check if there is an exact match to the input datatypes */ for (find = candidates; find; find = find->next) { if (memcmp(find->args, ret.argtypes, nargs * sizeof(Oid)) == 0) { ncandidates = 1; break; } } } else { FuncCandidateList c; for (c = candidates; c; c = c->next) ncandidates++; find = candidates; } if (ncandidates == 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(names, nargs, NIL, ret.argtypes)), errhint("No function matches the given name and argument types."))); /* * If we were able to choose a best candidate, we're done. * Otherwise, ambiguous function call. */ if (ncandidates > 1 || !OidIsValid(find->oid)) ereport(ERROR, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("function %s is not unique", func_signature_string(names, nargs, NIL, ret.argtypes)), errhint("Could not choose a best candidate function."))); foreach (l, names) { Value *v = lfirst(l); pfree(strVal(v)); pfree(v); }
// Levelpushing Trie Update unsigned int BFLevelPushingTrieUpdate(string sFileName,CFib *tFib) { unsigned int iEntryCount = 0; //the number of items from file char sPrefix[20]; //prefix from rib file unsigned long lPrefix; //the value of Prefix unsigned int iPrefixLen; //the length of PREFIX int iNextHop; //to store NEXTHOP in RIB file char operate_type_read; int operate_type; int readlines = 0; long updatetimeused = 0; long yearmonthday=0; //an integer to record year, month, day long hourminsec=0; //an integer to record hour, minute, second long yearmonthday_old=0; //an integer to record year, month, day long hourminsec_old=0; //an integer to record hour, minute, second long outputCount=0; long insertNum_old=0; long DelNum_old=0; long readlines_old=0; LARGE_INTEGER frequence,privious,privious1; if(!QueryPerformanceFrequency(&frequence)) return 0; FILE * fp_u; fp_u=fopen(UPDATE_TIME, "w"); fprintf(fp_u,"Time #update #update_in_minute #insertion_in_minute #deletion_in_minute \n"); for (int jjj = 1; jjj <= UpdateFileCount; jjj++) { char strName[20]; memset(strName, 0, sizeof(strName)); sprintf(strName, "updates%d.txt", jjj); ifstream fin(strName); if (!fin) { //printf("!!!error!!!! no file named:%s\n",strName); continue; } printf("\nParsing %s\n", strName); while (!fin.eof()) { lPrefix = 0; iPrefixLen = 0; iNextHop = -9; memset(sPrefix,0,sizeof(sPrefix)); //read data from rib file, iNextHop attention !!! fin >> yearmonthday >> hourminsec >> operate_type_read >> sPrefix; //>> iNextHop; if('W' == operate_type_read) { operate_type = _DELETE; } else if ('A' == operate_type_read) { fin >> iNextHop; operate_type = _NOT_DELETE; } else { printf("Format of update file Error, quit....\n"); getchar(); return 0; } int iStart = 0; //the end point of IP int iEnd = 0; //the end point of IP int iFieldIndex = 3; int iLen = strlen(sPrefix); //the length of Prefix if(iLen > 0) { if (yearmonthday - yearmonthday_old > 0 || hourminsec - hourminsec_old >= 100) { yearmonthday_old = yearmonthday; hourminsec_old = hourminsec; int hour_format = hourminsec/100; char hour_string[20]; memset(hour_string, 0, sizeof(hour_string)); if (0 == hour_format) sprintf(hour_string, "0000"); if (hour_format < 10) sprintf(hour_string, "000%d", hour_format); else if (hour_format < 100) sprintf(hour_string, "00%d", hour_format); else if (hour_format < 1000) sprintf(hour_string, "0%d", hour_format); else sprintf(hour_string, "%d", hour_format); if (readlines - readlines_old < 10000) { //printf("%d%s\t%u\t%u\t%u\t%d\n",yearmonthday,hour_string,readlines,readlines-readlines_old,tFib->CBFInsertNum-insertNum_old,tFib->CBFDelNum-DelNum_old); //fprintf(fp_u,"%d%s\t%u\t%u\t%u\t%d\n",yearmonthday,hour_string,readlines,readlines-readlines_old,tFib->CBFInsertNum-insertNum_old,tFib->CBFDelNum-DelNum_old); } insertNum_old = tFib->CBFInsertNum; DelNum_old = tFib->CBFDelNum; readlines_old = readlines; //printf("%d%s\t%d\t%u\t%d\t%d\t%d\n",yearmonthday,hour_string,readlines,tFib->trueUpdateNum,tFib->CBFInsertNum,tFib->CBFDelNum,tFib->invalid); //fprintf(fp_u,"%d%s\t%d\t%u\t%d\t%d\t%d\n",yearmonthday,hour_string,readlines,tFib->trueUpdateNum,tFib->CBFInsertNum,tFib->CBFDelNum,tFib->invalid); //fprintf(fp_u,"%d%d\t%d\t%d\t%d\t%d\n",yearmonthday,hourminsec,readlines,tFib->solidNodeCount,tFib->oldNodeCount,updatetimeused); } readlines++; for ( int i=0; i<iLen; i++ ) { //extract the first 3 sub-part if ( sPrefix[i] == '.' ) { iEnd = i; string strVal(sPrefix + iStart, iEnd - iStart); lPrefix += atol(strVal.c_str()) << (8 * iFieldIndex); //向左移位到高位 iFieldIndex--; iStart = i + 1; i++; } if ( sPrefix[i] == '/' ) { //extract the 4th sub-part iEnd = i; string strVal(sPrefix + iStart, iEnd - iStart); lPrefix += atol(strVal.c_str()); iStart = i + 1; //extract the length of prefix i++; strVal = string(sPrefix + iStart, iLen - 1); iPrefixLen = atoi(strVal.c_str()); } } char insert_C[50]; memset(insert_C,0,sizeof(insert_C)); //insert the current node into Trie tree for (unsigned int yi = 0; yi < iPrefixLen; yi++) { //turn right if(((lPrefix << yi) & HIGHTBIT) == HIGHTBIT) insert_C[yi]='1'; else insert_C[yi]='0'; } //printf("%s\/%d\t%d\n",insert_C,iPrefixLen,iNextHop); if (iPrefixLen < 8) { printf("%d-%d; ", iPrefixLen, iNextHop); } else { QueryPerformanceCounter(&privious); tFib->Update(iNextHop, insert_C, operate_type); QueryPerformanceCounter(&privious1); updatetimeused+=1000000*(privious1.QuadPart-privious.QuadPart)/frequence.QuadPart; } } }
/* * CommentObject -- * * This routine is used to add the associated comment into * pg_description for the object specified by the given SQL command. */ Oid CommentObject(CommentStmt *stmt) { ObjectAddress address; Relation relation; /* * When loading a dump, we may see a COMMENT ON DATABASE for the old name * of the database. Erroring out would prevent pg_restore from completing * (which is really pg_restore's fault, but for now we will work around * the problem here). Consensus is that the best fix is to treat wrong * database name as a WARNING not an ERROR; hence, the following special * case. (If the length of stmt->objname is not 1, get_object_address * will throw an error below; that's OK.) */ if (stmt->objtype == OBJECT_DATABASE && list_length(stmt->objname) == 1) { char *database = strVal(linitial(stmt->objname)); if (!OidIsValid(get_database_oid(database, true))) { ereport(WARNING, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", database))); return InvalidOid; } } /* * Translate the parser representation that identifies this object into an * ObjectAddress. get_object_address() will throw an error if the object * does not exist, and will also acquire a lock on the target to guard * against concurrent DROP operations. */ address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs, &relation, ShareUpdateExclusiveLock, false); /* Require ownership of the target object. */ check_object_ownership(GetUserId(), stmt->objtype, address, stmt->objname, stmt->objargs, relation); /* Perform other integrity checks as needed. */ switch (stmt->objtype) { case OBJECT_COLUMN: /* * Allow comments only on columns of tables, views, composite * types, and foreign tables (which are the only relkinds for * which pg_dump will dump per-column comments). In particular we * wish to disallow comments on index columns, because the naming * of an index's columns may change across PG versions, so dumping * per-column comments could create reload failures. */ if (relation->rd_rel->relkind != RELKIND_RELATION && relation->rd_rel->relkind != RELKIND_VIEW && relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE && relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, composite type, or foreign table", RelationGetRelationName(relation)))); break; default: break; } /* * Databases, tablespaces, and roles are cluster-wide objects, so any * comments on those objects are recorded in the shared pg_shdescription * catalog. Comments on all other objects are recorded in pg_description. */ if (stmt->objtype == OBJECT_DATABASE || stmt->objtype == OBJECT_TABLESPACE || stmt->objtype == OBJECT_ROLE) CreateSharedComments(address.objectId, address.classId, stmt->comment); else CreateComments(address.objectId, address.classId, address.objectSubId, stmt->comment); /* * If get_object_address() opened the relation for us, we close it to keep * the reference count correct - but we retain any locks acquired by * get_object_address() until commit time, to guard against concurrent * activity. */ if (relation != NULL) relation_close(relation, NoLock); return address.objectId; }
/* ---------------------------------------------------------------- * * ---------------------------------------------------------------- */ Datum int4notin(PG_FUNCTION_ARGS) { int32 not_in_arg = PG_GETARG_INT32(0); text *relation_and_attr = PG_GETARG_TEXT_P(1); List *names; int nnames; RangeVar *relrv; char *attribute; Relation relation_to_scan; int32 integer_value; HeapTuple current_tuple; HeapScanDesc scan_descriptor; bool isNull, retval; int attrid; Datum value; /* Parse the argument */ names = textToQualifiedNameList(relation_and_attr); nnames = list_length(names); if (nnames < 2) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"), errhint("Must provide \"relationname.columnname\"."))); attribute = strVal(llast(names)); names = list_truncate(names, nnames - 1); relrv = makeRangeVarFromNameList(names); /* Open the relation and get a relation descriptor */ relation_to_scan = heap_openrv(relrv, AccessShareLock); /* Find the column to search */ attrid = attnameAttNum(relation_to_scan, attribute, true); scan_descriptor = heap_beginscan(relation_to_scan, SnapshotNow, 0, (ScanKey) NULL); retval = true; /* do a scan of the relation, and do the check */ while ((current_tuple = heap_getnext(scan_descriptor, ForwardScanDirection)) != NULL) { value = heap_getattr(current_tuple, (AttrNumber) attrid, RelationGetDescr(relation_to_scan), &isNull); if (isNull) continue; integer_value = DatumGetInt32(value); if (not_in_arg == integer_value) { retval = false; break; /* can stop scanning now */ } } /* close the relation */ heap_endscan(scan_descriptor); heap_close(relation_to_scan, AccessShareLock); PG_RETURN_BOOL(retval); }
/* * Preprocess the query string and build up hash_cookie, which will be * passed to caql_switch later. */ struct caql_hash_cookie * cq_lookup(const char *str, unsigned int len, cq_list *pcql) { Node *query; struct caql_hash_cookie *hash_cookie; hash_cookie = caql_get_parser_cache(str, len); if (hash_cookie != NULL) return hash_cookie; query = caql_raw_parser(str, (const char *) pcql->filename, pcql->lineno); if (query == NULL) return NULL; hash_cookie = palloc0(sizeof(struct caql_hash_cookie)); switch(nodeTag(query)) { case T_CaQLSelect: { CaQLSelect *node = (CaQLSelect *) query; char *attname; if (node->forupdate) hash_cookie->bUpdate = true; if (node->count) hash_cookie->bCount = true; hash_cookie->relation = catcore_lookup_rel(node->from); if (hash_cookie->relation == NULL) elog(ERROR, "could not find relation \"%s\" in %s at %s:%d", node->from, str, pcql->filename, pcql->lineno); attname = strVal(linitial(node->targetlist)); /* * Look up attribute number if target list has a column. * '*' includes count('*'). The first character test is * not wrong due to the syntax limitation, and this is quick. */ if (attname[0] != '*') { hash_cookie->attnum = catcore_lookup_attnum(hash_cookie->relation, attname, &hash_cookie->atttype); if (hash_cookie->attnum == InvalidAttrNumber) elog(ERROR, "could not find attribute \"%s\" in %s at %s:%d", attname, str, pcql->filename, pcql->lineno); } hash_cookie->bAllEqual = caql_process_predicates(hash_cookie, node->where); } break; case T_CaQLInsert: { CaQLInsert *node = (CaQLInsert *) query; hash_cookie->bInsert = true; hash_cookie->relation = catcore_lookup_rel(node->into); if (hash_cookie->relation == NULL) elog(ERROR, "could not find relation \"%s\" in %s at %s:%d", node->into, str, pcql->filename, pcql->lineno); } break; case T_CaQLDelete: { CaQLDelete *node = (CaQLDelete *) query; hash_cookie->bDelete = true; hash_cookie->relation = catcore_lookup_rel(node->from); if (hash_cookie->relation == NULL) elog(ERROR, "could not find relation \"%s\" in %s at %s:%d", node->from, str, pcql->filename, pcql->lineno); hash_cookie->bAllEqual = caql_process_predicates(hash_cookie, node->where); } break; default: return NULL; } hash_cookie->name = str; hash_cookie->query = query; hash_cookie->file = (char *) pcql->filename; hash_cookie->lineno = pcql->lineno; /* Find an available index based on predicates or ORDER BY */ hash_cookie->index = caql_find_index(hash_cookie, query); if (hash_cookie->index != NULL) hash_cookie->syscacheid = GetSysCacheId(hash_cookie->index->indexoid); else hash_cookie->syscacheid = -1; caql_put_parser_cache(str, len, hash_cookie); return hash_cookie; }
static void yaz_xml2query_term(const xmlNode *ptr, Z_Term **term, ODR odr, int *error_code, const char **addinfo) { xmlChar *type = 0; struct _xmlAttr *attr; char *cdata = strVal(ptr->children, odr); for (attr = ptr->properties; attr; attr = attr->next) { if (!xmlStrcmp(attr->name, BAD_CAST "type") && attr->children && attr->children->type == XML_TEXT_NODE) type = attr->children->content; else { *error_code = 1; *addinfo = "bad attribute for attr content"; return; } } *term = (Z_Term *) odr_malloc(odr, sizeof(Z_Term)); if (!type || !xmlStrcmp(type, BAD_CAST "general")) { (*term)->which = Z_Term_general; (*term)->u.general = odr_create_Odr_oct(odr, cdata, strlen(cdata)); } else if (!xmlStrcmp(type, BAD_CAST "numeric")) { (*term)->which = Z_Term_numeric; (*term)->u.numeric = intVal(odr, cdata); } else if (!xmlStrcmp(type, BAD_CAST "string")) { (*term)->which = Z_Term_characterString; (*term)->u.characterString = cdata; } else if (!xmlStrcmp(type, BAD_CAST "oid")) { *error_code = 1; *addinfo = "unhandled term type: oid"; } else if (!xmlStrcmp(type, BAD_CAST "dateTime")) { *error_code = 1; *addinfo = "unhandled term type: dateTime"; } else if (!xmlStrcmp(type, BAD_CAST "integerAndUnit")) { *error_code = 1; *addinfo = "unhandled term type: integerAndUnit"; } else if (!xmlStrcmp(type, BAD_CAST "null")) { (*term)->which = Z_Term_null; (*term)->u.null = odr_nullval(); } else { *error_code = 1; *addinfo = "unhandled term type"; } }