/* * CreateTask creates a new task in shared hash, initializes the task, and sets * the task to assigned state. Note that this function expects the caller to * hold an exclusive lock over the shared hash. */ static void CreateTask(uint64 jobId, uint32 taskId, char *taskCallString) { WorkerTask *workerTask = NULL; uint32 assignmentTime = 0; char *databaseName = get_database_name(MyDatabaseId); char *userName = CurrentUserName(); /* increase task priority for cleanup tasks */ assignmentTime = (uint32) time(NULL); if (taskId == JOB_CLEANUP_TASK_ID) { assignmentTime = HIGH_PRIORITY_TASK_TIME; } /* enter the worker task into shared hash and initialize the task */ workerTask = WorkerTasksHashEnter(jobId, taskId); workerTask->assignedAt = assignmentTime; strlcpy(workerTask->taskCallString, taskCallString, TASK_CALL_STRING_SIZE); workerTask->taskStatus = TASK_ASSIGNED; workerTask->connectionId = INVALID_CONNECTION_ID; workerTask->failureCount = 0; strlcpy(workerTask->databaseName, databaseName, NAMEDATALEN); strlcpy(workerTask->userName, userName, NAMEDATALEN); }
int read_mercenarydb(void) { memset(mercenary_db,0,sizeof(mercenary_db)); sv_readsqldb(get_database_name(17), NULL, 26, MAX_MERCENARY_CLASS, &read_mercenarydb_sub); return 0; }
/* * calculate size of database in all tablespaces */ static int64 calculate_database_size(Oid dbOid) { int64 totalsize = 0; char pathname[MAXPGPATH]; Relation rel; HeapScanDesc scandesc; HeapTuple tuple; AclResult aclresult; Assert(Gp_role != GP_ROLE_EXECUTE); if (dbOid == HcatalogDbOid) ereport(ERROR, (ERRCODE_UNDEFINED_DATABASE, errmsg("database hcatalog (OID 6120) is reserved"))); /* User must have connect privilege for target database */ aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT); if (aclresult != ACLCHECK_OK) { aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(dbOid)); } /* Scan through all tablespaces */ rel = heap_open(TableSpaceRelationId, AccessShareLock); scandesc = heap_beginscan(rel, SnapshotNow, 0, NULL); tuple = heap_getnext(scandesc, ForwardScanDirection); while (HeapTupleIsValid(tuple)) { char *filespace; Oid tsOid; tsOid = HeapTupleGetOid(tuple); /* Don't include shared relations */ if (tsOid != GLOBALTABLESPACE_OID) { /* Find the filespace path for this tablespace */ /* Master access its own database first. */ PersistentTablespace_GetFilespacePath(tsOid, FALSE, &filespace); /* Build the path for this database in this tablespace */ FormDatabasePath(pathname, filespace, tsOid, dbOid); totalsize += db_dir_size(pathname); } tuple = heap_getnext(scandesc, ForwardScanDirection); } heap_endscan(scandesc); heap_close(rel, AccessShareLock); /* Complain if we found no trace of the DB at all */ if (totalsize == 0) ereport(ERROR, (ERRCODE_UNDEFINED_DATABASE, errmsg("database with OID %u does not exist", dbOid))); return totalsize; }
int read_elemental_skilldb(void) { struct s_elemental_db *db; int i, j = 0, k = 0, class_, skill_id, skill_lv, skillmode; if(SQL_ERROR == Sql_Query(dbmysql_handle, "SELECT * FROM `%s`", get_database_name(37))) { Sql_ShowDebug(dbmysql_handle); return -1; } while(SQL_SUCCESS == Sql_NextRow(dbmysql_handle)) { char *row[4]; k++; for(i = 0; i != 4; ++i) Sql_GetData(dbmysql_handle, i, &row[i], NULL); class_ = atoi(row[0]); ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, class_ == elemental_db[i].class_); if(i == MAX_ELEMENTAL_CLASS) { ShowError("read_elemental_skilldb : Classe n?o encontrada em elemental_db para a entrada de habilidade, ROW %d.\n", k); continue; } skill_id = atoi(row[1]); if(skill_id < EL_SKILLBASE || skill_id >= EL_SKILLBASE + MAX_ELEMENTALSKILL) { ShowError("read_elemental_skilldb : Habilidade fora do alcance, ROW %d.\n", k); continue; } db = &elemental_db[i]; skill_lv = atoi(row[2]); skillmode = atoi(row[3]); if(skillmode < EL_SKILLMODE_PASIVE || skillmode > EL_SKILLMODE_AGGRESSIVE) { ShowError("read_elemental_skilldb : Skillmode fora da faixa, ROW %d.\n",k); continue; } ARR_FIND(0, MAX_ELESKILLTREE, i, db->skill[i].id == 0 || db->skill[i].id == skill_id); if(i == MAX_ELESKILLTREE) { ShowWarning("Não foi possível carregar habilidade %d em Elemental %d's árvore. O número máximo de capacidade por elementar foi atingido.\n", skill_id, class_); continue; } db->skill[i].id = skill_id; db->skill[i].lv = skill_lv; db->skill[i].mode = skillmode; j++; } ShowSQL("Leitura de '"CL_WHITE"%lu"CL_RESET"' entradas na tabela '"CL_WHITE"%s"CL_RESET"'.\n", j, get_database_name(37)); Sql_FreeResult(dbmysql_handle); return 0; }
/* * current_database() * Expose the current database to the user */ Datum current_database(PG_FUNCTION_ARGS) { Name db; db = (Name) palloc(NAMEDATALEN); namestrcpy(db, get_database_name(MyDatabaseId)); PG_RETURN_NAME(db); }
/* * calculate size of database in all tablespaces */ static int64 calculate_database_size(Oid dbOid) { int64 totalsize; DIR *dirdesc; struct dirent *direntry; char dirpath[MAXPGPATH]; char pathname[MAXPGPATH + 12 + sizeof(TABLESPACE_VERSION_DIRECTORY)]; AclResult aclresult; /* * User must have connect privilege for target database * or be a member of pg_read_all_stats */ aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT); if (aclresult != ACLCHECK_OK && !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS)) { aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(dbOid)); } /* Shared storage in pg_global is not counted */ /* Include pg_default storage */ snprintf(pathname, sizeof(pathname), "base/%u", dbOid); totalsize = db_dir_size(pathname); /* Scan the non-default tablespaces */ snprintf(dirpath, MAXPGPATH, "pg_tblspc"); dirdesc = AllocateDir(dirpath); if (!dirdesc) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open tablespace directory \"%s\": %m", dirpath))); while ((direntry = ReadDir(dirdesc, dirpath)) != NULL) { CHECK_FOR_INTERRUPTS(); if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) continue; snprintf(pathname, sizeof(pathname), "pg_tblspc/%s/%s/%u", direntry->d_name, TABLESPACE_VERSION_DIRECTORY, dbOid); totalsize += db_dir_size(pathname); } FreeDir(dirdesc); return totalsize; }
/* * calculate size of database in all tablespaces */ static int64 calculate_database_size(Oid dbOid) { int64 totalsize; DIR *dirdesc; struct dirent *direntry; char dirpath[MAXPGPATH]; char pathname[MAXPGPATH]; AclResult aclresult; /* User must have connect privilege for target database */ aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(dbOid)); /* Shared storage in pg_global is not counted */ /* Include pg_default storage */ snprintf(pathname, MAXPGPATH, "base/%u", dbOid); totalsize = db_dir_size(pathname); /* Scan the non-default tablespaces */ snprintf(dirpath, MAXPGPATH, "pg_tblspc"); dirdesc = AllocateDir(dirpath); if (!dirdesc) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open tablespace directory \"%s\": %m", dirpath))); while ((direntry = ReadDir(dirdesc, dirpath)) != NULL) { CHECK_FOR_INTERRUPTS(); if (strcmp(direntry->d_name, ".") == 0 || strcmp(direntry->d_name, "..") == 0) continue; snprintf(pathname, MAXPGPATH, "pg_tblspc/%s/%s/%u", direntry->d_name, TABLESPACE_VERSION_DIRECTORY, dbOid); totalsize += db_dir_size(pathname); } FreeDir(dirdesc); /* Complain if we found no trace of the DB at all */ if (!totalsize) ereport(ERROR, (ERRCODE_UNDEFINED_DATABASE, errmsg("database with OID %u does not exist", dbOid))); return totalsize; }
/* * Set environment variables for libpq access */ void set_libpq_envvars(void) { setenv("PGAPPNAME", "plsh", 1); unsetenv("PGCLIENTENCODING"); setenv("PGDATABASE", get_database_name(MyDatabaseId), 1); #if PG_VERSION_NUM >= 90300 if (Unix_socket_directories) { char *rawstring; List *elemlist; rawstring = pstrdup(Unix_socket_directories); if (!SplitDirectoriesString(rawstring, ',', &elemlist)) ereport(WARNING, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid list syntax for \"unix_socket_directories\""))); if (list_length(elemlist)) setenv("PGHOST", linitial(elemlist), 1); else setenv("PGHOST", "localhost", 0); } #else if (UnixSocketDir && *UnixSocketDir) setenv("PGHOST", UnixSocketDir, 1); #endif else setenv("PGHOST", "localhost", 0); { char buf[16]; sprintf(buf, "%u", PostPortNumber); setenv("PGPORT", buf, 1); } if (getenv("PATH")) { char buf[MAXPGPATH]; char *p; strlcpy(buf, my_exec_path, sizeof(buf)); p = strrchr(buf, '/'); snprintf(p, sizeof(buf) - (p - buf), ":%s", getenv("PATH")); setenv("PATH", buf, 1); } }
/* * ConnectToNode opens a connection to a remote PostgreSQL server. The function * configures the connection's fallback application name to 'citus' and sets * the remote encoding to match the local one. All parameters are required to * be non NULL. * * We attempt to connect up to MAX_CONNECT_ATTEMPT times. After that we give up * and return NULL. */ PGconn * ConnectToNode(char *nodeName, int32 nodePort, char *nodeUser) { PGconn *connection = NULL; const char *clientEncoding = GetDatabaseEncodingName(); const char *dbname = get_database_name(MyDatabaseId); int attemptIndex = 0; const char *keywordArray[] = { "host", "port", "fallback_application_name", "client_encoding", "connect_timeout", "dbname", "user", NULL }; char nodePortString[12]; const char *valueArray[] = { nodeName, nodePortString, "citus", clientEncoding, CLIENT_CONNECT_TIMEOUT_SECONDS, dbname, nodeUser, NULL }; sprintf(nodePortString, "%d", nodePort); Assert(sizeof(keywordArray) == sizeof(valueArray)); for (attemptIndex = 0; attemptIndex < MAX_CONNECT_ATTEMPTS; attemptIndex++) { connection = PQconnectdbParams(keywordArray, valueArray, false); if (PQstatus(connection) == CONNECTION_OK) { break; } else { /* warn if still erroring on final attempt */ if (attemptIndex == MAX_CONNECT_ATTEMPTS - 1) { WarnRemoteError(connection, NULL); } PQfinish(connection); connection = NULL; } } return connection; }
int quest_read_db(void) { int QuestLoop, QueryLoop, MaxQuestLoop = 0; if(SQL_ERROR == Sql_Query(dbmysql_handle, "SELECT * FROM `%s`", get_database_name(50))) { Sql_ShowDebug(dbmysql_handle); return -1; } while(SQL_SUCCESS == Sql_NextRow(dbmysql_handle) && MaxQuestLoop < MAX_QUEST_DB) { char *row[9]; for(QueryLoop = 0; QueryLoop < 9; ++QueryLoop) Sql_GetData(dbmysql_handle, QueryLoop, &row[QueryLoop], NULL); memset(&quest_db[MaxQuestLoop], 0, sizeof(quest_db[0])); quest_db[MaxQuestLoop].id = atoi(row[0]); quest_db[MaxQuestLoop].time = atoi(row[1]); for(QuestLoop = 0; QuestLoop < MAX_QUEST_OBJECTIVES; QuestLoop++) { quest_db[MaxQuestLoop].mob[QuestLoop] = atoi(row[2*QuestLoop+2]); quest_db[MaxQuestLoop].count[QuestLoop] = atoi(row[2*QuestLoop+3]); if(!quest_db[MaxQuestLoop].mob[QuestLoop] || !quest_db[MaxQuestLoop].count[QuestLoop]) break; } quest_db[MaxQuestLoop].num_objectives = QuestLoop; MaxQuestLoop++; } ShowSQL("Leitura de '"CL_WHITE"%lu"CL_RESET"' entradas na tabela '"CL_WHITE"%s"CL_RESET"'.\n", MaxQuestLoop, get_database_name(50)); Sql_FreeResult(dbmysql_handle); return 0; }
/* --------------------------------------------------------------------- * CREATE PROCEDURAL LANGUAGE * --------------------------------------------------------------------- */ void CreateProceduralLanguage(CreatePLangStmt *stmt) { char *languageName; PLTemplate *pltemplate; Oid handlerOid, inlineOid, valOid; Oid funcrettype; Oid funcargtypes[1]; /* * Translate the language name to lower case */ languageName = case_translate_language_name(stmt->plname); /* * If we have template information for the language, ignore the supplied * parameters (if any) and use the template information. */ if ((pltemplate = find_language_template(languageName)) != NULL) { List *funcname; /* * Give a notice if we are ignoring supplied parameters. */ if (stmt->plhandler) ereport(NOTICE, (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters"))); /* * Check permission */ if (!superuser()) { if (!pltemplate->tmpldbacreate) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create procedural language \"%s\"", languageName))); if (!pg_database_ownercheck(MyDatabaseId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); } /* * Find or create the handler function, which we force to be in the * pg_catalog schema. If already present, it must have the correct * return type. */ funcname = SystemFuncName(pltemplate->tmplhandler); handlerOid = LookupFuncName(funcname, 0, funcargtypes, true); if (OidIsValid(handlerOid)) { funcrettype = get_func_rettype(handlerOid); if (funcrettype != LANGUAGE_HANDLEROID) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function %s must return type \"language_handler\"", NameListToString(funcname)))); } else { handlerOid = ProcedureCreate(pltemplate->tmplhandler, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ LANGUAGE_HANDLEROID, ClanguageId, F_FMGR_C_VALIDATOR, pltemplate->tmplhandler, pltemplate->tmpllibrary, false, /* isAgg */ false, /* isWindowFunc */ false, /* security_definer */ false, /* isStrict */ PROVOLATILE_VOLATILE, buildoidvector(funcargtypes, 0), PointerGetDatum(NULL), PointerGetDatum(NULL), PointerGetDatum(NULL), NIL, PointerGetDatum(NULL), 1, 0); } /* * Likewise for the anonymous block handler, if required; but we don't * care about its return type. */ if (pltemplate->tmplinline) { funcname = SystemFuncName(pltemplate->tmplinline); funcargtypes[0] = INTERNALOID; inlineOid = LookupFuncName(funcname, 1, funcargtypes, true); if (!OidIsValid(inlineOid)) { inlineOid = ProcedureCreate(pltemplate->tmplinline, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ VOIDOID, ClanguageId, F_FMGR_C_VALIDATOR, pltemplate->tmplinline, pltemplate->tmpllibrary, false, /* isAgg */ false, /* isWindowFunc */ false, /* security_definer */ true, /* isStrict */ PROVOLATILE_VOLATILE, buildoidvector(funcargtypes, 1), PointerGetDatum(NULL), PointerGetDatum(NULL), PointerGetDatum(NULL), NIL, PointerGetDatum(NULL), 1, 0); } } else inlineOid = InvalidOid; /* * Likewise for the validator, if required; but we don't care about * its return type. */ if (pltemplate->tmplvalidator) { funcname = SystemFuncName(pltemplate->tmplvalidator); funcargtypes[0] = OIDOID; valOid = LookupFuncName(funcname, 1, funcargtypes, true); if (!OidIsValid(valOid)) { valOid = ProcedureCreate(pltemplate->tmplvalidator, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ VOIDOID, ClanguageId, F_FMGR_C_VALIDATOR, pltemplate->tmplvalidator, pltemplate->tmpllibrary, false, /* isAgg */ false, /* isWindowFunc */ false, /* security_definer */ true, /* isStrict */ PROVOLATILE_VOLATILE, buildoidvector(funcargtypes, 1), PointerGetDatum(NULL), PointerGetDatum(NULL), PointerGetDatum(NULL), NIL, PointerGetDatum(NULL), 1, 0); } } else valOid = InvalidOid; /* ok, create it */ create_proc_lang(languageName, stmt->replace, GetUserId(), handlerOid, inlineOid, valOid, pltemplate->tmpltrusted); } else { /* * No template, so use the provided information. If there's no * handler clause, the user is trying to rely on a template that we * don't have, so complain accordingly. */ if (!stmt->plhandler) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unsupported language \"%s\"", languageName), errhint("The supported languages are listed in the pg_pltemplate system catalog."))); /* * Check permission */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create custom procedural language"))); /* * Lookup the PL handler function and check that it is of the expected * return type */ handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false); funcrettype = get_func_rettype(handlerOid); if (funcrettype != LANGUAGE_HANDLEROID) { /* * We allow OPAQUE just so we can load old dump files. When we * see a handler function declared OPAQUE, change it to * LANGUAGE_HANDLER. (This is probably obsolete and removable?) */ if (funcrettype == OPAQUEOID) { ereport(WARNING, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"", NameListToString(stmt->plhandler)))); SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID); } else ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function %s must return type \"language_handler\"", NameListToString(stmt->plhandler)))); } /* validate the inline function */ if (stmt->plinline) { funcargtypes[0] = INTERNALOID; inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false); /* return value is ignored, so we don't check the type */ } else inlineOid = InvalidOid; /* validate the validator function */ if (stmt->plvalidator) { funcargtypes[0] = OIDOID; valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false); /* return value is ignored, so we don't check the type */ } else valOid = InvalidOid; /* ok, create it */ create_proc_lang(languageName, stmt->replace, GetUserId(), handlerOid, inlineOid, valOid, stmt->pltrusted); } }
/* * launch_consumer_group * * Launch a group of background worker process that will consume from the given topic * into the given relation */ static bool launch_consumer_group(Relation consumers, KafkaConsumer *consumer, int64 offset) { BackgroundWorker worker; BackgroundWorkerHandle *handle; KafkaConsumerGroup *group; bool found; int i; group = (KafkaConsumerGroup *) hash_search(consumer_groups, &consumer->id, HASH_ENTER, &found); if (found) { KafkaConsumerProc *proc; HASH_SEQ_STATUS iter; bool running = false; hash_seq_init(&iter, consumer_procs); while ((proc = (KafkaConsumerProc *) hash_seq_search(&iter)) != NULL) { if (proc->consumer_id == consumer->id) { running = true; break; } } hash_seq_term(&iter); /* if there are already procs running, it's a noop */ if (running) return true; /* no procs actually running, so it's ok to launch new ones */ } group->parallelism = consumer->parallelism; for (i = 0; i < group->parallelism; i++) { /* we just need any unique OID here */ Oid id = GetNewOid(consumers); KafkaConsumerProc *proc; proc = (KafkaConsumerProc *) hash_search(consumer_procs, &id, HASH_ENTER, &found); if (found) continue; worker.bgw_main_arg = DatumGetObjectId(id); worker.bgw_flags = BGWORKER_BACKEND_DATABASE_CONNECTION | BGWORKER_SHMEM_ACCESS; worker.bgw_start_time = BgWorkerStart_RecoveryFinished; worker.bgw_restart_time = BGW_NEVER_RESTART; worker.bgw_main = NULL; worker.bgw_notify_pid = 0; /* this module is loaded dynamically, so we can't use bgw_main */ sprintf(worker.bgw_library_name, PIPELINE_KAFKA_LIB); sprintf(worker.bgw_function_name, KAFKA_CONSUME_MAIN); snprintf(worker.bgw_name, BGW_MAXLEN, "[kafka consumer] %s <- %s", consumer->rel->relname, consumer->topic); proc->consumer_id = consumer->id; proc->partition_group = i; proc->offset = offset; namestrcpy(&proc->dbname, get_database_name(MyDatabaseId)); if (!RegisterDynamicBackgroundWorker(&worker, &handle)) return false; proc->worker = *handle; } return true; }
/* * ReceiveRegularFile creates a local file at the given file path, and connects * to remote database that has the given node name and port number. The function * then issues the given transmit command using client-side logic (libpq), reads * the remote file's contents, and appends these contents to the local file. On * success, the function returns success; on failure, it cleans up all resources * and returns false. */ static bool ReceiveRegularFile(const char *nodeName, uint32 nodePort, StringInfo transmitCommand, StringInfo filePath) { int32 fileDescriptor = -1; char filename[MAXPGPATH]; int closed = -1; const int fileFlags = (O_APPEND | O_CREAT | O_RDWR | O_TRUNC | PG_BINARY); const int fileMode = (S_IRUSR | S_IWUSR); QueryStatus queryStatus = CLIENT_INVALID_QUERY; int32 connectionId = INVALID_CONNECTION_ID; char *nodeDatabase = NULL; bool querySent = false; bool queryReady = false; bool copyDone = false; /* create local file to append remote data to */ snprintf(filename, MAXPGPATH, "%s", filePath->data); fileDescriptor = BasicOpenFile(filename, fileFlags, fileMode); if (fileDescriptor < 0) { ereport(WARNING, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", filePath->data))); return false; } /* we use the same database name on the master and worker nodes */ nodeDatabase = get_database_name(MyDatabaseId); /* connect to remote node */ connectionId = MultiClientConnect(nodeName, nodePort, nodeDatabase, NULL); if (connectionId == INVALID_CONNECTION_ID) { ReceiveResourceCleanup(connectionId, filename, fileDescriptor); return false; } /* send request to remote node to start transmitting data */ querySent = MultiClientSendQuery(connectionId, transmitCommand->data); if (!querySent) { ReceiveResourceCleanup(connectionId, filename, fileDescriptor); return false; } /* loop until the remote node acknowledges our transmit request */ while (!queryReady) { ResultStatus resultStatus = MultiClientResultStatus(connectionId); if (resultStatus == CLIENT_RESULT_READY) { queryReady = true; } else if (resultStatus == CLIENT_RESULT_BUSY) { /* remote node did not respond; wait for longer */ long sleepIntervalPerCycle = RemoteTaskCheckInterval * 1000L; pg_usleep(sleepIntervalPerCycle); } else { ReceiveResourceCleanup(connectionId, filename, fileDescriptor); return false; } } /* check query response is as expected */ queryStatus = MultiClientQueryStatus(connectionId); if (queryStatus != CLIENT_QUERY_COPY) { ReceiveResourceCleanup(connectionId, filename, fileDescriptor); return false; } /* loop until we receive and append all the data from remote node */ while (!copyDone) { CopyStatus copyStatus = MultiClientCopyData(connectionId, fileDescriptor); if (copyStatus == CLIENT_COPY_DONE) { copyDone = true; } else if (copyStatus == CLIENT_COPY_MORE) { /* remote node will continue to send more data */ } else { ReceiveResourceCleanup(connectionId, filename, fileDescriptor); return false; } } /* we are done executing; release the connection and the file handle */ MultiClientDisconnect(connectionId); closed = close(fileDescriptor); if (closed < 0) { ereport(WARNING, (errcode_for_file_access(), errmsg("could not close file \"%s\": %m", filename))); /* if we failed to close file, try to delete it before erroring out */ DeleteFile(filename); return false; } /* we successfully received the remote file */ ereport(DEBUG2, (errmsg("received remote file \"%s\"", filename))); return true; }
/* * CREATE SCHEMA */ void CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) { const char *schemaName = stmt->schemaname; const char *authId = stmt->authid; const bool istemp = stmt->istemp; Oid namespaceId = 0; List *parsetree_list; ListCell *parsetree_item; Oid owner_uid; Oid saved_uid; AclResult aclresult; bool saved_secdefcxt; /* bool shouldDispatch = (Gp_role == GP_ROLE_DISPATCH && !IsBootstrapProcessingMode());*/ GetUserIdAndContext(&saved_uid, &saved_secdefcxt); /* * Who is supposed to own the new schema? */ if (authId) owner_uid = get_roleid_checked(authId); else owner_uid = saved_uid; /* * If we are creating a temporary schema then we can skip a * bunch of checks that we would otherwise make. */ if (istemp) { /* * CDB: Delete old temp schema. * * Remove any vestigages of old temporary schema, if any. This can * happen when an old session crashes and doesn't run normal session * shutdown. * * In postgres they try to reuse existing schemas in this case, * however that does not work well for us since the schemas may exist * on a segment by segment basis and we want to keep them syncronized * on oid. The best way of dealing with this is to just delete the * old schemas. */ RemoveSchema_internal(schemaName, DROP_CASCADE, true, true); } else { /* * To create a schema, must have schema-create privilege on the current * database and must be able to become the target role (this does not * imply that the target role itself must have create-schema privilege). * The latter provision guards against "giveaway" attacks. Note that a * superuser will always have both of these privileges a fortiori. */ aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); check_is_member_of_role(saved_uid, owner_uid); /* Additional check to protect reserved schema names */ if (!allowSystemTableModsDDL && (IsReservedName(schemaName) || strcmp(schemaName, "madlib") == 0)) { ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("unacceptable schema name \"%s\"", schemaName), errdetail("The prefix \"%s\" is reserved for system schemas.", GetReservedPrefix(schemaName)))); } } /* * If the requested authorization is different from the current user, * temporarily set the current user so that the object(s) will be created * with the correct ownership. * * (The setting will be restored at the end of this routine, or in case * of error, transaction abort will clean things up.) */ if (saved_uid != owner_uid) SetUserIdAndContext(owner_uid, true); /* * in hawq, should be only called on master except * UPGRADE model. */ Assert(gp_upgrade_mode || (Gp_role != GP_ROLE_EXECUTE)); /* Create the schema's namespace */ namespaceId = NamespaceCreate(schemaName, owner_uid, 0); /* MPP-6929: metadata tracking */ if (Gp_role == GP_ROLE_DISPATCH && !istemp) MetaTrackAddObject(NamespaceRelationId, namespaceId, saved_uid, "CREATE", "SCHEMA" ); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); /* If this is the temporary namespace we must mark it specially */ if (istemp) SetTempNamespace(namespaceId); /* * Temporarily make the new namespace be the front of the search path, as * well as the default creation target namespace. This will be undone at * the end of this routine, or upon error. */ PushSpecialNamespace(namespaceId); /* * Examine the list of commands embedded in the CREATE SCHEMA command, and * reorganize them into a sequentially executable order with no forward * references. Note that the result is still a list of raw parsetrees in * need of parse analysis --- we cannot, in general, run analyze.c on one * statement until we have actually executed the prior ones. */ parsetree_list = analyzeCreateSchemaStmt(stmt); /* * Analyze and execute each command contained in the CREATE SCHEMA */ foreach(parsetree_item, parsetree_list) { Node *parsetree = (Node *) lfirst(parsetree_item); List *querytree_list; ListCell *querytree_item; querytree_list = parse_analyze(parsetree, NULL, NULL, 0); foreach(querytree_item, querytree_list) { Query *querytree = (Query *) lfirst(querytree_item); /* schemas should contain only utility stmts */ Assert(querytree->commandType == CMD_UTILITY); /* do this step */ ProcessUtility(querytree->utilityStmt, queryString, NULL, false, /* not top level */ None_Receiver, NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); }
static PGconn * connect_to_localhost(void) { PGconn *conn; char sql[1024]; char *host; char dbName[1024]; /* Also ensure backend isn't confused by this environment var. */ setenv("PGCLIENTENCODING", GetDatabaseEncodingName(), 1); #ifdef HAVE_UNIX_SOCKETS host = (UnixSocketDir == NULL || UnixSocketDir[0] == '\0') ? DEFAULT_PGSOCKET_DIR : UnixSocketDir; #else host = "localhost"; #endif /* set dbname and disable hostaddr */ snprintf(dbName, lengthof(dbName), "dbname='%s' hostaddr=''", escape_param_str(get_database_name(MyDatabaseId))); conn = PQsetdbLogin( host, GetConfigOption("port", false, false), NULL, NULL, dbName, GetUserNameFromId(GetUserId()), NULL); if (PQstatus(conn) == CONNECTION_BAD) { ParallelWriter wr; wr.conn = conn; ereport(ERROR, (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), errmsg("could not establish connection to parallel writer"), errdetail("%s", finish_and_get_message(&wr)), errhint("Refer to the following if it is an authentication " "error. Specifies the authentication method to " "without the need for a password in pg_hba.conf (ex. " "trust or ident), or specify the password to the " "password file of the operating system user who ran " "PostgreSQL server. If cannot use these solution, " "specify WRITER=DIRECT."))); } /* attempt to set default datestyle */ snprintf(sql, lengthof(sql), "SET datestyle = '%s'", GetConfigOption("datestyle", false, false)); PQexec(conn, sql); /* attempt to set default datestyle */ snprintf(sql, lengthof(sql), "SET timezone = '%s'", show_timezone()); PQexec(conn, sql); /* set message receiver */ PQsetNoticeReceiver(conn, transfer_message, NULL); return conn; }
/* * CREATE SCHEMA */ void CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) { const char *schemaName = stmt->schemaname; const char *authId = stmt->authid; Oid namespaceId; OverrideSearchPath *overridePath; List *parsetree_list; ListCell *parsetree_item; Oid owner_uid; Oid saved_uid; int save_sec_context; AclResult aclresult; bool shouldDispatch = (Gp_role == GP_ROLE_DISPATCH && !IsBootstrapProcessingMode()); /* * GPDB: Creation of temporary namespaces is a special case. This statement * is dispatched by the dispatcher node the first time a temporary table is * created. It bypasses all the normal checks and logic of schema creation, * and is routed to the internal routine for creating temporary namespaces, * instead. */ if (stmt->istemp) { Assert(Gp_role == GP_ROLE_EXECUTE); Assert(stmt->schemaname == InvalidOid); Assert(stmt->authid == NULL); Assert(stmt->schemaElts == NIL); Assert(stmt->schemaOid != InvalidOid); Assert(stmt->toastSchemaOid != InvalidOid); InitTempTableNamespaceWithOids(stmt->schemaOid, stmt->toastSchemaOid); return; } GetUserIdAndSecContext(&saved_uid, &save_sec_context); /* * Who is supposed to own the new schema? */ if (authId) owner_uid = get_roleid_checked(authId); else owner_uid = saved_uid; /* * To create a schema, must have schema-create privilege on the current * database and must be able to become the target role (this does not * imply that the target role itself must have create-schema privilege). * The latter provision guards against "giveaway" attacks. Note that a * superuser will always have both of these privileges a fortiori. */ aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); check_is_member_of_role(saved_uid, owner_uid); /* Additional check to protect reserved schema names */ if (!allowSystemTableModsDDL && IsReservedName(schemaName)) { ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("unacceptable schema name \"%s\"", schemaName), errdetail("The prefix \"%s\" is reserved for system schemas.", GetReservedPrefix(schemaName)))); } /* * If the requested authorization is different from the current user, * temporarily set the current user so that the object(s) will be created * with the correct ownership. * * (The setting will be restored at the end of this routine, or in case * of error, transaction abort will clean things up.) */ if (saved_uid != owner_uid) SetUserIdAndSecContext(owner_uid, save_sec_context | SECURITY_LOCAL_USERID_CHANGE); /* Create the schema's namespace */ if (shouldDispatch || Gp_role != GP_ROLE_EXECUTE) { namespaceId = NamespaceCreate(schemaName, owner_uid, 0); if (shouldDispatch) { elog(DEBUG5, "shouldDispatch = true, namespaceOid = %d", namespaceId); Assert(stmt->schemaOid == 0); stmt->schemaOid = namespaceId; /* * Dispatch the command to all primary and mirror segment dbs. * Starts a global transaction and reconfigures cluster if needed. * Waits for QEs to finish. Exits via ereport(ERROR,...) if error. */ CdbDispatchUtilityStatement((Node *) stmt, DF_CANCEL_ON_ERROR | DF_WITH_SNAPSHOT | DF_NEED_TWO_PHASE, NULL); } /* MPP-6929: metadata tracking */ if (Gp_role == GP_ROLE_DISPATCH) MetaTrackAddObject(NamespaceRelationId, namespaceId, saved_uid, "CREATE", "SCHEMA" ); } else { namespaceId = NamespaceCreate(schemaName, owner_uid, stmt->schemaOid); } /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); /* * Temporarily make the new namespace be the front of the search path, as * well as the default creation target namespace. This will be undone at * the end of this routine, or upon error. */ overridePath = GetOverrideSearchPath(CurrentMemoryContext); overridePath->schemas = lcons_oid(namespaceId, overridePath->schemas); /* XXX should we clear overridePath->useTemp? */ PushOverrideSearchPath(overridePath); /* * Examine the list of commands embedded in the CREATE SCHEMA command, and * reorganize them into a sequentially executable order with no forward * references. Note that the result is still a list of raw parsetrees --- * we cannot, in general, run parse analysis on one statement until we * have actually executed the prior ones. */ parsetree_list = transformCreateSchemaStmt(stmt); /* * Execute each command contained in the CREATE SCHEMA. Since the grammar * allows only utility commands in CREATE SCHEMA, there is no need to pass * them through parse_analyze() or the rewriter; we can just hand them * straight to ProcessUtility. */ foreach(parsetree_item, parsetree_list) { Node *stmt = (Node *) lfirst(parsetree_item); /* do this step */ ProcessUtility(stmt, queryString, NULL, false, /* not top level */ None_Receiver, NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); }
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) #endif { const char *schemaName = stmt->schemaname; const char *authId = stmt->authid; Oid namespaceId; OverrideSearchPath *overridePath; List *parsetree_list; ListCell *parsetree_item; Oid owner_uid; Oid saved_uid; int save_sec_context; AclResult aclresult; GetUserIdAndSecContext(&saved_uid, &save_sec_context); /* * Who is supposed to own the new schema? */ if (authId) owner_uid = get_role_oid(authId, false); else owner_uid = saved_uid; /* * To create a schema, must have schema-create privilege on the current * database and must be able to become the target role (this does not * imply that the target role itself must have create-schema privilege). * The latter provision guards against "giveaway" attacks. Note that a * superuser will always have both of these privileges a fortiori. */ aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); check_is_member_of_role(saved_uid, owner_uid); /* Additional check to protect reserved schema names */ if (!allowSystemTableMods && IsReservedName(schemaName)) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("unacceptable schema name \"%s\"", schemaName), errdetail("The prefix \"pg_\" is reserved for system schemas."))); /* * If the requested authorization is different from the current user, * temporarily set the current user so that the object(s) will be created * with the correct ownership. * * (The setting will be restored at the end of this routine, or in case of * error, transaction abort will clean things up.) */ if (saved_uid != owner_uid) SetUserIdAndSecContext(owner_uid, save_sec_context | SECURITY_LOCAL_USERID_CHANGE); /* Create the schema's namespace */ namespaceId = NamespaceCreate(schemaName, owner_uid, false); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); /* * Temporarily make the new namespace be the front of the search path, as * well as the default creation target namespace. This will be undone at * the end of this routine, or upon error. */ overridePath = GetOverrideSearchPath(CurrentMemoryContext); overridePath->schemas = lcons_oid(namespaceId, overridePath->schemas); /* XXX should we clear overridePath->useTemp? */ PushOverrideSearchPath(overridePath); /* * Examine the list of commands embedded in the CREATE SCHEMA command, and * reorganize them into a sequentially executable order with no forward * references. Note that the result is still a list of raw parsetrees --- * we cannot, in general, run parse analysis on one statement until we * have actually executed the prior ones. */ parsetree_list = transformCreateSchemaStmt(stmt); #ifdef PGXC /* * Add a RemoteQuery node for a query at top level on a remote Coordinator, * if not done already. */ if (!sentToRemote) parsetree_list = AddRemoteQueryNode(parsetree_list, queryString, EXEC_ON_ALL_NODES, false); #endif /* * Execute each command contained in the CREATE SCHEMA. Since the grammar * allows only utility commands in CREATE SCHEMA, there is no need to pass * them through parse_analyze() or the rewriter; we can just hand them * straight to ProcessUtility. */ foreach(parsetree_item, parsetree_list) { Node *stmt = (Node *) lfirst(parsetree_item); /* do this step */ ProcessUtility(stmt, queryString, NULL, false, /* not top level */ None_Receiver, #ifdef PGXC true, #endif /* PGXC */ NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); }
/* * MultiClientConnect synchronously tries to establish a connection. If it * succeeds, it returns the connection id. Otherwise, it reports connection * error and returns INVALID_CONNECTION_ID. * * nodeDatabase and userName can be NULL, in which case values from the * current session are used. */ int32 MultiClientConnect(const char *nodeName, uint32 nodePort, const char *nodeDatabase, const char *userName) { PGconn *connection = NULL; char connInfoString[STRING_BUFFER_SIZE]; ConnStatusType connStatusType = CONNECTION_OK; int32 connectionId = AllocateConnectionId(); char *effectiveDatabaseName = NULL; char *effectiveUserName = NULL; if (XactModificationLevel > XACT_MODIFICATION_NONE) { ereport(ERROR, (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), errmsg("cannot open new connections after the first modification " "command within a transaction"))); } if (connectionId == INVALID_CONNECTION_ID) { ereport(WARNING, (errmsg("could not allocate connection in connection pool"))); return connectionId; } if (nodeDatabase == NULL) { effectiveDatabaseName = get_database_name(MyDatabaseId); } else { effectiveDatabaseName = pstrdup(nodeDatabase); } if (userName == NULL) { effectiveUserName = CurrentUserName(); } else { effectiveUserName = pstrdup(userName); } /* * FIXME: This code is bad on several levels. It completely forgoes any * escaping, it misses setting a number of parameters, it works with a * limited string size without erroring when it's too long. We shouldn't * even build a query string this way, there's PQconnectdbParams()! */ /* transcribe connection paremeters to string */ snprintf(connInfoString, STRING_BUFFER_SIZE, CONN_INFO_TEMPLATE, nodeName, nodePort, effectiveDatabaseName, effectiveUserName, CLIENT_CONNECT_TIMEOUT); /* establish synchronous connection to worker node */ connection = PQconnectdb(connInfoString); connStatusType = PQstatus(connection); if (connStatusType == CONNECTION_OK) { ClientConnectionArray[connectionId] = connection; } else { WarnRemoteError(connection, NULL); PQfinish(connection); connectionId = INVALID_CONNECTION_ID; } pfree(effectiveDatabaseName); pfree(effectiveUserName); return connectionId; }
/* * exec_object_restorecon * * This routine is a helper called by sepgsql_restorecon; it set up * initial security labels of database objects within the supplied * catalog OID. */ static void exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId) { Relation rel; SysScanDesc sscan; HeapTuple tuple; char *database_name = get_database_name(MyDatabaseId); char *namespace_name; Oid namespace_id; char *relation_name; /* * Open the target catalog. We don't want to allow writable * accesses by other session during initial labeling. */ rel = heap_open(catalogId, AccessShareLock); sscan = systable_beginscan(rel, InvalidOid, false, SnapshotNow, 0, NULL); while (HeapTupleIsValid(tuple = systable_getnext(sscan))) { Form_pg_namespace nspForm; Form_pg_class relForm; Form_pg_attribute attForm; Form_pg_proc proForm; char *objname; int objtype = 1234; ObjectAddress object; security_context_t context; /* * The way to determine object name depends on object classes. * So, any branches set up `objtype', `objname' and `object' here. */ switch (catalogId) { case NamespaceRelationId: nspForm = (Form_pg_namespace) GETSTRUCT(tuple); objtype = SELABEL_DB_SCHEMA; objname = quote_object_name(database_name, NameStr(nspForm->nspname), NULL, NULL); object.classId = NamespaceRelationId; object.objectId = HeapTupleGetOid(tuple); object.objectSubId = 0; break; case RelationRelationId: relForm = (Form_pg_class) GETSTRUCT(tuple); if (relForm->relkind == RELKIND_RELATION) objtype = SELABEL_DB_TABLE; else if (relForm->relkind == RELKIND_SEQUENCE) objtype = SELABEL_DB_SEQUENCE; else if (relForm->relkind == RELKIND_VIEW) objtype = SELABEL_DB_VIEW; else continue; /* no need to assign security label */ namespace_name = get_namespace_name(relForm->relnamespace); objname = quote_object_name(database_name, namespace_name, NameStr(relForm->relname), NULL); pfree(namespace_name); object.classId = RelationRelationId; object.objectId = HeapTupleGetOid(tuple); object.objectSubId = 0; break; case AttributeRelationId: attForm = (Form_pg_attribute) GETSTRUCT(tuple); if (get_rel_relkind(attForm->attrelid) != RELKIND_RELATION) continue; /* no need to assign security label */ objtype = SELABEL_DB_COLUMN; namespace_id = get_rel_namespace(attForm->attrelid); namespace_name = get_namespace_name(namespace_id); relation_name = get_rel_name(attForm->attrelid); objname = quote_object_name(database_name, namespace_name, relation_name, NameStr(attForm->attname)); pfree(namespace_name); pfree(relation_name); object.classId = RelationRelationId; object.objectId = attForm->attrelid; object.objectSubId = attForm->attnum; break; case ProcedureRelationId: proForm = (Form_pg_proc) GETSTRUCT(tuple); objtype = SELABEL_DB_PROCEDURE; namespace_name = get_namespace_name(proForm->pronamespace); objname = quote_object_name(database_name, namespace_name, NameStr(proForm->proname), NULL); pfree(namespace_name); object.classId = ProcedureRelationId; object.objectId = HeapTupleGetOid(tuple); object.objectSubId = 0; break; default: elog(ERROR, "unexpected catalog id: %u", catalogId); objname = NULL; /* for compiler quiet */ break; } if (selabel_lookup_raw(sehnd, &context, objname, objtype) == 0) { PG_TRY(); { /* * Check SELinux permission to relabel the fetched object, * then do the actual relabeling. */ sepgsql_object_relabel(&object, context); SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, context); } PG_CATCH(); { freecon(context); PG_RE_THROW(); } PG_END_TRY(); freecon(context); } else if (errno == ENOENT) ereport(WARNING, (errmsg("SELinux: no initial label assigned for %s (type=%d), skipping", objname, objtype))); else ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("SELinux: could not determine initial security label for %s (type=%d): %m", objname, objtype))); pfree(objname); } systable_endscan(sscan); heap_close(rel, NoLock); }
int read_mercenary_skilldb(void) { sv_readsqldb(get_database_name(18), NULL, 3, -1, &read_mercenary_skilldb_sub); return 0; }
/* * lazy_vacuum_rel() -- perform LAZY VACUUM for one heap relation * * This routine vacuums a single heap, cleans out its indexes, and * updates its relpages and reltuples statistics. * * At entry, we have already established a transaction and opened * and locked the relation. * * The return value indicates whether this function has held off * interrupts -- caller must RESUME_INTERRUPTS() after commit if true. */ bool lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy, List *updated_stats) { LVRelStats *vacrelstats; Relation *Irel; int nindexes; BlockNumber possibly_freeable; PGRUsage ru0; TimestampTz starttime = 0; bool heldoff = false; pg_rusage_init(&ru0); /* measure elapsed time iff autovacuum logging requires it */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration > 0) starttime = GetCurrentTimestamp(); if (vacstmt->verbose) elevel = INFO; else elevel = DEBUG2; if (Gp_role == GP_ROLE_DISPATCH) elevel = DEBUG2; /* vacuum and analyze messages aren't interesting from the QD */ #ifdef FAULT_INJECTOR if (vacuumStatement_IsInAppendOnlyDropPhase(vacstmt)) { FaultInjector_InjectFaultIfSet( CompactionBeforeSegmentFileDropPhase, DDLNotSpecified, "", // databaseName ""); // tableName } if (vacummStatement_IsInAppendOnlyCleanupPhase(vacstmt)) { FaultInjector_InjectFaultIfSet( CompactionBeforeCleanupPhase, DDLNotSpecified, "", // databaseName ""); // tableName } #endif /* * MPP-23647. Update xid limits for heap as well as appendonly * relations. This allows setting relfrozenxid to correct value * for an appendonly (AO/CO) table. */ vac_strategy = bstrategy; vacuum_set_xid_limits(vacstmt->freeze_min_age, onerel->rd_rel->relisshared, &OldestXmin, &FreezeLimit); /* * Execute the various vacuum operations. Appendonly tables are treated * differently. */ if (RelationIsAoRows(onerel) || RelationIsAoCols(onerel)) { lazy_vacuum_aorel(onerel, vacstmt, updated_stats); return false; } vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); /* heap relation */ /* Set threshold for interesting free space = average request size */ /* XXX should we scale it up or down? Adjust vacuum.c too, if so */ vacrelstats->threshold = GetAvgFSMRequestSize(&onerel->rd_node); vacrelstats->num_index_scans = 0; /* Open all indexes of the relation */ vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel); vacrelstats->hasindex = (nindexes > 0); /* Do the vacuuming */ lazy_scan_heap(onerel, vacrelstats, Irel, nindexes, updated_stats); /* Done with indexes */ vac_close_indexes(nindexes, Irel, NoLock); /* * Optionally truncate the relation. * * Don't even think about it unless we have a shot at releasing a goodly * number of pages. Otherwise, the time taken isn't worth it. * * Note that after we've truncated the heap, it's too late to abort the * transaction; doing so would lose the sinval messages needed to tell * the other backends about the table being shrunk. We prevent interrupts * in that case; caller is responsible for re-enabling them after * committing the transaction. */ possibly_freeable = vacrelstats->rel_pages - vacrelstats->nonempty_pages; if (possibly_freeable > 0 && (possibly_freeable >= REL_TRUNCATE_MINIMUM || possibly_freeable >= vacrelstats->rel_pages / REL_TRUNCATE_FRACTION)) { HOLD_INTERRUPTS(); heldoff = true; lazy_truncate_heap(onerel, vacrelstats); } /* Update shared free space map with final free space info */ lazy_update_fsm(onerel, vacrelstats); if (vacrelstats->tot_free_pages > MaxFSMPages) ereport(WARNING, (errmsg("relation \"%s.%s\" contains more than \"max_fsm_pages\" pages with useful free space", get_namespace_name(RelationGetNamespace(onerel)), RelationGetRelationName(onerel)), /* Only suggest VACUUM FULL if > 20% free */ (vacrelstats->tot_free_pages > vacrelstats->rel_pages * 0.20) ? errhint("Consider using VACUUM FULL on this relation or increasing the configuration parameter \"max_fsm_pages\".") : errhint("Consider increasing the configuration parameter \"max_fsm_pages\"."))); /* Update statistics in pg_class */ vac_update_relstats_from_list(onerel, vacrelstats->rel_pages, vacrelstats->rel_tuples, vacrelstats->hasindex, FreezeLimit, updated_stats); /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, true /*vacrelstats->scanned_all*/, vacstmt->analyze, vacrelstats->rel_tuples); if (gp_indexcheck_vacuum == INDEX_CHECK_ALL || (gp_indexcheck_vacuum == INDEX_CHECK_SYSTEM && PG_CATALOG_NAMESPACE == RelationGetNamespace(onerel))) { int i; for (i = 0; i < nindexes; i++) { if (Irel[i]->rd_rel->relam == BTREE_AM_OID) _bt_validate_vacuum(Irel[i], onerel, OldestXmin); } } /* and log the action if appropriate */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) { if (Log_autovacuum_min_duration == 0 || TimestampDifferenceExceeds(starttime, GetCurrentTimestamp(), Log_autovacuum_min_duration)) ereport(LOG, (errmsg("automatic vacuum of table \"%s.%s.%s\": index scans: %d\n" "pages: %d removed, %d remain\n" "tuples: %.0f removed, %.0f remain\n" "system usage: %s", get_database_name(MyDatabaseId), get_namespace_name(RelationGetNamespace(onerel)), RelationGetRelationName(onerel), vacrelstats->num_index_scans, vacrelstats->pages_removed, vacrelstats->rel_pages, vacrelstats->tuples_deleted, vacrelstats->rel_tuples, pg_rusage_show(&ru0)))); } return heldoff; }
/* * CREATE SCHEMA */ Oid CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) { const char *schemaName = stmt->schemaname; Oid namespaceId; OverrideSearchPath *overridePath; List *parsetree_list; ListCell *parsetree_item; Oid owner_uid; Oid saved_uid; int save_sec_context; AclResult aclresult; ObjectAddress address; GetUserIdAndSecContext(&saved_uid, &save_sec_context); /* * Who is supposed to own the new schema? */ if (stmt->authrole) owner_uid = get_rolespec_oid(stmt->authrole, false); else owner_uid = saved_uid; /* fill schema name with the user name if not specified */ if (!schemaName) { HeapTuple tuple; tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for role %u", owner_uid); schemaName = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname)); ReleaseSysCache(tuple); } /* * To create a schema, must have schema-create privilege on the current * database and must be able to become the target role (this does not * imply that the target role itself must have create-schema privilege). * The latter provision guards against "giveaway" attacks. Note that a * superuser will always have both of these privileges a fortiori. */ aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); check_is_member_of_role(saved_uid, owner_uid); /* Additional check to protect reserved schema names */ if (!allowSystemTableMods && IsReservedName(schemaName)) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("unacceptable schema name \"%s\"", schemaName), errdetail("The prefix \"pg_\" is reserved for system schemas."))); /* * If if_not_exists was given and the schema already exists, bail out. * (Note: we needn't check this when not if_not_exists, because * NamespaceCreate will complain anyway.) We could do this before making * the permissions checks, but since CREATE TABLE IF NOT EXISTS makes its * creation-permission check first, we do likewise. */ if (stmt->if_not_exists && SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(schemaName))) { ereport(NOTICE, (errcode(ERRCODE_DUPLICATE_SCHEMA), errmsg("schema \"%s\" already exists, skipping", schemaName))); return InvalidOid; } /* * If the requested authorization is different from the current user, * temporarily set the current user so that the object(s) will be created * with the correct ownership. * * (The setting will be restored at the end of this routine, or in case of * error, transaction abort will clean things up.) */ if (saved_uid != owner_uid) SetUserIdAndSecContext(owner_uid, save_sec_context | SECURITY_LOCAL_USERID_CHANGE); /* Create the schema's namespace */ namespaceId = NamespaceCreate(schemaName, owner_uid, false); /* Advance cmd counter to make the namespace visible */ CommandCounterIncrement(); /* * Temporarily make the new namespace be the front of the search path, as * well as the default creation target namespace. This will be undone at * the end of this routine, or upon error. */ overridePath = GetOverrideSearchPath(CurrentMemoryContext); overridePath->schemas = lcons_oid(namespaceId, overridePath->schemas); /* XXX should we clear overridePath->useTemp? */ PushOverrideSearchPath(overridePath); /* * Report the new schema to possibly interested event triggers. Note we * must do this here and not in ProcessUtilitySlow because otherwise the * objects created below are reported before the schema, which would be * wrong. */ ObjectAddressSet(address, NamespaceRelationId, namespaceId); EventTriggerCollectSimpleCommand(address, InvalidObjectAddress, (Node *) stmt); /* * Examine the list of commands embedded in the CREATE SCHEMA command, and * reorganize them into a sequentially executable order with no forward * references. Note that the result is still a list of raw parsetrees --- * we cannot, in general, run parse analysis on one statement until we * have actually executed the prior ones. */ parsetree_list = transformCreateSchemaStmt(stmt); /* * Execute each command contained in the CREATE SCHEMA. Since the grammar * allows only utility commands in CREATE SCHEMA, there is no need to pass * them through parse_analyze() or the rewriter; we can just hand them * straight to ProcessUtility. */ foreach(parsetree_item, parsetree_list) { Node *stmt = (Node *) lfirst(parsetree_item); /* do this step */ ProcessUtility(stmt, queryString, PROCESS_UTILITY_SUBCOMMAND, NULL, None_Receiver, NULL); /* make sure later steps can see the object created here */ CommandCounterIncrement(); }
int read_elementaldb(void) { struct s_elemental_db *db; struct status_data *status; int count = 0, ele; memset(elemental_db,0,sizeof(elemental_db)); if(SQL_ERROR == Sql_Query(dbmysql_handle, "SELECT * FROM `%s`", get_database_name(36))) { Sql_ShowDebug(dbmysql_handle); return -1; } while(SQL_SUCCESS == Sql_NextRow(dbmysql_handle) && count < MAX_ELEMENTAL_CLASS) { char *row[26]; int i; for(i = 0; i != 26; ++i) Sql_GetData(dbmysql_handle, i, &row[i], NULL); db = &elemental_db[count]; db->class_ = atoi(row[0]); safestrncpy(db->sprite, row[1], NAME_LENGTH); safestrncpy(db->name, row[2], NAME_LENGTH); db->lv = atoi(row[3]); status = &db->status; db->vd.class_ = db->class_; status->max_hp = atoi(row[4]); status->max_sp = atoi(row[5]); status->rhw.range = atoi(row[6]); status->rhw.atk = atoi(row[7]); status->rhw.atk2 = atoi(row[8]); status->def = atoi(row[9]); status->mdef = atoi(row[10]); status->str = atoi(row[11]); status->agi = atoi(row[12]); status->vit = atoi(row[13]); status->int_ = atoi(row[14]); status->dex = atoi(row[15]); status->luk = atoi(row[16]); db->range2 = atoi(row[17]); db->range3 = atoi(row[18]); status->size = atoi(row[19]); status->race = atoi(row[20]); ele = atoi(row[21]); status->def_ele = ele%10; status->ele_lv = ele/20; if(status->def_ele >= ELE_MAX) { ShowWarning("Elemental %d tem o tipo de elemento inválido %d (elemento máximo ? %d)\n", db->class_, status->def_ele, ELE_MAX - 1); status->def_ele = ELE_NEUTRAL; } if(status->ele_lv < 1 || status->ele_lv > 4) { ShowWarning("Elemental %d tem nível de elemento inválido %d (máximo ? 4)\n", db->class_, status->ele_lv); status->ele_lv = 1; } status->aspd_rate = 1000; status->speed = atoi(row[22]); status->adelay = atoi(row[23]); status->amotion = atoi(row[24]); status->dmotion = atoi(row[25]); ++count; } ShowSQL("Leitura de '"CL_WHITE"%lu"CL_RESET"' entradas na tabela '"CL_WHITE"%s"CL_RESET"'.\n", count, get_database_name(36)); Sql_FreeResult(dbmysql_handle); return 0; }
/* --------------------------------------------------------------------- * CREATE PROCEDURAL LANGUAGE * --------------------------------------------------------------------- */ void CreateProceduralLanguage(CreatePLangStmt *stmt) { char *languageName; PLTemplate *pltemplate; Oid handlerOid, inlineOid, valOid; Oid funcrettype; Oid funcargtypes[1]; /* * Translate the language name and check that this language doesn't * already exist */ languageName = case_translate_language_name(stmt->plname); if (SearchSysCacheExists(LANGNAME, PointerGetDatum(languageName), 0, 0, 0)) { /* * MPP-7563: special case plpgsql to omit a notice if it already exists * rather than an error. This allows us to install plpgsql by default * while allowing it to be dropped and not create issues for * dump/restore. This should be phased out in a later releases if/when * plpgsql becomes a true internal language that can not be dropped. * * Note: hardcoding this on the name is semi-safe since we would ignore * any handler functions anyways since plpgsql exists in pg_pltemplate. * Alternatively this logic could be extended to apply to all languages * in pg_pltemplate. */ if (strcmp(languageName, "plpgsql") == 0) { ereport(NOTICE, (errmsg("language \"plpgsql\" already exists, skipping"))); return; } else { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("language \"%s\" already exists", languageName))); } } /* * If we have template information for the language, ignore the supplied * parameters (if any) and use the template information. */ if ((pltemplate = find_language_template(languageName)) != NULL) { List *funcname; /* * Give a notice if we are ignoring supplied parameters. */ if (stmt->plhandler) if (Gp_role != GP_ROLE_EXECUTE) ereport(NOTICE, (errmsg("using pg_pltemplate information instead of " "CREATE LANGUAGE parameters"))); /* * Check permission */ if (!superuser()) { if (!pltemplate->tmpldbacreate) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create procedural language \"%s\"", languageName))); if (!pg_database_ownercheck(MyDatabaseId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); } /* * Find or create the handler function, which we force to be in the * pg_catalog schema. If already present, it must have the correct * return type. */ funcname = SystemFuncName(pltemplate->tmplhandler); handlerOid = LookupFuncName(funcname, 0, funcargtypes, true); if (OidIsValid(handlerOid)) { funcrettype = get_func_rettype(handlerOid); if (funcrettype != LANGUAGE_HANDLEROID) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function %s must return type \"language_handler\"", NameListToString(funcname)))); } else { handlerOid = ProcedureCreate(pltemplate->tmplhandler, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ LANGUAGE_HANDLEROID, ClanguageId, F_FMGR_C_VALIDATOR, InvalidOid, /* describeFuncOid */ pltemplate->tmplhandler, pltemplate->tmpllibrary, false, /* isAgg */ false, /* isWin */ false, /* security_definer */ false, /* isStrict */ PROVOLATILE_VOLATILE, buildoidvector(funcargtypes, 0), PointerGetDatum(NULL), PointerGetDatum(NULL), PointerGetDatum(NULL), NIL, PointerGetDatum(NULL), 1, 0, PRODATAACCESS_NONE, stmt->plhandlerOid); } /* * Likewise for the anonymous block handler, if required; but we don't * care about its return type. */ if (pltemplate->tmplinline) { funcname = SystemFuncName(pltemplate->tmplinline); funcargtypes[0] = INTERNALOID; inlineOid = LookupFuncName(funcname, 1, funcargtypes, true); if (!OidIsValid(inlineOid)) { inlineOid = ProcedureCreate(pltemplate->tmplinline, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ VOIDOID, ClanguageId, F_FMGR_C_VALIDATOR, InvalidOid, /* describeFuncOid */ pltemplate->tmplinline, pltemplate->tmpllibrary, false, /* isAgg */ false, /* isWin */ false, /* security_definer */ true, /* isStrict */ PROVOLATILE_IMMUTABLE, buildoidvector(funcargtypes, 1), PointerGetDatum(NULL), PointerGetDatum(NULL), PointerGetDatum(NULL), NIL, PointerGetDatum(NULL), 1, 0, PRODATAACCESS_NONE, stmt->plinlineOid); } } else inlineOid = InvalidOid; /* * Likewise for the validator, if required; but we don't care about * its return type. */ if (pltemplate->tmplvalidator) { funcname = SystemFuncName(pltemplate->tmplvalidator); funcargtypes[0] = OIDOID; valOid = LookupFuncName(funcname, 1, funcargtypes, true); if (!OidIsValid(valOid)) { valOid = ProcedureCreate(pltemplate->tmplvalidator, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ VOIDOID, ClanguageId, F_FMGR_C_VALIDATOR, InvalidOid, /* describeFuncOid */ pltemplate->tmplvalidator, pltemplate->tmpllibrary, false, /* isAgg */ false, /* isWin */ false, /* security_definer */ true, /* isStrict */ PROVOLATILE_IMMUTABLE, buildoidvector(funcargtypes, 1), PointerGetDatum(NULL), PointerGetDatum(NULL), PointerGetDatum(NULL), NIL, PointerGetDatum(NULL), 1, 0, PRODATAACCESS_NONE, stmt->plvalidatorOid); } } else valOid = InvalidOid; /* ok, create it */ create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid, valOid, pltemplate->tmpltrusted, &(stmt->plangOid)); } else { /* * No template, so use the provided information. If there's no * handler clause, the user is trying to rely on a template that we * don't have, so complain accordingly. */ if (!stmt->plhandler) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unsupported language \"%s\"", languageName), errhint("The supported languages are listed in the pg_pltemplate system catalog."))); /* * Check permission */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create custom procedural language"))); /* * Lookup the PL handler function and check that it is of the expected * return type */ handlerOid = LookupFuncName(stmt->plhandler, 0, funcargtypes, false); funcrettype = get_func_rettype(handlerOid); if (funcrettype != LANGUAGE_HANDLEROID) { /* * We allow OPAQUE just so we can load old dump files. When we * see a handler function declared OPAQUE, change it to * LANGUAGE_HANDLER. (This is probably obsolete and removable?) */ if (funcrettype == OPAQUEOID) { if (Gp_role != GP_ROLE_EXECUTE) ereport(WARNING, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("changing return type of function %s from \"opaque\" to \"language_handler\"", NameListToString(stmt->plhandler)))); SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID); } else ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("function %s must return type \"language_handler\"", NameListToString(stmt->plhandler)))); } /* validate the inline function */ if (stmt->plinline) { funcargtypes[0] = INTERNALOID; inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false); /* return value is ignored, so we don't check the type */ } else inlineOid = InvalidOid; /* validate the validator function */ if (stmt->plvalidator) { funcargtypes[0] = OIDOID; valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false); /* return value is ignored, so we don't check the type */ } else valOid = InvalidOid; /* ok, create it */ create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid, valOid, stmt->pltrusted, &(stmt->plangOid)); } if (Gp_role == GP_ROLE_DISPATCH) { stmt->plhandlerOid = handlerOid; stmt->plinlineOid = inlineOid; stmt->plvalidatorOid = valOid; CdbDispatchUtilityStatement((Node *) stmt, DF_CANCEL_ON_ERROR| DF_WITH_SNAPSHOT| DF_NEED_TWO_PHASE, NULL); } }
Datum worker_test(PG_FUNCTION_ARGS) { int i, nworkers; dsm_segment *seg; test_shm_mq_header *hdr; MemoryContext oldcontext; worker_state *wstate; nworkers = PG_GETARG_INT32(0); #if PG_VERSION_NUM >= 90500 seg = dsm_create(sizeof(test_shm_mq_header), 0); #else seg = dsm_create(sizeof(test_shm_mq_header) #endif hdr = dsm_segment_address(seg); printf("begin worker_test: %d, %p\n", dsm_segment_handle(seg), hdr); MemSet(hdr, 0, sizeof(test_shm_mq_header)); SpinLockInit(&hdr->mutex); strncpy(hdr->dbname, get_database_name(MyDatabaseId), sizeof(hdr->dbname)); oldcontext = MemoryContextSwitchTo(CurTransactionContext); wstate = MemoryContextAlloc(TopTransactionContext, offsetof(worker_state, handle) + sizeof(BackgroundWorkerHandle *) * nworkers); MemSet(wstate, 0, offsetof(worker_state, handle) + sizeof(BackgroundWorkerHandle *) * nworkers); on_dsm_detach(seg, cleanup_background_workers, PointerGetDatum(wstate)); for (i = 0; i < nworkers; i++) { BackgroundWorker worker; MemSet(&worker, 0, sizeof(worker)); worker.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION; worker.bgw_start_time = BgWorkerStart_ConsistentState; worker.bgw_restart_time = BGW_NEVER_RESTART; worker.bgw_main = NULL; /* new worker might not have library loaded */ sprintf(worker.bgw_library_name, "worker_test"); sprintf(worker.bgw_function_name, "worker_test_main"); snprintf(worker.bgw_name, BGW_MAXLEN, "worker_test %d", i); worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(seg)); worker.bgw_notify_pid = MyProcPid; if (!RegisterDynamicBackgroundWorker(&worker, &wstate->handle[i])) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), errmsg("could not register background process"), errhint("You may need to increase max_worker_processes."))); ++wstate->nworkers; } for (i = 0; i < nworkers; i++) { BgwHandleStatus status; pid_t pid; status = WaitForBackgroundWorkerStartup(wstate->handle[i], &pid); if (status == BGWH_STOPPED) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), errmsg("could not start background process"), errhint("More details may be available in the server log."))); if (status == BGWH_POSTMASTER_DIED) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), errmsg("cannot start background processes without postmaster"), errhint("Kill all remaining database processes and restart the database."))); Assert(status == BGWH_STARTED); } wait_for_workers_to_become_ready(wstate, hdr); cancel_on_dsm_detach(seg, cleanup_background_workers, PointerGetDatum(wstate)); dsm_detach(seg); pfree(wstate); MemoryContextSwitchTo(oldcontext); PG_RETURN_VOID(); }
/* * lazy_truncate_heap - try to truncate off any empty pages at the end */ static void lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats) { BlockNumber old_rel_pages = vacrelstats->rel_pages; BlockNumber new_rel_pages; PGRUsage ru0; int lock_retry; pg_rusage_init(&ru0); /* * Loop until no more truncating can be done. */ do { /* * We need full exclusive lock on the relation in order to do * truncation. If we can't get it, give up rather than waiting --- we * don't want to block other backends, and we don't want to deadlock * (which is quite possible considering we already hold a lower-grade * lock). */ vacrelstats->lock_waiter_detected = false; lock_retry = 0; while (true) { if (ConditionalLockRelation(onerel, AccessExclusiveLock)) break; /* * Check for interrupts while trying to (re-)acquire the exclusive * lock. */ CHECK_FOR_INTERRUPTS(); if (++lock_retry > (AUTOVACUUM_TRUNCATE_LOCK_TIMEOUT / AUTOVACUUM_TRUNCATE_LOCK_WAIT_INTERVAL)) { /* * We failed to establish the lock in the specified number of * retries. This means we give up truncating. Suppress the * ANALYZE step. Doing an ANALYZE at this point will reset the * dead_tuple_count in the stats collector, so we will not get * called by the autovacuum launcher again to do the truncate. */ vacrelstats->lock_waiter_detected = true; ereport(LOG, (errmsg("automatic vacuum of table \"%s.%s.%s\": " "could not (re)acquire exclusive " "lock for truncate scan", get_database_name(MyDatabaseId), get_namespace_name(RelationGetNamespace(onerel)), RelationGetRelationName(onerel)))); return; } pg_usleep(AUTOVACUUM_TRUNCATE_LOCK_WAIT_INTERVAL); } /* * Now that we have exclusive lock, look to see if the rel has grown * whilst we were vacuuming with non-exclusive lock. If so, give up; * the newly added pages presumably contain non-deletable tuples. */ new_rel_pages = RelationGetNumberOfBlocks(onerel); if (new_rel_pages != old_rel_pages) { /* * Note: we intentionally don't update vacrelstats->rel_pages with * the new rel size here. If we did, it would amount to assuming * that the new pages are empty, which is unlikely. Leaving the * numbers alone amounts to assuming that the new pages have the * same tuple density as existing ones, which is less unlikely. */ UnlockRelation(onerel, AccessExclusiveLock); return; } /* * Scan backwards from the end to verify that the end pages actually * contain no tuples. This is *necessary*, not optional, because * other backends could have added tuples to these pages whilst we * were vacuuming. */ new_rel_pages = count_nondeletable_pages(onerel, vacrelstats); if (new_rel_pages >= old_rel_pages) { /* can't do anything after all */ UnlockRelation(onerel, AccessExclusiveLock); return; } /* * Okay to truncate. */ RelationTruncate(onerel, new_rel_pages); /* * We can release the exclusive lock as soon as we have truncated. * Other backends can't safely access the relation until they have * processed the smgr invalidation that smgrtruncate sent out ... but * that should happen as part of standard invalidation processing once * they acquire lock on the relation. */ UnlockRelation(onerel, AccessExclusiveLock); /* * Update statistics. Here, it *is* correct to adjust rel_pages * without also touching reltuples, since the tuple count wasn't * changed by the truncation. */ vacrelstats->pages_removed += old_rel_pages - new_rel_pages; vacrelstats->rel_pages = new_rel_pages; ereport(elevel, (errmsg("\"%s\": truncated %u to %u pages", RelationGetRelationName(onerel), old_rel_pages, new_rel_pages), errdetail("%s.", pg_rusage_show(&ru0)))); old_rel_pages = new_rel_pages; } while (new_rel_pages > vacrelstats->nonempty_pages && vacrelstats->lock_waiter_detected); }
/* * lazy_vacuum_rel() -- perform LAZY VACUUM for one heap relation * * This routine vacuums a single heap, cleans out its indexes, and * updates its relpages and reltuples statistics. * * At entry, we have already established a transaction and opened * and locked the relation. */ void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy) { LVRelStats *vacrelstats; Relation *Irel; int nindexes; BlockNumber possibly_freeable; PGRUsage ru0; TimestampTz starttime = 0; long secs; int usecs; double read_rate, write_rate; bool scan_all; TransactionId freezeTableLimit; BlockNumber new_rel_pages; double new_rel_tuples; BlockNumber new_rel_allvisible; TransactionId new_frozen_xid; /* measure elapsed time iff autovacuum logging requires it */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) { pg_rusage_init(&ru0); starttime = GetCurrentTimestamp(); } if (vacstmt->options & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; vac_strategy = bstrategy; vacuum_set_xid_limits(vacstmt->freeze_min_age, vacstmt->freeze_table_age, onerel->rd_rel->relisshared, &OldestXmin, &FreezeLimit, &freezeTableLimit); scan_all = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid, freezeTableLimit); vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); vacrelstats->old_rel_pages = onerel->rd_rel->relpages; vacrelstats->old_rel_tuples = onerel->rd_rel->reltuples; vacrelstats->num_index_scans = 0; /* Open all indexes of the relation */ vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel); vacrelstats->hasindex = (nindexes > 0); /* Do the vacuuming */ lazy_scan_heap(onerel, vacrelstats, Irel, nindexes, scan_all); /* Done with indexes */ vac_close_indexes(nindexes, Irel, NoLock); /* * Optionally truncate the relation. * * Don't even think about it unless we have a shot at releasing a goodly * number of pages. Otherwise, the time taken isn't worth it. */ possibly_freeable = vacrelstats->rel_pages - vacrelstats->nonempty_pages; if (possibly_freeable > 0 && (possibly_freeable >= REL_TRUNCATE_MINIMUM || possibly_freeable >= vacrelstats->rel_pages / REL_TRUNCATE_FRACTION)) lazy_truncate_heap(onerel, vacrelstats); /* Vacuum the Free Space Map */ FreeSpaceMapVacuum(onerel); /* * Update statistics in pg_class. * * A corner case here is that if we scanned no pages at all because every * page is all-visible, we should not update relpages/reltuples, because * we have no new information to contribute. In particular this keeps * us from replacing relpages=reltuples=0 (which means "unknown tuple * density") with nonzero relpages and reltuples=0 (which means "zero * tuple density") unless there's some actual evidence for the latter. * * We do update relallvisible even in the corner case, since if the * table is all-visible we'd definitely like to know that. But clamp * the value to be not more than what we're setting relpages to. * * Also, don't change relfrozenxid if we skipped any pages, since then * we don't know for certain that all tuples have a newer xmin. */ new_rel_pages = vacrelstats->rel_pages; new_rel_tuples = vacrelstats->new_rel_tuples; if (vacrelstats->scanned_pages == 0 && new_rel_pages > 0) { new_rel_pages = vacrelstats->old_rel_pages; new_rel_tuples = vacrelstats->old_rel_tuples; } new_rel_allvisible = visibilitymap_count(onerel); if (new_rel_allvisible > new_rel_pages) new_rel_allvisible = new_rel_pages; new_frozen_xid = FreezeLimit; if (vacrelstats->scanned_pages < vacrelstats->rel_pages) new_frozen_xid = InvalidTransactionId; vac_update_relstats(onerel, new_rel_pages, new_rel_tuples, new_rel_allvisible, vacrelstats->hasindex, new_frozen_xid); /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, new_rel_tuples); /* and log the action if appropriate */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) { TimestampTz endtime = GetCurrentTimestamp(); if (Log_autovacuum_min_duration == 0 || TimestampDifferenceExceeds(starttime, endtime, Log_autovacuum_min_duration)) { TimestampDifference(starttime, endtime, &secs, &usecs); read_rate = 0; write_rate = 0; if ((secs > 0) || (usecs > 0)) { read_rate = (double) BLCKSZ * VacuumPageMiss / (1024 * 1024) / (secs + usecs / 1000000.0); write_rate = (double) BLCKSZ * VacuumPageDirty / (1024 * 1024) / (secs + usecs / 1000000.0); } ereport(LOG, (errmsg("automatic vacuum of table \"%s.%s.%s\": index scans: %d\n" "pages: %d removed, %d remain\n" "tuples: %.0f removed, %.0f remain\n" "buffer usage: %d hits, %d misses, %d dirtied\n" "avg read rate: %.3f MiB/s, avg write rate: %.3f MiB/s\n" "system usage: %s", get_database_name(MyDatabaseId), get_namespace_name(RelationGetNamespace(onerel)), RelationGetRelationName(onerel), vacrelstats->num_index_scans, vacrelstats->pages_removed, vacrelstats->rel_pages, vacrelstats->tuples_deleted, vacrelstats->new_rel_tuples, VacuumPageHit, VacuumPageMiss, VacuumPageDirty, read_rate,write_rate, pg_rusage_show(&ru0)))); } } }
foreach(lc, allocated_descriptors) { desc = lfirst(lc); if (desc->indexRelid == indexRel->rd_id) return desc; } heapRel = relation_open(indexRel->rd_index->indrelid, AccessShareLock); desc = palloc0(sizeof(ZDBIndexDescriptor)); /* these all come from the actual index */ desc->indexRelid = RelationGetRelid(indexRel); desc->heapRelid = RelationGetRelid(heapRel); desc->isShadow = ZDBIndexOptionsGetShadow(indexRel) != NULL; desc->logit = false; desc->databaseName = pstrdup(get_database_name(MyDatabaseId)); desc->schemaName = pstrdup(get_namespace_name(RelationGetNamespace(heapRel))); desc->tableName = pstrdup(RelationGetRelationName(heapRel)); desc->options = ZDBIndexOptionsGetOptions(indexRel) == NULL ? NULL : pstrdup(ZDBIndexOptionsGetOptions(indexRel)); desc->searchPreference = ZDBIndexOptionsGetSearchPreference(indexRel); desc->refreshInterval = ZDBIndexOptionsGetRefreshInterval(indexRel); desc->bulk_concurrency = ZDBIndexOptionsGetBulkConcurrency(indexRel); desc->batch_size = ZDBIndexOptionsGetBatchSize(indexRel); desc->ignoreVisibility = ZDBIndexOptionsGetIgnoreVisibility(indexRel); desc->fieldLists = ZDBIndexOptionsGetFieldLists(indexRel); desc->alwaysResolveJoins = ZDBIndexOptionsAlwaysResolveJoins(indexRel); heapTupDesc = RelationGetDescr(heapRel); for (i = 0; i < heapTupDesc->natts; i++) { if (heapTupDesc->attrs[i]->atttypid == JSONOID) {
/* * lazy_vacuum_rel() -- perform LAZY VACUUM for one heap relation * * This routine vacuums a single heap, cleans out its indexes, and * updates its relpages and reltuples statistics. * * At entry, we have already established a transaction and opened * and locked the relation. */ void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy) { LVRelStats *vacrelstats; Relation *Irel; int nindexes; BlockNumber possibly_freeable; PGRUsage ru0; TimestampTz starttime = 0; bool scan_all; TransactionId freezeTableLimit; pg_rusage_init(&ru0); /* measure elapsed time iff autovacuum logging requires it */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration > 0) starttime = GetCurrentTimestamp(); if (vacstmt->options & VACOPT_VERBOSE) elevel = INFO; else elevel = DEBUG2; vac_strategy = bstrategy; vacuum_set_xid_limits(vacstmt->freeze_min_age, vacstmt->freeze_table_age, onerel->rd_rel->relisshared, &OldestXmin, &FreezeLimit, &freezeTableLimit); scan_all = TransactionIdPrecedesOrEquals(onerel->rd_rel->relfrozenxid, freezeTableLimit); vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats)); vacrelstats->old_rel_tuples = onerel->rd_rel->reltuples; vacrelstats->num_index_scans = 0; /* Open all indexes of the relation */ vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel); vacrelstats->hasindex = (nindexes > 0); /* Do the vacuuming */ lazy_scan_heap(onerel, vacrelstats, Irel, nindexes, scan_all); /* Done with indexes */ vac_close_indexes(nindexes, Irel, NoLock); /* * Optionally truncate the relation. * * Don't even think about it unless we have a shot at releasing a goodly * number of pages. Otherwise, the time taken isn't worth it. */ possibly_freeable = vacrelstats->rel_pages - vacrelstats->nonempty_pages; if (possibly_freeable > 0 && (possibly_freeable >= REL_TRUNCATE_MINIMUM || possibly_freeable >= vacrelstats->rel_pages / REL_TRUNCATE_FRACTION)) lazy_truncate_heap(onerel, vacrelstats); /* Vacuum the Free Space Map */ FreeSpaceMapVacuum(onerel); /* * Update statistics in pg_class. But don't change relfrozenxid if we * skipped any pages. */ vac_update_relstats(onerel, vacrelstats->rel_pages, vacrelstats->new_rel_tuples, vacrelstats->hasindex, (vacrelstats->scanned_pages < vacrelstats->rel_pages) ? InvalidTransactionId : FreezeLimit); /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, vacrelstats->new_rel_tuples); /* and log the action if appropriate */ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0) { if (Log_autovacuum_min_duration == 0 || TimestampDifferenceExceeds(starttime, GetCurrentTimestamp(), Log_autovacuum_min_duration)) ereport(LOG, (errmsg("automatic vacuum of table \"%s.%s.%s\": index scans: %d\n" "pages: %d removed, %d remain\n" "tuples: %.0f removed, %.0f remain\n" "system usage: %s", get_database_name(MyDatabaseId), get_namespace_name(RelationGetNamespace(onerel)), RelationGetRelationName(onerel), vacrelstats->num_index_scans, vacrelstats->pages_removed, vacrelstats->rel_pages, vacrelstats->tuples_deleted, vacrelstats->new_rel_tuples, pg_rusage_show(&ru0)))); } }
/* * Delete error log of the specified relation. This returns true from master * iif all segments and master find the relation. */ Datum gp_truncate_error_log(PG_FUNCTION_ARGS) { text *relname; char *relname_str; RangeVar *relrv; Oid relid; bool allResults = true; relname = PG_GETARG_TEXT_P(0); relname_str = text_to_cstring(relname); if (strcmp(relname_str, "*.*") == 0) { /* * Only superuser is allowed to delete log files across database. */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to delete all error log files")))); ErrorLogDelete(InvalidOid, InvalidOid); } else if (strcmp(relname_str, "*") == 0) { /* * Database owner can delete error log files. */ if (!pg_database_ownercheck(MyDatabaseId, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, get_database_name(MyDatabaseId)); ErrorLogDelete(MyDatabaseId, InvalidOid); } else { AclResult aclresult; relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); relid = RangeVarGetRelid(relrv, true); /* Return false if the relation does not exist. */ if (!OidIsValid(relid)) PG_RETURN_BOOL(false); /* * Allow only the table owner to truncate error log. */ aclresult = pg_class_aclcheck(relid, GetUserId(), ACL_TRUNCATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_CLASS, relrv->relname); /* We don't care if this fails or not. */ ErrorLogDelete(MyDatabaseId, relid); } /* * Dispatch the work to segments. */ if (Gp_role == GP_ROLE_DISPATCH) { int i = 0; StringInfoData sql; CdbPgResults cdb_pgresults = {NULL, 0}; initStringInfo(&sql); appendStringInfo(&sql, "SELECT pg_catalog.gp_truncate_error_log(%s)", quote_literal_internal(text_to_cstring(relname))); CdbDispatchCommand(sql.data, DF_WITH_SNAPSHOT, &cdb_pgresults); for (i = 0; i < cdb_pgresults.numResults; i++) { Datum value; bool isnull; struct pg_result *pgresult = cdb_pgresults.pg_results[i]; if (PQresultStatus(pgresult) != PGRES_TUPLES_OK) { cdbdisp_clearCdbPgResults(&cdb_pgresults); ereport(ERROR, (errmsg("unexpected result from segment: %d", PQresultStatus(pgresult)))); } value = ResultToDatum(pgresult, 0, 0, boolin, &isnull); allResults &= (!isnull && DatumGetBool(value)); } cdbdisp_clearCdbPgResults(&cdb_pgresults); pfree(sql.data); } /* Return true iif all segments return true. */ PG_RETURN_BOOL(allResults); }