コード例 #1
0
ファイル: proclang.c プロジェクト: CraigBryan/PostgresqlFun
/*
 * Guts of language creation.
 */
static void
create_proc_lang(const char *languageName,
				 Oid handlerOid, Oid valOid, bool trusted)
{
	Relation	rel;
	TupleDesc	tupDesc;
	Datum		values[Natts_pg_language];
	char		nulls[Natts_pg_language];
	NameData	langname;
	HeapTuple	tup;
	ObjectAddress myself,
				referenced;

	/*
	 * Insert the new language into pg_language
	 */
	rel = heap_open(LanguageRelationId, RowExclusiveLock);
	tupDesc = rel->rd_att;

	memset(values, 0, sizeof(values));
	memset(nulls, ' ', sizeof(nulls));

	namestrcpy(&langname, languageName);
	values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
	values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
	values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
	values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
	values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
	nulls[Anum_pg_language_lanacl - 1] = 'n';

	tup = heap_formtuple(tupDesc, values, nulls);

	simple_heap_insert(rel, tup);

	CatalogUpdateIndexes(rel, tup);

	/*
	 * Create dependencies for language
	 */
	myself.classId = LanguageRelationId;
	myself.objectId = HeapTupleGetOid(tup);
	myself.objectSubId = 0;

	/* dependency on the PL handler function */
	referenced.classId = ProcedureRelationId;
	referenced.objectId = handlerOid;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on the validator function, if any */
	if (OidIsValid(valOid))
	{
		referenced.classId = ProcedureRelationId;
		referenced.objectId = valOid;
		referenced.objectSubId = 0;
		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
	}

	heap_close(rel, RowExclusiveLock);
}
コード例 #2
0
ファイル: catcache.c プロジェクト: sunyangkobe/cscd43
/*
 * build_dummy_tuple
 *		Generate a palloc'd HeapTuple that contains the specified key
 *		columns, and NULLs for other columns.
 *
 * This is used to store the keys for negative cache entries and CatCList
 * entries, which don't have real tuples associated with them.
 */
static HeapTuple
build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys)
{
	HeapTuple	ntp;
	TupleDesc	tupDesc = cache->cc_tupdesc;
	Datum	   *values;
	char	   *nulls;
	Oid			tupOid = InvalidOid;
	NameData	tempNames[4];
	int			i;

	values = (Datum *) palloc(tupDesc->natts * sizeof(Datum));
	nulls = (char *) palloc(tupDesc->natts * sizeof(char));

	memset(values, 0, tupDesc->natts * sizeof(Datum));
	memset(nulls, 'n', tupDesc->natts * sizeof(char));

	for (i = 0; i < nkeys; i++)
	{
		int			attindex = cache->cc_key[i];
		Datum		keyval = skeys[i].sk_argument;

		if (attindex > 0)
		{
			/*
			 * Here we must be careful in case the caller passed a C
			 * string where a NAME is wanted: convert the given argument
			 * to a correctly padded NAME.	Otherwise the memcpy() done in
			 * heap_formtuple could fall off the end of memory.
			 */
			if (cache->cc_isname[i])
			{
				Name		newval = &tempNames[i];

				namestrcpy(newval, DatumGetCString(keyval));
				keyval = NameGetDatum(newval);
			}
			values[attindex - 1] = keyval;
			nulls[attindex - 1] = ' ';
		}
		else
		{
			Assert(attindex == ObjectIdAttributeNumber);
			tupOid = DatumGetObjectId(keyval);
		}
	}

	ntp = heap_formtuple(tupDesc, values, nulls);
	if (tupOid != InvalidOid)
		HeapTupleSetOid(ntp, tupOid);

	pfree(values);
	pfree(nulls);

	return ntp;
}
コード例 #3
0
ファイル: TupleDesc.c プロジェクト: jmptrader/pljava
/*
 * Class:     org_postgresql_pljava_internal_TupleDesc
 * Method:    _formTuple
 * Signature: (J[Ljava/lang/Object;)Lorg/postgresql/pljava/internal/Tuple;
 */
JNIEXPORT jobject JNICALL
Java_org_postgresql_pljava_internal_TupleDesc__1formTuple(JNIEnv* env, jclass cls, jlong _this, jobjectArray jvalues)
{
	jobject result = 0;

	BEGIN_NATIVE
	Ptr2Long p2l;
	p2l.longVal = _this;
	PG_TRY();
	{
		jint   idx;
		HeapTuple tuple;
		MemoryContext curr;
		TupleDesc self = (TupleDesc)p2l.ptrVal;
		int    count   = self->natts;
		Datum* values  = (Datum*)palloc(count * sizeof(Datum));
		char*  nulls   = palloc(count);
		jobject typeMap = Invocation_getTypeMap();

		memset(values, 0,  count * sizeof(Datum));
		memset(nulls, 'n', count);	/* all values null initially */
	
		for(idx = 0; idx < count; ++idx)
		{
			jobject value = JNI_getObjectArrayElement(jvalues, idx);
			if(value != 0)
			{
				Type type = Type_fromOid(SPI_gettypeid(self, idx + 1), typeMap);
				values[idx] = Type_coerceObject(type, value);
				nulls[idx] = ' ';
			}
		}

		curr = MemoryContextSwitchTo(JavaMemoryContext);
		tuple = heap_formtuple(self, values, nulls);
		result = Tuple_internalCreate(tuple, false);
		MemoryContextSwitchTo(curr);
		pfree(values);
		pfree(nulls);
	}
	PG_CATCH();
	{
		Exception_throw_ERROR("heap_formtuple");
	}
	PG_END_TRY();
	END_NATIVE
	return result;
}
コード例 #4
0
ファイル: apsp.c プロジェクト: CCheng1231/pgrouting
static int compute_apsp_warshall(char* sql, bool directed, 
                                 bool has_reverse_cost, 
                                 apsp_element_t **pair, int *pair_count) 
{
  int i;
  int SPIcode;
  void *SPIplan;
  Portal SPIportal;
  bool moredata = TRUE;
  int ntuples;
  edge_t *edges = NULL;
  int total_tuples = 0;
  edge_columns_t edge_columns = {.id= -1, .source= -1, .target= -1, 
                                 .cost= -1, .reverse_cost= -1};
  int v_max_id=0;
  int v_min_id=INT_MAX;

  int s_count = 0;
  int t_count = 0;

  char *err_msg;
  int ret = -1;
  register int z;

//  set<int> vertices;
  
  DBG("start compute_apsp_warshall\n");
        
  SPIcode = SPI_connect();
  if (SPIcode  != SPI_OK_CONNECT)
    {
      elog(ERROR, "compute_apsp_warshall: couldn't open a connection to SPI");
      return -1;
    }

  SPIplan = SPI_prepare(sql, 0, NULL);
  if (SPIplan  == NULL)
    {
      elog(ERROR, "compute_apsp_warshall: couldn't create query plan via SPI");
      return -1;
    }

  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) 
    {
      elog(ERROR, "compute_apsp_warshall: SPI_cursor_open('%s') returns NULL", sql);
      return -1;
    }

  while (moredata == TRUE)
    {
      SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);

      if (edge_columns.id == -1) 
        {
          if (fetch_edge_columns(SPI_tuptable, &edge_columns, 
                                 has_reverse_cost) == -1)
	    return finish(SPIcode, ret);
        }

      ntuples = SPI_processed;
      total_tuples += ntuples;
      if (!edges)
        edges = palloc(total_tuples * sizeof(edge_t));
      else
        edges = repalloc(edges, total_tuples * sizeof(edge_t));

      if (edges == NULL) 
        {
          elog(ERROR, "Out of memory");
	    return finish(SPIcode, ret);	  
        }

      DBG("Number of tuples fetched: %i",ntuples);
      
      if (ntuples > 0) 
        {
          int t;
          SPITupleTable *tuptable = SPI_tuptable;
          TupleDesc tupdesc = SPI_tuptable->tupdesc;
                
          for (t = 0; t < ntuples; t++) 
            {
              HeapTuple tuple = tuptable->vals[t];
              fetch_edge(&tuple, &tupdesc, &edge_columns, 
                         &edges[total_tuples - ntuples + t]);
//	      vertices.insert(edges[total_tuples - ntuples + t].source);
//	      vertices.insert(edges[total_tuples - ntuples + t].target);
            }
          SPI_freetuptable(tuptable);
        } 
      else 
        {
          moredata = FALSE;
        }
    }
    
#ifdef DEBUG
      
      
          
          for (i = 0; i < total_tuples; i++) 
            {
              DBG("Step %i src_vertex_id  %i ", i, edges[i].source);
              DBG("        dest_vertex_id    %i ", edges[i].target);
              DBG("        cost       %f ", edges[i].cost);
            }
      
#endif
    

  DBG("Calling boost_apsp\n");
        
  //start_vertex -= v_min_id;
  //end_vertex   -= v_min_id;

  ret = boost_apsp(edges, total_tuples, 0,                        //vertices.size()
                       directed, has_reverse_cost,
                       pair, pair_count, &err_msg);
  DBG("Boost message: \n%s",err_msg);
  DBG("SIZE %i\n",*pair_count);

/*  //::::::::::::::::::::::::::::::::
  //:: restoring original vertex id
  //::::::::::::::::::::::::::::::::
  for(z=0;z<*path_count;z++)
  {
    //DBG("vetex %i\n",(*path)[z].vertex_id);
    (*path)[z].vertex_id+=v_min_id;
  }

  DBG("ret = %i\n", ret);

  DBG("*path_count = %i\n", *path_count);

  DBG("ret = %i\n", ret);
  */
  if (ret < 0)
    {
      //elog(ERROR, "Error computing path: %s", err_msg);
      ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), 
        errmsg("Error computing path: %s", err_msg)));
    } 
    
  return finish(SPIcode, ret);
}


PG_FUNCTION_INFO_V1(apsp_warshall);
Datum
apsp_warshall(PG_FUNCTION_ARGS)
{
  FuncCallContext     *funcctx;
  int                  call_cntr;
  int                  max_calls;
  TupleDesc            tuple_desc;
  apsp_element_t      *pair;                         

  /* stuff done only on the first call of the function */
  if (SRF_IS_FIRSTCALL())
    {
      MemoryContext   oldcontext;
      int pair_count = 0;  
      int ret;

      /* create a function context for cross-call persistence */
      funcctx = SRF_FIRSTCALL_INIT();

      /* switch to memory context appropriate for multiple function calls */
      oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);


      ret = compute_apsp_warshall(text2char(PG_GETARG_TEXT_P(0)),
                                  PG_GETARG_BOOL(1),
                                  PG_GETARG_BOOL(2), &pair, &pair_count);                  
#ifdef DEBUG
      DBG("Ret is %i", ret);
      if (ret >= 0) 
        {
          int i;
          for (i = 0; i < pair_count; i++) 
            {
              DBG("Step: %i, source_id: %i, target_id: %i, cost: %f ", i, pair[i].src_vertex_id, pair[i].dest_vertex_id, pair[i].cost);
            }
        }
#endif

      /* total number of tuples to be returned */
      funcctx->max_calls = pair_count;
      funcctx->user_fctx = pair;

      funcctx->tuple_desc = 
        BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));

      MemoryContextSwitchTo(oldcontext);
    }

  /* stuff done on every call of the function */
  funcctx = SRF_PERCALL_SETUP();

  call_cntr = funcctx->call_cntr;
  max_calls = funcctx->max_calls;
  tuple_desc = funcctx->tuple_desc;
  pair = (apsp_element_t*) funcctx->user_fctx;

  if (call_cntr < max_calls)    /* do when there is more left to send */
    {
      HeapTuple    tuple;
      Datum        result;
      Datum *values;
      char* nulls;

      /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one    
 
      values = palloc(4 * sizeof(Datum));
      nulls = palloc(4 * sizeof(char));
  
      values[0] = call_cntr;
      nulls[0] = ' ';
      values[1] = Int32GetDatum(path[call_cntr].vertex_id);
      nulls[1] = ' ';
      values[2] = Int32GetDatum(path[call_cntr].edge_id);
      nulls[2] = ' ';
      values[3] = Float8GetDatum(path[call_cntr].cost);
      nulls[3] = ' ';
      */
    
      values = palloc(4 * sizeof(Datum));
      nulls = palloc(4 * sizeof(char));

      values[0] = Int32GetDatum(call_cntr);
      nulls[0] = ' ';
      values[1] = Int32GetDatum(pair[call_cntr].src_vertex_id);
      nulls[1] = ' ';
      values[2] = Int32GetDatum(pair[call_cntr].dest_vertex_id);
      nulls[2] = ' ';
      values[3] = Float8GetDatum(pair[call_cntr].cost);
      nulls[3] = ' ';
		      
      tuple = heap_formtuple(tuple_desc, values, nulls);

      /* make the tuple into a datum */
      result = HeapTupleGetDatum(tuple);

      /* clean up (this is not really necessary) */
      pfree(values);
      pfree(nulls);

      SRF_RETURN_NEXT(funcctx, result);
    }
  else    /* do when there is no more left */
    {
      SRF_RETURN_DONE(funcctx);
    }
}
コード例 #5
0
ファイル: dijkstra.c プロジェクト: guolivar/totus-niwa
static int compute_shortest_path(char* sql, int start_vertex, 
                                 int end_vertex, bool directed, 
                                 bool has_reverse_cost, 
                                 path_element_t **path, int *path_count) 
{

  int SPIcode;
  void *SPIplan;
  Portal SPIportal;
  bool moredata = TRUE;
  int ntuples;
  edge_t *edges = NULL;
  int total_tuples = 0;
  edge_columns_t edge_columns = {id: -1, source: -1, target: -1, 
                                 cost: -1, reverse_cost: -1};
  int v_max_id=0;
  int v_min_id=INT_MAX;

  int s_count = 0;
  int t_count = 0;

  char *err_msg;
  int ret = -1;
  register int z;

  DBG("start shortest_path\n");
        
  SPIcode = SPI_connect();
  if (SPIcode  != SPI_OK_CONNECT)
    {
      elog(ERROR, "shortest_path: couldn't open a connection to SPI");
      return -1;
    }

  SPIplan = SPI_prepare(sql, 0, NULL);
  if (SPIplan  == NULL)
    {
      elog(ERROR, "shortest_path: couldn't create query plan via SPI");
      return -1;
    }

  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) 
    {
      elog(ERROR, "shortest_path: SPI_cursor_open('%s') returns NULL", sql);
      return -1;
    }

  while (moredata == TRUE)
    {
      SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);

      if (edge_columns.id == -1) 
        {
          if (fetch_edge_columns(SPI_tuptable, &edge_columns, 
                                 has_reverse_cost) == -1)
	    return finish(SPIcode, ret);
        }

      ntuples = SPI_processed;
      total_tuples += ntuples;
      if (!edges)
        edges = palloc(total_tuples * sizeof(edge_t));
      else
        edges = repalloc(edges, total_tuples * sizeof(edge_t));

      if (edges == NULL) 
        {
          elog(ERROR, "Out of memory");
	    return finish(SPIcode, ret);	  
        }

      if (ntuples > 0) 
        {
          int t;
          SPITupleTable *tuptable = SPI_tuptable;
          TupleDesc tupdesc = SPI_tuptable->tupdesc;
                
          for (t = 0; t < ntuples; t++) 
            {
              HeapTuple tuple = tuptable->vals[t];
              fetch_edge(&tuple, &tupdesc, &edge_columns, 
                         &edges[total_tuples - ntuples + t]);
            }
          SPI_freetuptable(tuptable);
        } 
      else 
        {
          moredata = FALSE;
        }
    }

  //defining min and max vertex id
      
  DBG("Total %i tuples", total_tuples);
    
  for(z=0; z<total_tuples; z++)
  {
    if(edges[z].source<v_min_id)
    v_min_id=edges[z].source;
  
    if(edges[z].source>v_max_id)
      v_max_id=edges[z].source;
		            
    if(edges[z].target<v_min_id)
      v_min_id=edges[z].target;

    if(edges[z].target>v_max_id)
      v_max_id=edges[z].target;      
								        
    DBG("%i <-> %i", v_min_id, v_max_id);
							
  }

  //::::::::::::::::::::::::::::::::::::  
  //:: reducing vertex id (renumbering)
  //::::::::::::::::::::::::::::::::::::
  for(z=0; z<total_tuples; z++)
  {
    //check if edges[] contains source and target
    if(edges[z].source == start_vertex || edges[z].target == start_vertex)
      ++s_count;
    if(edges[z].source == end_vertex || edges[z].target == end_vertex)
      ++t_count;

    edges[z].source-=v_min_id;
    edges[z].target-=v_min_id;
    DBG("%i - %i", edges[z].source, edges[z].target);      
  }

  DBG("Total %i tuples", total_tuples);

  if(s_count == 0)
  {
    elog(ERROR, "Source vertex: %d was not found as vertex of any of the input edges.", start_vertex);
    return -1;
  }
      
  if(t_count == 0)
  {
    elog(ERROR, "Target vertex: %d was not found as vertex of any of the input edges.", end_vertex);
    return -1;
  }
  
  DBG("Calling boost_dijkstra\n");
        
  start_vertex -= v_min_id;
  end_vertex   -= v_min_id;

  ret = boost_dijkstra(edges, total_tuples, start_vertex, end_vertex,
                       directed, has_reverse_cost,
                       path, path_count, &err_msg);

  DBG("SIZE %i\n",*path_count);

  //::::::::::::::::::::::::::::::::
  //:: restoring original vertex id
  //::::::::::::::::::::::::::::::::
  for(z=0;z<*path_count;z++)
  {
    //DBG("vetex %i\n",(*path)[z].vertex_id);
    (*path)[z].vertex_id+=v_min_id;
  }

  DBG("ret = %i\n", ret);

  DBG("*path_count = %i\n", *path_count);

  DBG("ret = %i\n", ret);
  
  if (ret < 0)
    {
      //elog(ERROR, "Error computing path: %s", err_msg);
      ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), 
        errmsg("Error computing path: %s", err_msg)));
    } 

  if (edges) {
    /* clean up input egdes */
    pfree (edges);
  }
    
  return finish(SPIcode, ret);
}


PG_FUNCTION_INFO_V1(shortest_path);
Datum
shortest_path(PG_FUNCTION_ARGS)
{
  FuncCallContext     *funcctx;
  int                  call_cntr;
  int                  max_calls;
  TupleDesc            tuple_desc;
  path_element_t      *path = NULL;
  char                *sql = NULL;

  /* stuff done only on the first call of the function */
  if (SRF_IS_FIRSTCALL())
    {
      MemoryContext   oldcontext;
      int path_count = 0;
      int ret;

      /* create a function context for cross-call persistence */
      funcctx = SRF_FIRSTCALL_INIT();

      /* switch to memory context appropriate for multiple function calls */
      oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

      /* edge sql query */
      sql = text2char(PG_GETARG_TEXT_P(0));

      ret = compute_shortest_path(sql,
                                  PG_GETARG_INT32(1),
                                  PG_GETARG_INT32(2),
                                  PG_GETARG_BOOL(3),
                                  PG_GETARG_BOOL(4), &path, &path_count);

      /* clean up sql query string */
      if (sql) {
        pfree (sql);
      }

#ifdef DEBUG
      DBG("Ret is %i", ret);
      if (ret >= 0) 
        {
          int i;
          for (i = 0; i < path_count; i++) 
            {
              DBG("Step %i vertex_id  %i ", i, path[i].vertex_id);
              DBG("        edge_id    %i ", path[i].edge_id);
              DBG("        cost       %f ", path[i].cost);
            }
        }
#endif

      /* total number of tuples to be returned */
      funcctx->max_calls = path_count;
      funcctx->user_fctx = path;

      funcctx->tuple_desc = 
        BlessTupleDesc(RelationNameGetTupleDesc("path_result"));

      MemoryContextSwitchTo(oldcontext);
    }

  /* stuff done on every call of the function */
  funcctx = SRF_PERCALL_SETUP();

  call_cntr = funcctx->call_cntr;
  max_calls = funcctx->max_calls;
  tuple_desc = funcctx->tuple_desc;
  path = (path_element_t*) funcctx->user_fctx;

  if (call_cntr < max_calls)    /* do when there is more left to send */
    {
      HeapTuple    tuple;
      Datum        result;
      Datum *values;
      char* nulls;

      /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one    
 
      values = palloc(4 * sizeof(Datum));
      nulls = palloc(4 * sizeof(char));
  
      values[0] = call_cntr;
      nulls[0] = ' ';
      values[1] = Int32GetDatum(path[call_cntr].vertex_id);
      nulls[1] = ' ';
      values[2] = Int32GetDatum(path[call_cntr].edge_id);
      nulls[2] = ' ';
      values[3] = Float8GetDatum(path[call_cntr].cost);
      nulls[3] = ' ';
      */
    
      values = palloc(3 * sizeof(Datum));
      nulls = palloc(3 * sizeof(char));

      values[0] = Int32GetDatum(path[call_cntr].vertex_id);
      nulls[0] = ' ';
      values[1] = Int32GetDatum(path[call_cntr].edge_id);
      nulls[1] = ' ';
      values[2] = Float8GetDatum(path[call_cntr].cost);
      nulls[2] = ' ';
		      
      tuple = heap_formtuple(tuple_desc, values, nulls);

      /* make the tuple into a datum */
      result = HeapTupleGetDatum(tuple);

      /* clean up (this is not really necessary) */
      pfree(values);
      pfree(nulls);

      SRF_RETURN_NEXT(funcctx, result);
    }
  else    /* do when there is no more left */
    {
      if (path) {
        /* clean up returned edge paths
           must be a free because it's malloc'd */
        free (path);
        path = NULL;
      }

      SRF_RETURN_DONE(funcctx);
    }
}
コード例 #6
0
ファイル: pg_aggregate.c プロジェクト: sunyangkobe/cscd43
/*
 * AggregateCreate
 */
void
AggregateCreate(const char *aggName,
				Oid aggNamespace,
				List *aggtransfnName,
				List *aggfinalfnName,
				Oid aggBaseType,
				Oid aggTransType,
				const char *agginitval)
{
	Relation	aggdesc;
	HeapTuple	tup;
	char		nulls[Natts_pg_aggregate];
	Datum		values[Natts_pg_aggregate];
	Form_pg_proc proc;
	Oid			transfn;
	Oid			finalfn = InvalidOid;	/* can be omitted */
	Oid			rettype;
	Oid			finaltype;
	Oid			fnArgs[FUNC_MAX_ARGS];
	int			nargs_transfn;
	Oid			procOid;
	TupleDesc	tupDesc;
	int			i;
	ObjectAddress myself,
				referenced;

	/* sanity checks (caller should have caught these) */
	if (!aggName)
		elog(ERROR, "no aggregate name supplied");

	if (!aggtransfnName)
		elog(ERROR, "aggregate must have a transition function");

	/*
	 * If transtype is polymorphic, basetype must be polymorphic also;
	 * else we will have no way to deduce the actual transtype.
	 */
	if ((aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID) &&
		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("cannot determine transition data type"),
				 errdetail("An aggregate using \"anyarray\" or \"anyelement\" as "
				 "transition type must have one of them as its base type.")));

	/* handle transfn */
	MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
	fnArgs[0] = aggTransType;
	if (aggBaseType == ANYOID)
		nargs_transfn = 1;
	else
	{
		fnArgs[1] = aggBaseType;
		nargs_transfn = 2;
	}
	transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
								  &rettype);

	/*
	 * Return type of transfn (possibly after refinement by
	 * enforce_generic_type_consistency, if transtype isn't polymorphic)
	 * must exactly match declared transtype.
	 *
	 * In the non-polymorphic-transtype case, it might be okay to allow a
	 * rettype that's binary-coercible to transtype, but I'm not quite
	 * convinced that it's either safe or useful.  When transtype is
	 * polymorphic we *must* demand exact equality.
	 */
	if (rettype != aggTransType)
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("return type of transition function %s is not %s",
						NameListToString(aggtransfnName),
						format_type_be(aggTransType))));

	tup = SearchSysCache(PROCOID,
						 ObjectIdGetDatum(transfn),
						 0, 0, 0);
	if (!HeapTupleIsValid(tup))
		elog(ERROR, "cache lookup failed for function %u", transfn);
	proc = (Form_pg_proc) GETSTRUCT(tup);

	/*
	 * If the transfn is strict and the initval is NULL, make sure input
	 * type and transtype are the same (or at least binary-compatible), so
	 * that it's OK to use the first input value as the initial
	 * transValue.
	 */
	if (proc->proisstrict && agginitval == NULL)
	{
		if (!IsBinaryCoercible(aggBaseType, aggTransType))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
	}
	ReleaseSysCache(tup);

	/* handle finalfn, if supplied */
	if (aggfinalfnName)
	{
		MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
		fnArgs[0] = aggTransType;
		finalfn = lookup_agg_function(aggfinalfnName, 1, fnArgs,
									  &finaltype);
	}
	else
	{
		/*
		 * If no finalfn, aggregate result type is type of the state value
		 */
		finaltype = aggTransType;
	}
	Assert(OidIsValid(finaltype));

	/*
	 * If finaltype (i.e. aggregate return type) is polymorphic, basetype
	 * must be polymorphic also, else parser will fail to deduce result
	 * type.  (Note: given the previous test on transtype and basetype,
	 * this cannot happen, unless someone has snuck a finalfn definition
	 * into the catalogs that itself violates the rule against polymorphic
	 * result with no polymorphic input.)
	 */
	if ((finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID) &&
		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("cannot determine result data type"),
			   errdetail("An aggregate returning \"anyarray\" or \"anyelement\" "
						 "must have one of them as its base type.")));

	/*
	 * Everything looks okay.  Try to create the pg_proc entry for the
	 * aggregate.  (This could fail if there's already a conflicting
	 * entry.)
	 */
	MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
	fnArgs[0] = aggBaseType;

	procOid = ProcedureCreate(aggName,
							  aggNamespace,
							  false,	/* no replacement */
							  false,	/* doesn't return a set */
							  finaltype,		/* returnType */
							  INTERNALlanguageId,		/* languageObjectId */
							  0,
							  "aggregate_dummy",		/* placeholder proc */
							  "-",		/* probin */
							  true,		/* isAgg */
							  false,	/* security invoker (currently not
										 * definable for agg) */
							  false,	/* isStrict (not needed for agg) */
							  PROVOLATILE_IMMUTABLE,	/* volatility (not
														 * needed for agg) */
							  1,	/* parameterCount */
							  fnArgs);	/* parameterTypes */

	/*
	 * Okay to create the pg_aggregate entry.
	 */

	/* initialize nulls and values */
	for (i = 0; i < Natts_pg_aggregate; i++)
	{
		nulls[i] = ' ';
		values[i] = (Datum) NULL;
	}
	values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
	values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
	values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
	values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
	if (agginitval)
		values[Anum_pg_aggregate_agginitval - 1] =
			DirectFunctionCall1(textin, CStringGetDatum(agginitval));
	else
		nulls[Anum_pg_aggregate_agginitval - 1] = 'n';

	aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
	tupDesc = aggdesc->rd_att;

	tup = heap_formtuple(tupDesc, values, nulls);
	simple_heap_insert(aggdesc, tup);

	CatalogUpdateIndexes(aggdesc, tup);

	heap_close(aggdesc, RowExclusiveLock);

	/*
	 * Create dependencies for the aggregate (above and beyond those
	 * already made by ProcedureCreate).  Note: we don't need an explicit
	 * dependency on aggTransType since we depend on it indirectly through
	 * transfn.
	 */
	myself.classId = RelOid_pg_proc;
	myself.objectId = procOid;
	myself.objectSubId = 0;

	/* Depends on transition function */
	referenced.classId = RelOid_pg_proc;
	referenced.objectId = transfn;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* Depends on final function, if any */
	if (OidIsValid(finalfn))
	{
		referenced.classId = RelOid_pg_proc;
		referenced.objectId = finalfn;
		referenced.objectSubId = 0;
		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
	}
}
コード例 #7
0
ファイル: tspInterface.c プロジェクト: mrdapotts/pgrouting
static int compute_sql_asm_tsp(char* sql, int sourceVertexId,
                       bool reverseCost, 
                       tspPathElementType **path, int *pathCount) {
	int SPIcode;
  	void *SPIplan;
  	Portal SPIportal;
  	bool moredata = TRUE;
  	int ntuples;
  	tspEdgeType *edges = NULL;
  	int totalTuples = 0;

	DBG("Sql %s source %d reverse %s",sql,sourceVertexId,reverseCost==true?"true":"false");

  	tspEdgeType edgeColumns = {.id= -1, .source= -1, .target= -1, .cost= -1 };
  	char *errMesg;
  	int ret = -1;
  	errMesg=palloc(sizeof(char) * 300);	

  	DBG("start compute_sql_asm_tsp %i",*pathCount);

  	SPIcode = SPI_connect();
  	if (SPIcode  != SPI_OK_CONNECT) {
      		elog(ERROR, "compute_sql_asm_tsp: couldn't open a connection to SPI");
      		return -1;
  	}

		SPIplan = SPI_prepare(sql, 0, NULL);
  	if (SPIplan  == NULL) {
      		elog(ERROR, "compute_sql_asm_tsp: couldn't create query plan via SPI");
      		return -1;
  	}

  	if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) {
      		elog(ERROR, "compute_sql_asm_tsp: SPI_cursor_open('%s') returns NULL", sql);
      		return -1;
  	}

  	while (moredata == TRUE) {
      		SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);

      		if (edgeColumns.id == -1) {
          		if (!fetchEdgeTspColumns(SPI_tuptable, &edgeColumns,reverseCost))
            			return finish(SPIcode, ret);
      		}

      		ntuples = SPI_processed;
      		totalTuples += ntuples;
      		if (!edges){
        		edges = palloc(totalTuples * sizeof(tspEdgeType));
      		} else {
        		edges = repalloc(edges, totalTuples * sizeof(tspEdgeType));
		}
      		if (edges == NULL) {
          		elog(ERROR, "Out of memory");
          		return finish(SPIcode, ret);
      		}

      		if (ntuples > 0) {
          		int t;
          		SPITupleTable *tuptable = SPI_tuptable;
          		TupleDesc tupdesc = SPI_tuptable->tupdesc;

          		for (t = 0; t < ntuples; t++) {
              			HeapTuple tuple = tuptable->vals[t];
              			fetchEdgeTsp(&tuple, &tupdesc, &edgeColumns, &edges[totalTuples - ntuples + t],reverseCost);
          		}
          		SPI_freetuptable(tuptable);
      		} else {
          		moredata = FALSE;
      		}
  	}


  	DBG("Total %i tuples", totalTuples);
  	DBG("Calling tsp functions total tuples <%i> initial path count <%i>", totalTuples,*pathCount);
	
	ret=processATSPData(edges,totalTuples,sourceVertexId,reverseCost, path, pathCount,errMesg);

  	DBG("SIZE %i elements to process",*pathCount);

  	if (!ret ) {
      		elog(ERROR, "Error computing path: %s", errMesg);
  	}
  	return finish(SPIcode, ret);
}


PG_FUNCTION_INFO_V1(sql_asm_tsp);
Datum sql_asm_tsp(PG_FUNCTION_ARGS) {
  	FuncCallContext     *funcctx;
  	int                  callCntr;
  	int                  maxCalls;
  	TupleDesc            tupleDesc;
  	tspPathElementType   *path;

  	/* stuff done only on the first call of the function */
  	if (SRF_IS_FIRSTCALL()) {
      		MemoryContext   oldcontext;
      		int pathCount = 0;
      		int ret;

      		/* create a function context for cross-call persistence */
      		funcctx = SRF_FIRSTCALL_INIT();

      		/* switch to memory context appropriate for multiple function calls */
      		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

      		ret = compute_sql_asm_tsp(text2char(PG_GETARG_TEXT_P(0)),
                	PG_GETARG_INT32(1), PG_GETARG_BOOL(2), &path, &pathCount);


#ifdef DEBUG
      		if (ret >= 0) {
          		int i;
          		for (i = 0; i < pathCount; i++) {
              			DBG("Step # %i vertexId  %i cost %.4f", i, path[i].vertexId,path[i].cost);
          		}
      		}
#endif

      		/* total number of tuples to be returned */
      		funcctx->max_calls = pathCount;
      		funcctx->user_fctx = path;

      		DBG("Path count %i", pathCount);

      		funcctx->tuple_desc =
            		BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));

      		MemoryContextSwitchTo(oldcontext);
  	}

  	funcctx = SRF_PERCALL_SETUP();
  	callCntr = funcctx->call_cntr;
  	maxCalls = funcctx->max_calls;
  	tupleDesc = funcctx->tuple_desc;
  	path = (tspPathElementType*) funcctx->user_fctx;

  	if (callCntr < maxCalls) {   /* do when there is more left to send */
      		HeapTuple    tuple;
      		Datum        result;
      		Datum *values;
      		char* nulls;

      		values = palloc(4 * sizeof(Datum));
      		nulls = palloc(4 * sizeof(char));

      		values[0] = Int32GetDatum(callCntr);
      		nulls[0] = ' ';
      		values[1] = Int32GetDatum(path[callCntr].vertexId);
      		nulls[1] = ' ';
      		values[2] = Float8GetDatum(0); // edge id not supplied by this method
      		nulls[2] = ' ';
      		values[3] = Float8GetDatum(path[callCntr].cost);
      		nulls[3] = ' ';

      		tuple = heap_formtuple(tupleDesc, values, nulls);

      		/* make the tuple into a datum */
      		result = HeapTupleGetDatum(tuple);

      		/* clean up (this is not really necessary) */
      		pfree(values);
      		pfree(nulls);

      		SRF_RETURN_NEXT(funcctx, result);
  	} else {   /* do when there is no more left */
      		SRF_RETURN_DONE(funcctx);
  	}
}
コード例 #8
0
Datum
#else  // _MSC_VER
PGDLLEXPORT Datum
#endif
one_to_one_withPoints(PG_FUNCTION_ARGS) {
    FuncCallContext     *funcctx;
    uint32_t              call_cntr;
    uint32_t               max_calls;
    TupleDesc            tuple_desc;

    /*******************************************************************************/
    /*                          MODIFY AS NEEDED                                   */
    /*                                                                             */
    General_path_element_t  *result_tuples = NULL;
    size_t result_count = 0;
    /*                                                                             */
    /*******************************************************************************/

    if (SRF_IS_FIRSTCALL()) {
        MemoryContext   oldcontext;
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);


        /*******************************************************************************/
        /*                          MODIFY AS NEEDED                                   */
        // CREATE OR REPLACE FUNCTION pgr_withPoint(
        // edges_sql TEXT,
        // points_sql TEXT,
        // start_pid BIGINT,
        // end_pid BIGINT,
        // directed BOOLEAN -- DEFAULT true,
        // driving_side CHAR -- DEFAULT 'b',
        // details BOOLEAN -- DEFAULT true,
        // only_cost BOOLEAN DEFAULT false,

        PGR_DBG("Calling process");
        PGR_DBG("initial driving side:%s", pgr_text2char(PG_GETARG_TEXT_P(5)));
        process(
                pgr_text2char(PG_GETARG_TEXT_P(0)),
                pgr_text2char(PG_GETARG_TEXT_P(1)),
                PG_GETARG_INT64(2),
                PG_GETARG_INT64(3),
                PG_GETARG_BOOL(4),
                pgr_text2char(PG_GETARG_TEXT_P(5)),
                PG_GETARG_BOOL(6),
                PG_GETARG_BOOL(7),
                &result_tuples,
                &result_count);
        /*                                                                             */
        /*******************************************************************************/

        funcctx->max_calls = (uint32_t)result_count;
        funcctx->user_fctx = result_tuples;
        if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                         "that cannot accept type record")));

        funcctx->tuple_desc = tuple_desc;
        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();
    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    tuple_desc = funcctx->tuple_desc;
    result_tuples = (General_path_element_t*) funcctx->user_fctx;

    if (call_cntr < max_calls) {
        HeapTuple    tuple;
        Datum        result;
        Datum        *values;
        char*        nulls;

        /*******************************************************************************/
        /*                          MODIFY AS NEEDED                                   */
        // OUT seq BIGINT,
        // OUT path_seq,
        // OUT node BIGINT,
        // OUT edge BIGINT,
        // OUT cost FLOAT,
        // OUT agg_cost FLOAT)


        values = palloc(6 * sizeof(Datum));
        nulls = palloc(6 * sizeof(char));

        size_t i;
        for(i = 0; i < 6; ++i) {
            nulls[i] = ' ';
        }


        // postgres starts counting from 1
        values[0] = Int32GetDatum(call_cntr + 1);
        values[1] = Int32GetDatum(result_tuples[call_cntr].seq);
        values[2] = Int64GetDatum(result_tuples[call_cntr].node);
        values[3] = Int64GetDatum(result_tuples[call_cntr].edge);
        values[4] = Float8GetDatum(result_tuples[call_cntr].cost);
        values[5] = Float8GetDatum(result_tuples[call_cntr].agg_cost);
        /*******************************************************************************/

        tuple = heap_formtuple(tuple_desc, values, nulls);
        result = HeapTupleGetDatum(tuple);
        SRF_RETURN_NEXT(funcctx, result);
    } else {
        // cleanup
        if (result_tuples) free(result_tuples);

        SRF_RETURN_DONE(funcctx);
    }
}
コード例 #9
0
ファイル: rowtypes.c プロジェクト: KMU-embedded/mosbench-ext
/*
 * record_recv		- binary input routine for any composite type.
 */
Datum
record_recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	Oid			tupType = PG_GETARG_OID(1);

#ifdef NOT_USED
	int32		typmod = PG_GETARG_INT32(2);
#endif
	HeapTupleHeader result;
	int32		tupTypmod;
	TupleDesc	tupdesc;
	HeapTuple	tuple;
	RecordIOData *my_extra;
	int			ncolumns;
	int			usercols;
	int			validcols;
	int			i;
	Datum	   *values;
	char	   *nulls;

	/*
	 * Use the passed type unless it's RECORD; we can't support input of
	 * anonymous types, mainly because there's no good way to figure out which
	 * anonymous type is wanted.  Note that for RECORD, what we'll probably
	 * actually get is RECORD's typelem, ie, zero.
	 */
	if (tupType == InvalidOid || tupType == RECORDOID)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
		   errmsg("input of anonymous composite types is not implemented")));
	tupTypmod = -1;				/* for all non-anonymous types */
	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
	ncolumns = tupdesc->natts;

	/*
	 * We arrange to look up the needed I/O info just once per series of
	 * calls, assuming the record type doesn't change underneath us.
	 */
	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL ||
		my_extra->ncolumns != ncolumns)
	{
		fcinfo->flinfo->fn_extra =
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
							   sizeof(RecordIOData) - sizeof(ColumnIOData)
							   + ncolumns * sizeof(ColumnIOData));
		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
		my_extra->record_type = InvalidOid;
		my_extra->record_typmod = 0;
	}

	if (my_extra->record_type != tupType ||
		my_extra->record_typmod != tupTypmod)
	{
		MemSet(my_extra, 0,
			   sizeof(RecordIOData) - sizeof(ColumnIOData)
			   + ncolumns * sizeof(ColumnIOData));
		my_extra->record_type = tupType;
		my_extra->record_typmod = tupTypmod;
		my_extra->ncolumns = ncolumns;
	}

	values = (Datum *) palloc(ncolumns * sizeof(Datum));
	nulls = (char *) palloc(ncolumns * sizeof(char));

	/* Fetch number of columns user thinks it has */
	usercols = pq_getmsgint(buf, 4);

	/* Need to scan to count nondeleted columns */
	validcols = 0;
	for (i = 0; i < ncolumns; i++)
	{
		if (!tupdesc->attrs[i]->attisdropped)
			validcols++;
	}
	if (usercols != validcols)
		ereport(ERROR,
				(errcode(ERRCODE_DATATYPE_MISMATCH),
				 errmsg("wrong number of columns: %d, expected %d",
						usercols, validcols)));

	/* Process each column */
	for (i = 0; i < ncolumns; i++)
	{
		ColumnIOData *column_info = &my_extra->columns[i];
		Oid			column_type = tupdesc->attrs[i]->atttypid;
		Oid			coltypoid;
		int			itemlen;
		StringInfoData item_buf;
		StringInfo	bufptr;
		char		csave;

		/* Ignore dropped columns in datatype, but fill with nulls */
		if (tupdesc->attrs[i]->attisdropped)
		{
			values[i] = (Datum) 0;
			nulls[i] = 'n';
			continue;
		}

		/* Verify column datatype */
		coltypoid = pq_getmsgint(buf, sizeof(Oid));
		if (coltypoid != column_type)
			ereport(ERROR,
					(errcode(ERRCODE_DATATYPE_MISMATCH),
					 errmsg("wrong data type: %u, expected %u",
							coltypoid, column_type)));

		/* Get and check the item length */
		itemlen = pq_getmsgint(buf, 4);
		if (itemlen < -1 || itemlen > (buf->len - buf->cursor))
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
					 errmsg("insufficient data left in message")));

		if (itemlen == -1)
		{
			/* -1 length means NULL */
			bufptr = NULL;
			nulls[i] = 'n';
			csave = 0;			/* keep compiler quiet */
		}
		else
		{
			/*
			 * Rather than copying data around, we just set up a phony
			 * StringInfo pointing to the correct portion of the input buffer.
			 * We assume we can scribble on the input buffer so as to maintain
			 * the convention that StringInfos have a trailing null.
			 */
			item_buf.data = &buf->data[buf->cursor];
			item_buf.maxlen = itemlen + 1;
			item_buf.len = itemlen;
			item_buf.cursor = 0;

			buf->cursor += itemlen;

			csave = buf->data[buf->cursor];
			buf->data[buf->cursor] = '\0';

			bufptr = &item_buf;
			nulls[i] = ' ';
		}

		/* Now call the column's receiveproc */
		if (column_info->column_type != column_type)
		{
			getTypeBinaryInputInfo(column_type,
								   &column_info->typiofunc,
								   &column_info->typioparam);
			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
						  fcinfo->flinfo->fn_mcxt);
			column_info->column_type = column_type;
		}

		values[i] = ReceiveFunctionCall(&column_info->proc,
										bufptr,
										column_info->typioparam,
										tupdesc->attrs[i]->atttypmod);

		if (bufptr)
		{
			/* Trouble if it didn't eat the whole buffer */
			if (item_buf.cursor != itemlen)
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
						 errmsg("improper binary format in record column %d",
								i + 1)));

			buf->data[buf->cursor] = csave;
		}
	}

	tuple = heap_formtuple(tupdesc, values, nulls);

	/*
	 * We cannot return tuple->t_data because heap_formtuple allocates it as
	 * part of a larger chunk, and our caller may expect to be able to pfree
	 * our result.	So must copy the info into a new palloc chunk.
	 */
	result = (HeapTupleHeader) palloc(tuple->t_len);
	memcpy(result, tuple->t_data, tuple->t_len);

	heap_freetuple(tuple);
	pfree(values);
	pfree(nulls);
	ReleaseTupleDesc(tupdesc);

	PG_RETURN_HEAPTUPLEHEADER(result);
}
コード例 #10
0
ファイル: async.c プロジェクト: berkeley-cs186/course-fa07
/*
 *--------------------------------------------------------------
 * Async_Listen
 *
 *		This is executed by the SQL listen command.
 *
 *		Register the current backend as listening on the specified
 *		relation.
 *
 * Side effects:
 *		pg_listener is updated.
 *
 *--------------------------------------------------------------
 */
void
Async_Listen(const char *relname)
{
	Relation	lRel;
	HeapScanDesc scan;
	HeapTuple	tuple;
	Datum		values[Natts_pg_listener];
	char		nulls[Natts_pg_listener];
	int			i;
	bool		alreadyListener = false;

	if (Trace_notify)
		elog(DEBUG1, "Async_Listen(%s,%d)", relname, MyProcPid);

	lRel = heap_open(ListenerRelationId, ExclusiveLock);

	/* Detect whether we are already listening on this relname */
	scan = heap_beginscan(lRel, SnapshotNow, 0, NULL);
	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
	{
		Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(tuple);

		if (listener->listenerpid == MyProcPid &&
			strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0)
		{
			alreadyListener = true;
			/* No need to scan the rest of the table */
			break;
		}
	}
	heap_endscan(scan);

	if (alreadyListener)
	{
		heap_close(lRel, ExclusiveLock);
		return;
	}

	/*
	 * OK to insert a new tuple
	 */

	for (i = 0; i < Natts_pg_listener; i++)
	{
		nulls[i] = ' ';
		values[i] = PointerGetDatum(NULL);
	}

	i = 0;
	values[i++] = (Datum) relname;
	values[i++] = (Datum) MyProcPid;
	values[i++] = (Datum) 0;	/* no notifies pending */

	tuple = heap_formtuple(RelationGetDescr(lRel), values, nulls);
	simple_heap_insert(lRel, tuple);

#ifdef NOT_USED					/* currently there are no indexes */
	CatalogUpdateIndexes(lRel, tuple);
#endif

	heap_freetuple(tuple);

	heap_close(lRel, ExclusiveLock);

	/*
	 * now that we are listening, make sure we will unlisten before dying.
	 */
	if (!unlistenExitRegistered)
	{
		on_shmem_exit(Async_UnlistenOnExit, 0);
		unlistenExitRegistered = true;
	}
}
コード例 #11
0
ファイル: tsp2.c プロジェクト: mrdapotts/pgrouting
Datum
tsp_matrix(PG_FUNCTION_ARGS)
{
    FuncCallContext     *funcctx;
    int                  call_cntr;
    int                  max_calls;
    TupleDesc            tuple_desc;
    AttInMetadata       *attinmeta;

    DTYPE               *matrix;
    int                 *tsp_res;
    int                  num;

    /* stuff done only on the first call of the function */
    if (SRF_IS_FIRSTCALL()) {
        MemoryContext   oldcontext;
        //int path_count;
        int ret=-1;

        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();

        /* switch to memory context appropriate for multiple function calls */
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        matrix = get_pgarray(&num, PG_GETARG_ARRAYTYPE_P(0));

        ret = solve_tsp(matrix, num,
                        PG_GETARG_INT32(1), // start index
                        PG_GETARG_INT32(2), // end  index
                        &tsp_res);

        pfree(matrix);
        if (ret < 0) {
            elog(ERROR, "Error, failed to solve TSP.");
        }

        funcctx->max_calls = num;
        funcctx->user_fctx = tsp_res;

        /* Build a tuple descriptor for our result type */
        if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));

        funcctx->tuple_desc = BlessTupleDesc(tuple_desc);

        /*
         * generate attribute metadata needed later to produce tuples from raw
         * C strings
         */
        //attinmeta = TupleDescGetAttInMetadata(tuple_desc);
        //funcctx->attinmeta = attinmeta;

        MemoryContextSwitchTo(oldcontext);
    }

    /* stuff done on every call of the function */
    funcctx = SRF_PERCALL_SETUP();

    call_cntr  = funcctx->call_cntr;
    max_calls  = funcctx->max_calls;
    tuple_desc = funcctx->tuple_desc;
    tsp_res    = funcctx->user_fctx;

    DBG("Trying to allocate some memory");
    DBG("call_cntr = %i, max_calls = %i", call_cntr, max_calls);

    if (call_cntr < max_calls) {   /* do when there is more left to send */
        HeapTuple    tuple;
        Datum        result;
        Datum *values;
        char* nulls;

        values = palloc(2 * sizeof(Datum));
        nulls = palloc(2 * sizeof(char));

        values[0] = Int32GetDatum(call_cntr);
        nulls[0] = ' ';
        values[1] = Int32GetDatum(tsp_res[call_cntr]);
        nulls[1] = ' ';

        DBG("RESULT: %d, %d", call_cntr, tsp_res[call_cntr]);

        DBG("Heap making");

        tuple = heap_formtuple(tuple_desc, values, nulls);

        DBG("Datum making");

        /* make the tuple into a datum */
        result = HeapTupleGetDatum(tuple);

        DBG("RESULT: seq:%d, id:%d", call_cntr, tsp_res[call_cntr]);
        DBG("Trying to free some memory");

        /* clean up (this is not really necessary) */
        pfree(values);
        pfree(nulls);


        SRF_RETURN_NEXT(funcctx, result);
    }
    else {   /* do when there is no more left */
        DBG("Freeing tsp_res");
        free(tsp_res);

        DBG("Ending function");
        SRF_RETURN_DONE(funcctx);
    }
}
コード例 #12
0
Datum
#else  // _MSC_VER
PGDLLEXPORT Datum
#endif
one_to_many_dijkstra(PG_FUNCTION_ARGS) {
    FuncCallContext     *funcctx;
    uint32_t              call_cntr;
    uint32_t               max_calls;
    TupleDesc            tuple_desc;

    /**************************************************************************/
    /*                          MODIFY AS NEEDED                              */
    /*                                                                        */
    General_path_element_t  *result_tuples = 0;
    size_t result_count = 0;
    /*                                                                        */
    /**************************************************************************/

    if (SRF_IS_FIRSTCALL()) {
        MemoryContext   oldcontext;
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);


        /**********************************************************************/
        /*                          MODIFY AS NEEDED                          */
        // CREATE OR REPLACE FUNCTION pgr_dijkstra(sql text,
        // start_vid bigint,
        // end_vids anyarray,
        // directed boolean default true,
        // only_cost boolean default false

        PGR_DBG("Initializing arrays");
        int64_t* end_vidsArr;
        size_t size_end_vidsArr;
        end_vidsArr = (int64_t*)
            pgr_get_bigIntArray(&size_end_vidsArr, PG_GETARG_ARRAYTYPE_P(2));
        PGR_DBG("targetsArr size %ld ", size_end_vidsArr);

        PGR_DBG("Calling process");
        process(
                pgr_text2char(PG_GETARG_TEXT_P(0)),
                PG_GETARG_INT64(1),
                end_vidsArr, size_end_vidsArr,
                PG_GETARG_BOOL(3),
                PG_GETARG_BOOL(4),
                &result_tuples,
                &result_count);

        PGR_DBG("Cleaning arrays");
        free(end_vidsArr);
        /*                                                                    */
        /**********************************************************************/

        funcctx->max_calls = (uint32_t)result_count;
        funcctx->user_fctx = result_tuples;
        if (get_call_result_type(fcinfo, NULL, &tuple_desc)
                != TYPEFUNC_COMPOSITE) {
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                         "that cannot accept type record")));
        }

        funcctx->tuple_desc = tuple_desc;
        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();
    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    tuple_desc = funcctx->tuple_desc;
    result_tuples = (General_path_element_t*) funcctx->user_fctx;

    if (call_cntr < max_calls) {
        HeapTuple    tuple;
        Datum        result;
        Datum        *values;
        char*        nulls;

        /*********************************************************************/
        /*                          MODIFY AS NEEDED                         */
        // OUT seq integer,
        // OUT path_seq INTEGER,
        // OUT end_vid BIGINT,
        // OUT node bigint,
        // OUT edge bigint,
        // OUT cost float,
        // OUT agg_cost float)

        values = palloc(7 * sizeof(Datum));
        nulls = palloc(7 * sizeof(char));


        size_t i;
        for (i = 0; i < 7; ++i) {
            nulls[i] = ' ';
        }

        // postgres starts counting from 1
        values[0] = Int32GetDatum(call_cntr + 1);
        values[1] = Int32GetDatum(result_tuples[call_cntr].seq);
        values[2] = Int64GetDatum(result_tuples[call_cntr].end_id);
        values[3] = Int64GetDatum(result_tuples[call_cntr].node);
        values[4] = Int64GetDatum(result_tuples[call_cntr].edge);
        values[5] = Float8GetDatum(result_tuples[call_cntr].cost);
        values[6] = Float8GetDatum(result_tuples[call_cntr].agg_cost);
        /*********************************************************************/

        tuple = heap_formtuple(tuple_desc, values, nulls);
        result = HeapTupleGetDatum(tuple);
        SRF_RETURN_NEXT(funcctx, result);
    } else {
        // cleanup
        if (result_tuples) free(result_tuples);

        SRF_RETURN_DONE(funcctx);
    }
}
コード例 #13
0
ファイル: pg_operator.c プロジェクト: sunyangkobe/cscd43
/*
 * OperatorCreate
 *
 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
 *		operatorName			name for new operator
 *		operatorNamespace		namespace for new operator
 *		leftTypeId				X left type ID
 *		rightTypeId				X right type ID
 *		procedureName			procedure for operator
 *		commutatorName			X commutator operator
 *		negatorName				X negator operator
 *		restrictionName			X restriction sel. procedure
 *		joinName				X join sel. procedure
 *		canHash					hash join can be used with this operator
 *		leftSortName			X left sort operator (for merge join)
 *		rightSortName			X right sort operator (for merge join)
 *		ltCompareName			X L<R compare operator (for merge join)
 *		gtCompareName			X L>R compare operator (for merge join)
 *
 * This routine gets complicated because it allows the user to
 * specify operators that do not exist.  For example, if operator
 * "op" is being defined, the negator operator "negop" and the
 * commutator "commop" can also be defined without specifying
 * any information other than their names.	Since in order to
 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
 * operators must be placed in the fields of "op", a forward
 * declaration is done on the commutator and negator operators.
 * This is called creating a shell, and its main effect is to
 * create a tuple in the PG_OPERATOR catalog with minimal
 * information about the operator (just its name and types).
 * Forward declaration is used only for this purpose, it is
 * not available to the user as it is for type definition.
 *
 * Algorithm:
 *
 * check if operator already defined
 *	  if so, but oprcode is null, save the Oid -- we are filling in a shell
 *	  otherwise error
 * get the attribute types from relation descriptor for pg_operator
 * assign values to the fields of the operator:
 *	 operatorName
 *	 owner id (simply the user id of the caller)
 *	 operator "kind" either "b" for binary or "l" for left unary
 *	 canHash boolean
 *	 leftTypeObjectId -- type must already be defined
 *	 rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
 *	 resultType -- defer this, since it must be determined from
 *				   the pg_procedure catalog
 *	 commutatorObjectId -- if this is NULL, enter ObjectId=0
 *					  else if this already exists, enter its ObjectId
 *					  else if this does not yet exist, and is not
 *						the same as the main operatorName, then create
 *						a shell and enter the new ObjectId
 *					  else if this does not exist but IS the same
 *						name & types as the main operator, set the ObjectId=0.
 *						(We are creating a self-commutating operator.)
 *						The link will be fixed later by OperatorUpd.
 *	 negatorObjectId   -- same as for commutatorObjectId
 *	 leftSortObjectId  -- same as for commutatorObjectId
 *	 rightSortObjectId -- same as for commutatorObjectId
 *	 operatorProcedure -- must access the pg_procedure catalog to get the
 *				   ObjectId of the procedure that actually does the operator
 *				   actions this is required.  Do a lookup to find out the
 *				   return type of the procedure
 *	 restrictionProcedure -- must access the pg_procedure catalog to get
 *				   the ObjectId but this is optional
 *	 joinProcedure -- same as restrictionProcedure
 * now either insert or replace the operator into the pg_operator catalog
 * if the operator shell is being filled in
 *	 access the catalog in order to get a valid buffer
 *	 create a tuple using ModifyHeapTuple
 *	 get the t_self from the modified tuple and call RelationReplaceHeapTuple
 * else if a new operator is being created
 *	 create a tuple using heap_formtuple
 *	 call simple_heap_insert
 */
void
OperatorCreate(const char *operatorName,
			   Oid operatorNamespace,
			   Oid leftTypeId,
			   Oid rightTypeId,
			   List *procedureName,
			   List *commutatorName,
			   List *negatorName,
			   List *restrictionName,
			   List *joinName,
			   bool canHash,
			   List *leftSortName,
			   List *rightSortName,
			   List *ltCompareName,
			   List *gtCompareName)
{
	Relation	pg_operator_desc;
	HeapTuple	tup;
	char		nulls[Natts_pg_operator];
	char		replaces[Natts_pg_operator];
	Datum		values[Natts_pg_operator];
	Oid			operatorObjectId;
	bool		operatorAlreadyDefined;
	Oid			procOid;
	Oid			operResultType;
	Oid			commutatorId,
				negatorId,
				leftSortId,
				rightSortId,
				ltCompareId,
				gtCompareId,
				restOid,
				joinOid;
	bool		selfCommutator = false;
	Oid			typeId[FUNC_MAX_ARGS];
	int			nargs;
	NameData	oname;
	TupleDesc	tupDesc;
	int			i;

	/*
	 * Sanity checks
	 */
	if (!validOperatorName(operatorName))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_NAME),
				 errmsg("\"%s\" is not a valid operator name",
						operatorName)));

	if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
		errmsg("at least one of leftarg or rightarg must be specified")));

	if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
	{
		/* If it's not a binary op, these things mustn't be set: */
		if (commutatorName)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				  errmsg("only binary operators can have commutators")));
		if (joinName)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
			 errmsg("only binary operators can have join selectivity")));
		if (canHash)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("only binary operators can hash")));
		if (leftSortName || rightSortName || ltCompareName || gtCompareName)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("only binary operators can merge join")));
	}

	operatorObjectId = OperatorGet(operatorName,
								   operatorNamespace,
								   leftTypeId,
								   rightTypeId,
								   &operatorAlreadyDefined);

	if (operatorAlreadyDefined)
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_FUNCTION),
				 errmsg("operator %s already exists",
						operatorName)));

	/*
	 * At this point, if operatorObjectId is not InvalidOid then we are
	 * filling in a previously-created shell.
	 */

	/*
	 * Look up registered procedures -- find the return type of
	 * procedureName to place in "result" field. Do this before shells are
	 * created so we don't have to worry about deleting them later.
	 */
	MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
	if (!OidIsValid(leftTypeId))
	{
		typeId[0] = rightTypeId;
		nargs = 1;
	}
	else if (!OidIsValid(rightTypeId))
	{
		typeId[0] = leftTypeId;
		nargs = 1;
	}
	else
	{
		typeId[0] = leftTypeId;
		typeId[1] = rightTypeId;
		nargs = 2;
	}
	procOid = LookupFuncName(procedureName, nargs, typeId, false);
	operResultType = get_func_rettype(procOid);

	/*
	 * find restriction estimator
	 */
	if (restrictionName)
	{
		MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
		typeId[0] = INTERNALOID;	/* Query */
		typeId[1] = OIDOID;		/* operator OID */
		typeId[2] = INTERNALOID;	/* args list */
		typeId[3] = INT4OID;	/* varRelid */

		restOid = LookupFuncName(restrictionName, 4, typeId, false);
	}
	else
		restOid = InvalidOid;

	/*
	 * find join estimator
	 */
	if (joinName)
	{
		MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
		typeId[0] = INTERNALOID;	/* Query */
		typeId[1] = OIDOID;		/* operator OID */
		typeId[2] = INTERNALOID;	/* args list */
		typeId[3] = INT2OID;	/* jointype */

		joinOid = LookupFuncName(joinName, 4, typeId, false);
	}
	else
		joinOid = InvalidOid;

	/*
	 * set up values in the operator tuple
	 */

	for (i = 0; i < Natts_pg_operator; ++i)
	{
		values[i] = (Datum) NULL;
		replaces[i] = 'r';
		nulls[i] = ' ';
	}

	i = 0;
	namestrcpy(&oname, operatorName);
	values[i++] = NameGetDatum(&oname); /* oprname */
	values[i++] = ObjectIdGetDatum(operatorNamespace);	/* oprnamespace */
	values[i++] = Int32GetDatum(GetUserId());	/* oprowner */
	values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');	/* oprkind */
	values[i++] = BoolGetDatum(canHash);		/* oprcanhash */
	values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
	values[i++] = ObjectIdGetDatum(rightTypeId);		/* oprright */
	values[i++] = ObjectIdGetDatum(operResultType);		/* oprresult */

	/*
	 * Set up the other operators.	If they do not currently exist, create
	 * shells in order to get ObjectId's.
	 */

	if (commutatorName)
	{
		/* commutator has reversed arg types */
		commutatorId = get_other_operator(commutatorName,
										  rightTypeId, leftTypeId,
										  operatorName, operatorNamespace,
										  leftTypeId, rightTypeId,
										  true);

		/*
		 * self-linkage to this operator; will fix below. Note that only
		 * self-linkage for commutation makes sense.
		 */
		if (!OidIsValid(commutatorId))
			selfCommutator = true;
	}
	else
		commutatorId = InvalidOid;
	values[i++] = ObjectIdGetDatum(commutatorId);		/* oprcom */

	if (negatorName)
	{
		/* negator has same arg types */
		negatorId = get_other_operator(negatorName,
									   leftTypeId, rightTypeId,
									   operatorName, operatorNamespace,
									   leftTypeId, rightTypeId,
									   false);
	}
	else
		negatorId = InvalidOid;
	values[i++] = ObjectIdGetDatum(negatorId);	/* oprnegate */

	if (leftSortName)
	{
		/* left sort op takes left-side data type */
		leftSortId = get_other_operator(leftSortName,
										leftTypeId, leftTypeId,
										operatorName, operatorNamespace,
										leftTypeId, rightTypeId,
										false);
	}
	else
		leftSortId = InvalidOid;
	values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */

	if (rightSortName)
	{
		/* right sort op takes right-side data type */
		rightSortId = get_other_operator(rightSortName,
										 rightTypeId, rightTypeId,
										 operatorName, operatorNamespace,
										 leftTypeId, rightTypeId,
										 false);
	}
	else
		rightSortId = InvalidOid;
	values[i++] = ObjectIdGetDatum(rightSortId);		/* oprrsortop */

	if (ltCompareName)
	{
		/* comparator has same arg types */
		ltCompareId = get_other_operator(ltCompareName,
										 leftTypeId, rightTypeId,
										 operatorName, operatorNamespace,
										 leftTypeId, rightTypeId,
										 false);
	}
	else
		ltCompareId = InvalidOid;
	values[i++] = ObjectIdGetDatum(ltCompareId);		/* oprltcmpop */

	if (gtCompareName)
	{
		/* comparator has same arg types */
		gtCompareId = get_other_operator(gtCompareName,
										 leftTypeId, rightTypeId,
										 operatorName, operatorNamespace,
										 leftTypeId, rightTypeId,
										 false);
	}
	else
		gtCompareId = InvalidOid;
	values[i++] = ObjectIdGetDatum(gtCompareId);		/* oprgtcmpop */

	values[i++] = ObjectIdGetDatum(procOid);	/* oprcode */
	values[i++] = ObjectIdGetDatum(restOid);	/* oprrest */
	values[i++] = ObjectIdGetDatum(joinOid);	/* oprjoin */

	pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);

	/*
	 * If we are adding to an operator shell, update; else insert
	 */
	if (operatorObjectId)
	{
		tup = SearchSysCacheCopy(OPEROID,
								 ObjectIdGetDatum(operatorObjectId),
								 0, 0, 0);
		if (!HeapTupleIsValid(tup))
			elog(ERROR, "cache lookup failed for operator %u",
				 operatorObjectId);

		tup = heap_modifytuple(tup,
							   pg_operator_desc,
							   values,
							   nulls,
							   replaces);

		simple_heap_update(pg_operator_desc, &tup->t_self, tup);
	}
	else
	{
		tupDesc = pg_operator_desc->rd_att;
		tup = heap_formtuple(tupDesc, values, nulls);

		operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
	}

	/* Must update the indexes in either case */
	CatalogUpdateIndexes(pg_operator_desc, tup);

	/* Add dependencies for the entry */
	makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc));

	heap_close(pg_operator_desc, RowExclusiveLock);

	/*
	 * If a commutator and/or negator link is provided, update the other
	 * operator(s) to point at this one, if they don't already have a
	 * link. This supports an alternate style of operator definition
	 * wherein the user first defines one operator without giving negator
	 * or commutator, then defines the other operator of the pair with the
	 * proper commutator or negator attribute.	That style doesn't require
	 * creation of a shell, and it's the only style that worked right
	 * before Postgres version 6.5. This code also takes care of the
	 * situation where the new operator is its own commutator.
	 */
	if (selfCommutator)
		commutatorId = operatorObjectId;

	if (OidIsValid(commutatorId) || OidIsValid(negatorId))
		OperatorUpd(operatorObjectId, commutatorId, negatorId);
}
コード例 #14
0
ファイル: pg_operator.c プロジェクト: sunyangkobe/cscd43
/*
 * OperatorShellMake
 *		Make a "shell" entry for a not-yet-existing operator.
 */
static Oid
OperatorShellMake(const char *operatorName,
				  Oid operatorNamespace,
				  Oid leftTypeId,
				  Oid rightTypeId)
{
	Relation	pg_operator_desc;
	Oid			operatorObjectId;
	int			i;
	HeapTuple	tup;
	Datum		values[Natts_pg_operator];
	char		nulls[Natts_pg_operator];
	NameData	oname;
	TupleDesc	tupDesc;

	/*
	 * validate operator name
	 */
	if (!validOperatorName(operatorName))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_NAME),
				 errmsg("\"%s\" is not a valid operator name",
						operatorName)));

	/*
	 * initialize our *nulls and *values arrays
	 */
	for (i = 0; i < Natts_pg_operator; ++i)
	{
		nulls[i] = ' ';
		values[i] = (Datum) NULL;		/* redundant, but safe */
	}

	/*
	 * initialize values[] with the operator name and input data types.
	 * Note that oprcode is set to InvalidOid, indicating it's a shell.
	 */
	i = 0;
	namestrcpy(&oname, operatorName);
	values[i++] = NameGetDatum(&oname); /* oprname */
	values[i++] = ObjectIdGetDatum(operatorNamespace);	/* oprnamespace */
	values[i++] = Int32GetDatum(GetUserId());	/* oprowner */
	values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');	/* oprkind */
	values[i++] = BoolGetDatum(false);	/* oprcanhash */
	values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
	values[i++] = ObjectIdGetDatum(rightTypeId);		/* oprright */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */
	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */

	/*
	 * open pg_operator
	 */
	pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
	tupDesc = pg_operator_desc->rd_att;

	/*
	 * create a new operator tuple
	 */
	tup = heap_formtuple(tupDesc, values, nulls);

	/*
	 * insert our "shell" operator tuple
	 */
	operatorObjectId = simple_heap_insert(pg_operator_desc, tup);

	CatalogUpdateIndexes(pg_operator_desc, tup);

	/* Add dependencies for the entry */
	makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc));

	heap_freetuple(tup);

	/*
	 * close the operator relation and return the oid.
	 */
	heap_close(pg_operator_desc, RowExclusiveLock);

	return operatorObjectId;
}
コード例 #15
0
ファイル: shooting_star.c プロジェクト: CCheng1231/pgrouting
static int compute_shortest_path_shooting_star(char* sql, int source_edge_id, 
				       int target_edge_id, bool directed, 
				       bool has_reverse_cost, 
				       path_element_t **path, int *path_count) 
{
  
  int SPIcode;
  void *SPIplan;
  Portal SPIportal;
  bool moredata = TRUE;
  int ntuples;
  edge_shooting_star_t *edges = NULL;
  int total_tuples = 0;
  
//  int v_max_id=0;
//  int v_min_id=INT_MAX;  
  int e_max_id=0;
  int e_min_id=INT_MAX;  
    
  edge_shooting_star_columns_t edge_columns = {id: -1, source: -1, target: -1, 
				       cost: -1, reverse_cost: -1, 
				       s_x: -1, s_y: -1, t_x: -1, t_y: -1,
				       to_cost: -1, rule: -1};
  char *err_msg;
  int ret = -1;
  register int z, t;
  
  int s_count=0;
  int t_count=0;
  
  DBG("start shortest_path_shooting_star\n");
        
  SPIcode = SPI_connect();
  if (SPIcode  != SPI_OK_CONNECT)
    {
      elog(ERROR, "shortest_path_shooting_star: couldn't open a connection to SPI");
      return -1;
    }

  SPIplan = SPI_prepare(sql, 0, NULL);
  if (SPIplan  == NULL)
    {
      elog(ERROR, "shortest_path_shooting_star: couldn't create query plan via SPI");
      return -1;
    }

  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) 
    {
      elog(ERROR, "shortest_path_shooting_star: SPI_cursor_open('%s') returns NULL", 
	   sql);
      return -1;
    }

  while (moredata == TRUE)
    {
      SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);

      if (edge_columns.id == -1) 
        {
	  if (fetch_edge_shooting_star_columns(SPI_tuptable, &edge_columns, 
				       has_reverse_cost) == -1)
	    return finish(SPIcode, ret);
        }
	
	//DBG("***%i***", ret);

      ntuples = SPI_processed;
      total_tuples += ntuples;

      if (!edges)
	edges = palloc(total_tuples * sizeof(edge_shooting_star_t));
      else
	edges = repalloc(edges, total_tuples * sizeof(edge_shooting_star_t));

      if (edges == NULL) 
        {
	  elog(ERROR, "Out of memory");
	  return finish(SPIcode, ret);
        }

      if (ntuples > 0) 
        {
	  int t;
	  SPITupleTable *tuptable = SPI_tuptable;
	  TupleDesc tupdesc = SPI_tuptable->tupdesc;
	  
	  for (t = 0; t < ntuples; t++) 
            {
	      HeapTuple tuple = tuptable->vals[t];
	      fetch_edge_shooting_star(&tuple, &tupdesc, &edge_columns, 
			       &edges[total_tuples - ntuples + t]);
            }
	  SPI_freetuptable(tuptable);
        } 
      else 
        {
	  moredata = FALSE;
        }
    }
    
      
  DBG("Total %i tuples", total_tuples);

    

  for(z=0; z<total_tuples; z++)
  {
    if(edges[z].id<e_min_id)
      e_min_id=edges[z].id;

    if(edges[z].id>e_max_id)
      e_max_id=edges[z].id;

  }

    DBG("E : %i <-> %i", e_min_id, e_max_id);

  for(z=0; z<total_tuples; ++z)
  {

    //check if edges[] contains source and target
    if(edges[z].id == source_edge_id)
      ++s_count;
    if(edges[z].id == target_edge_id)
      ++t_count;


    //edges[z].source-=v_min_id;
    //edges[z].target-=v_min_id;
    
  }
    
  DBG("Total %i tuples", total_tuples);

  if(s_count == 0)
  {
    elog(ERROR, "Start edge was not found.");
    return -1;
  }
	      
  if(t_count == 0)
  {
    elog(ERROR, "Target edge was not found.");
    return -1;
  }
			    
  DBG("Total %i tuples", total_tuples);

  DBG("Calling boost_shooting_star <%i>\n", total_tuples);

  //time_t stime = time(NULL);    

  ret = boost_shooting_star(edges, total_tuples, source_edge_id, 
		    target_edge_id,
		    directed, has_reverse_cost,
		    path, path_count, &err_msg, e_max_id);

  //time_t etime = time(NULL);    

  //DBG("Path was calculated in %f seconds. \n", difftime(etime, stime));

  DBG("SIZE %i\n",*path_count);

  DBG("ret =  %i\n",ret);
  

  if (ret < 0)
    {
      ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), 
        errmsg("Error computing path: %s", err_msg)));
    } 
  return finish(SPIcode, ret);
}


PG_FUNCTION_INFO_V1(shortest_path_shooting_star);
Datum
shortest_path_shooting_star(PG_FUNCTION_ARGS)
{
  FuncCallContext     *funcctx;
  int                  call_cntr;
  int                  max_calls;
  TupleDesc            tuple_desc;
  path_element_t      *path = 0;
  
  /* stuff done only on the first call of the function */
  if (SRF_IS_FIRSTCALL())
    {
      MemoryContext   oldcontext;
      int path_count = 0;
      int ret;

      /* create a function context for cross-call persistence */
      funcctx = SRF_FIRSTCALL_INIT();
      
      /* switch to memory context appropriate for multiple function calls */
      oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);


      ret = compute_shortest_path_shooting_star(text2char(PG_GETARG_TEXT_P(0)),
					PG_GETARG_INT32(1),
					PG_GETARG_INT32(2),
					PG_GETARG_BOOL(3),
					PG_GETARG_BOOL(4), 
					&path, &path_count);

#ifdef DEBUG
      DBG("Ret is %i", ret);
      if (ret >= 0) 
        {
	  int i;
	  for (i = 0; i < path_count; i++) 
            {
	      DBG("Step # %i vertex_id  %i ", i, path[i].vertex_id);
	      DBG("        edge_id    %i ", path[i].edge_id);
	      DBG("        cost       %f ", path[i].cost);
            }
        }
#endif

      /* total number of tuples to be returned */
      DBG("Conting tuples number\n");
      funcctx->max_calls = path_count;
      funcctx->user_fctx = path;
      
      DBG("Path count %i", path_count);
      
      funcctx->tuple_desc = 
	BlessTupleDesc(RelationNameGetTupleDesc("pgr_costResult"));

      MemoryContextSwitchTo(oldcontext);
    }

  /* stuff done on every call of the function */

  funcctx = SRF_PERCALL_SETUP();
  
  call_cntr = funcctx->call_cntr;
  max_calls = funcctx->max_calls;
  tuple_desc = funcctx->tuple_desc;
  path = (path_element_t*) funcctx->user_fctx;
  
  DBG("Trying to allocate some memory\n");

  if (call_cntr < max_calls)    /* do when there is more left to send */
    {
      HeapTuple    tuple;
      Datum        result;
      Datum *values;
      char* nulls;
      
      values = palloc(4 * sizeof(Datum));
      nulls = palloc(4 * sizeof(char));
  
      values[0] = Int32GetDatum(call_cntr);
      nulls[0] = ' ';
      values[1] = Int32GetDatum(path[call_cntr].vertex_id);
      nulls[1] = ' ';
      values[2] = Int32GetDatum(path[call_cntr].edge_id);
      nulls[2] = ' ';
      values[3] = Float8GetDatum(path[call_cntr].cost);
      nulls[3] = ' ';
  
      tuple = heap_formtuple(tuple_desc, values, nulls);
  
      /* make the tuple into a datum */
      result = HeapTupleGetDatum(tuple);
  
      /* clean up (this is not really necessary) */
      pfree(values);
      pfree(nulls);
      
      SRF_RETURN_NEXT(funcctx, result);
    }
  else    /* do when there is no more left */
    {
      if (path) free(path);
      SRF_RETURN_DONE(funcctx);
    }
}
コード例 #16
0
ファイル: alpha.c プロジェクト: mrdapotts/pgrouting
static int compute_alpha_shape(char* sql, vertex_t **res, int *res_count)
{

    int SPIcode;
    void *SPIplan;
    Portal SPIportal;
    bool moredata = TRUE;
    int ntuples;
    vertex_t *vertices = NULL;
    int total_tuples = 0;
    vertex_columns_t vertex_columns = {.id= -1, .x= -1, .y= -1};
    char *err_msg;
    int ret = -1;

    DBG("start alpha_shape\n");

    SPIcode = SPI_connect();
    if (SPIcode  != SPI_OK_CONNECT)
    {
        elog(ERROR, "alpha_shape: couldn't open a connection to SPI");
        return -1;
    }

    SPIplan = SPI_prepare(sql, 0, NULL);
    if (SPIplan  == NULL)
    {
        elog(ERROR, "alpha_shape: couldn't create query plan via SPI");
        return -1;
    }

    if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL)
    {
        elog(ERROR, "alpha_shape: SPI_cursor_open('%s') returns NULL", sql);
        return -1;
    }

    while (moredata == TRUE)
    {
        SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);

        if (vertex_columns.id == -1)
        {
            if (fetch_vertices_columns(SPI_tuptable, &vertex_columns) == -1)
                return finish(SPIcode, ret);
        }

        ntuples = SPI_processed;
        total_tuples += ntuples;
        if (!vertices)
            vertices = palloc(total_tuples * sizeof(vertex_t));
        else
            vertices = repalloc(vertices, total_tuples * sizeof(vertex_t));

        if (vertices == NULL)
        {
            elog(ERROR, "Out of memory");
            return finish(SPIcode, ret);
        }

        if (ntuples > 0)
        {
            int t;
            SPITupleTable *tuptable = SPI_tuptable;
            TupleDesc tupdesc = SPI_tuptable->tupdesc;

            for (t = 0; t < ntuples; t++)
            {
                HeapTuple tuple = tuptable->vals[t];
                fetch_vertex(&tuple, &tupdesc, &vertex_columns,
                             &vertices[total_tuples - ntuples + t]);
            }
            SPI_freetuptable(tuptable);
        }
        else
        {
            moredata = FALSE;
        }
    }


    // if (total_tuples < 2) //this was the buggy code of the pgrouting project.
    // TODO: report this as a bug to the pgrouting project
    // the CGAL alpha-shape function crashes if called with less than three points!!!

    if (total_tuples == 0) {
        elog(ERROR, "Distance is too short. no vertex for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
    }
    if (total_tuples == 1) {
        elog(ERROR, "Distance is too short. only 1 vertex for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
    }
    if (total_tuples == 2) {
        elog(ERROR, "Distance is too short. only 2 vertices for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
    }
    if (total_tuples < 3)
    {
        // elog(ERROR, "Distance is too short ....");
        return finish(SPIcode, ret);
    }

    DBG("Calling CGAL alpha-shape\n");

    profstop("extract", prof_extract);
    profstart(prof_alpha);

    ret = alpha_shape(vertices, total_tuples, res, res_count, &err_msg);

    profstop("alpha", prof_alpha);
    profstart(prof_store);

    if (ret < 0)
    {
        //elog(ERROR, "Error computing shape: %s", err_msg);
        ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing shape: %s", err_msg)));
    }

    return finish(SPIcode, ret);
}

PG_FUNCTION_INFO_V1(alphashape);

Datum alphashape(PG_FUNCTION_ARGS)
{
    FuncCallContext      *funcctx;
    int                  call_cntr;
    int                  max_calls;
    TupleDesc            tuple_desc;
    vertex_t     *res = 0;

    /* stuff done only on the first call of the function */
    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext   oldcontext;
        int res_count;
        int ret;

        // XXX profiling messages are not thread safe
        profstart(prof_total);
        profstart(prof_extract);

        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();

        /* switch to memory context appropriate for multiple function calls */
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        ret = compute_alpha_shape(text2char(PG_GETARG_TEXT_P(0)),
                                  &res, &res_count);

        /* total number of tuples to be returned */
        DBG("Conting tuples number\n");
        funcctx->max_calls = res_count;
        funcctx->user_fctx = res;

        DBG("Total count %i", res_count);

        if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));

        funcctx->tuple_desc = BlessTupleDesc(tuple_desc);

        MemoryContextSwitchTo(oldcontext);
    }

    /* stuff done on every call of the function */
    DBG("Strange stuff doing\n");
    funcctx = SRF_PERCALL_SETUP();

    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    tuple_desc = funcctx->tuple_desc;
    res = (vertex_t*) funcctx->user_fctx;

    DBG("Trying to allocate some memory\n");

    if (call_cntr < max_calls)    /* do when there is more left to send */
    {
        HeapTuple    tuple;
        Datum        result;
        Datum *values;
        char* nulls;

        /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one

        values = palloc(3 * sizeof(Datum));
        nulls = palloc(3 * sizeof(char));

        values[0] = call_cntr;
        nulls[0] = ' ';
        values[1] = Float8GetDatum(res[call_cntr].x);
        nulls[1] = ' ';
        values[2] = Float8GetDatum(res[call_cntr].y);
        nulls[2] = ' ';
        */

        values = palloc(2 * sizeof(Datum));
        nulls = palloc(2 * sizeof(char));

        values[0] = Float8GetDatum(res[call_cntr].x);
        nulls[0] = ' ';
        values[1] = Float8GetDatum(res[call_cntr].y);
        nulls[1] = ' ';

        DBG("Heap making\n");

        tuple = heap_formtuple(tuple_desc, values, nulls);

        DBG("Datum making\n");

        /* make the tuple into a datum */
        result = HeapTupleGetDatum(tuple);

        DBG("Trying to free some memory\n");

        /* clean up (this is not really necessary) */
        pfree(values);
        pfree(nulls);

        SRF_RETURN_NEXT(funcctx, result);
    }
    else    /* do when there is no more left */
    {
        if (res) free(res);
        profstop("store", prof_store);
        profstop("total", prof_total);
#ifdef PROFILE
        elog(NOTICE, "_________");
#endif
        SRF_RETURN_DONE(funcctx);
    }
}
コード例 #17
0
ファイル: xyd_tsp.c プロジェクト: DavidLiuGitHub/pgrouting
Datum
#else  // _MSC_VER
PGDLLEXPORT Datum
#endif
xyd_tsp(PG_FUNCTION_ARGS) {
    FuncCallContext     *funcctx;
    uint32_t              call_cntr;
    uint32_t               max_calls;
    TupleDesc            tuple_desc;

    /**************************************************************************/
    /*                          MODIFY AS NEEDED                              */
    /*                                                                        */
    General_path_element_t  *result_tuples = 0;
    size_t result_count = 0;
    /*                                                                        */
    /**************************************************************************/

    if (SRF_IS_FIRSTCALL()) {
        MemoryContext   oldcontext;
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);


        /**********************************************************************/
        /*                          MODIFY AS NEEDED                          */
        // CREATE OR REPLACE FUNCTION pgr_dijkstra(
        // sql text,
        // start_vid BIGINT,
        // end_vid BIGINT,
        // directed BOOLEAN default true,

        PGR_DBG("Calling process");
        process(
                pgr_text2char(PG_GETARG_TEXT_P(0)),
                PG_GETARG_INT64(1),
                PG_GETARG_INT64(2),
                &result_tuples,
                &result_count);

        /*                                                                    */
        /**********************************************************************/

        funcctx->max_calls = (uint32_t) result_count;
        funcctx->user_fctx = result_tuples;
        if (get_call_result_type(fcinfo, NULL, &tuple_desc)
                != TYPEFUNC_COMPOSITE) {
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                         "that cannot accept type record")));
        }

        funcctx->tuple_desc = tuple_desc;
        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();
    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    tuple_desc = funcctx->tuple_desc;
    result_tuples = (General_path_element_t*) funcctx->user_fctx;

    if (call_cntr < max_calls) {
        HeapTuple    tuple;
        Datum        result;
        Datum        *values;
        char*        nulls;

        /**********************************************************************/
        /*                          MODIFY AS NEEDED                          */
        // OUT seq INTEGER,
        // OUT node BIGINT,
        // OUT cost FLOAT,
        // OUT agg_cost FLOAT

        values = palloc(4 * sizeof(Datum));
        nulls = palloc(4 * sizeof(char));


        size_t i;
        for (i = 0; i < 4; ++i) {
            nulls[i] = ' ';
        }

        // postgres starts counting from 1
        values[0] = Int32GetDatum(call_cntr + 1);
        values[1] = Int64GetDatum(result_tuples[call_cntr].node);
        values[2] = Float8GetDatum(result_tuples[call_cntr].cost);
        values[3] = Float8GetDatum(result_tuples[call_cntr].agg_cost);
        /**********************************************************************/

        tuple = heap_formtuple(tuple_desc, values, nulls);
        result = HeapTupleGetDatum(tuple);
        SRF_RETURN_NEXT(funcctx, result);
    } else {
        // cleanup
        if (result_tuples) free(result_tuples);

        SRF_RETURN_DONE(funcctx);
    }
}
コード例 #18
0
/*
 * ConversionCreate
 *
 * Add a new tuple to pg_conversion.
 */
Oid
ConversionCreate(const char *conname, Oid connamespace,
				 Oid conowner,
				 int32 conforencoding, int32 contoencoding,
				 Oid conproc, bool def)
{
	int			i;
	Relation	rel;
	TupleDesc	tupDesc;
	HeapTuple	tup;
	char		nulls[Natts_pg_conversion];
	Datum		values[Natts_pg_conversion];
	NameData	cname;
	Oid			oid;
	ObjectAddress myself,
				referenced;

	/* sanity checks */
	if (!conname)
		elog(ERROR, "no conversion name supplied");

	/* make sure there is no existing conversion of same name */
	if (SearchSysCacheExists(CONNAMENSP,
							 PointerGetDatum(conname),
							 ObjectIdGetDatum(connamespace),
							 0, 0))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("conversion \"%s\" already exists", conname)));

	if (def)
	{
		/*
		 * make sure there is no existing default <for encoding><to encoding>
		 * pair in this name space
		 */
		if (FindDefaultConversion(connamespace,
								  conforencoding,
								  contoencoding))
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_OBJECT),
					 errmsg("default conversion for %s to %s already exists",
							pg_encoding_to_char(conforencoding),
							pg_encoding_to_char(contoencoding))));
	}

	/* open pg_conversion */
	rel = heap_open(ConversionRelationId, RowExclusiveLock);
	tupDesc = rel->rd_att;

	/* initialize nulls and values */
	for (i = 0; i < Natts_pg_conversion; i++)
	{
		nulls[i] = ' ';
		values[i] = (Datum) NULL;
	}

	/* form a tuple */
	namestrcpy(&cname, conname);
	values[Anum_pg_conversion_conname - 1] = NameGetDatum(&cname);
	values[Anum_pg_conversion_connamespace - 1] = ObjectIdGetDatum(connamespace);
	values[Anum_pg_conversion_conowner - 1] = ObjectIdGetDatum(conowner);
	values[Anum_pg_conversion_conforencoding - 1] = Int32GetDatum(conforencoding);
	values[Anum_pg_conversion_contoencoding - 1] = Int32GetDatum(contoencoding);
	values[Anum_pg_conversion_conproc - 1] = ObjectIdGetDatum(conproc);
	values[Anum_pg_conversion_condefault - 1] = BoolGetDatum(def);

	tup = heap_formtuple(tupDesc, values, nulls);

	/* insert a new tuple */
	oid = simple_heap_insert(rel, tup);
	Assert(OidIsValid(oid));

	/* update the index if any */
	CatalogUpdateIndexes(rel, tup);

	myself.classId = ConversionRelationId;
	myself.objectId = HeapTupleGetOid(tup);
	myself.objectSubId = 0;

	/* create dependency on conversion procedure */
	referenced.classId = ProcedureRelationId;
	referenced.objectId = conproc;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* create dependency on owner */
	recordDependencyOnOwner(ConversionRelationId, HeapTupleGetOid(tup),
							conowner);

	heap_freetuple(tup);
	heap_close(rel, RowExclusiveLock);

	return oid;
}
コード例 #19
0
Datum
#else  // _MSC_VER
PGDLLEXPORT Datum
#endif
driving_many_to_dist(PG_FUNCTION_ARGS) {
  FuncCallContext     *funcctx;
  int                  call_cntr;
  int                  max_calls;
  TupleDesc            tuple_desc;
  pgr_path_element3_t  *ret_path = 0;

  /* stuff done only on the first call of the function */
  if (SRF_IS_FIRSTCALL()) {
      MemoryContext   oldcontext;
      int path_count = 0;

      /* create a function context for cross-call persistence */
      funcctx = SRF_FIRSTCALL_INIT();

      /* switch to memory context appropriate for multiple function calls */
      oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

      int64_t* sourcesArr;
      int num;

      sourcesArr = (int64_t*) pgr_get_bigIntArray(&num, PG_GETARG_ARRAYTYPE_P(1));
      PGR_DBG("sourcesArr size %d ", num);

      PGR_DBG("Calling driving_many_to_dist_driver");
      driving_many_to_dist_driver(
               pgr_text2char(PG_GETARG_TEXT_P(0)),  // sql
               sourcesArr, num,                     // array of sources
               PG_GETARG_FLOAT8(2),                 // distance
               PG_GETARG_BOOL(3),                   // directed
               PG_GETARG_BOOL(4),                   // equicost
               PG_GETARG_BOOL(5),                   // has_rcost
               &ret_path, &path_count);

      free(sourcesArr);

      /* total number of tuples to be returned */
      funcctx->max_calls = path_count;
      funcctx->user_fctx = ret_path;
      if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));

      funcctx->tuple_desc = tuple_desc;

      MemoryContextSwitchTo(oldcontext);
  }

  /* stuff done on every call of the function */
  funcctx = SRF_PERCALL_SETUP();

  call_cntr = funcctx->call_cntr;
  max_calls = funcctx->max_calls;
  tuple_desc = funcctx->tuple_desc;
  ret_path = (pgr_path_element3_t*) funcctx->user_fctx;

  /* do when there is more left to send */
  if (call_cntr < max_calls) {
      HeapTuple    tuple;
      Datum        result;
      Datum *values;
      char* nulls;

      values = palloc(6 * sizeof(Datum));
      nulls = palloc(6 * sizeof(char));
      // id, start_v, node, edge, cost, tot_cost
      values[0] = Int32GetDatum(call_cntr + 1);
      nulls[0] = ' ';
      values[1] = Int64GetDatum(ret_path[call_cntr].from);
      nulls[1] = ' ';
      values[2] = Int64GetDatum(ret_path[call_cntr].vertex);
      nulls[2] = ' ';
      values[3] = Int64GetDatum(ret_path[call_cntr].edge);
      nulls[3] = ' ';
      values[4] = Float8GetDatum(ret_path[call_cntr].cost);
      nulls[4] = ' ';
      values[5] = Float8GetDatum(ret_path[call_cntr].tot_cost);
      nulls[5] = ' ';

      tuple = heap_formtuple(tuple_desc, values, nulls);

      /* make the tuple into a datum */
      result = HeapTupleGetDatum(tuple);

      /* clean up (this is not really necessary) */
      pfree(values);
      pfree(nulls);

      SRF_RETURN_NEXT(funcctx, result);
  } else {
      /* do when there is no more left */
      if (ret_path) free(ret_path);
      SRF_RETURN_DONE(funcctx);
  }
}
コード例 #20
0
ファイル: inv_api.c プロジェクト: berkeley-cs186/course-fa07
int
inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
{
	int			nwritten = 0;
	int			n;
	int			off;
	int			len;
	int32		pageno = (int32) (obj_desc->offset / LOBLKSIZE);
	ScanKeyData skey[2];
	IndexScanDesc sd;
	HeapTuple	oldtuple;
	Form_pg_largeobject olddata;
	bool		neednextpage;
	bytea	   *datafield;
	bool		pfreeit;
	struct
	{
		bytea		hdr;
		char		data[LOBLKSIZE];
	}			workbuf;
	char	   *workb = VARATT_DATA(&workbuf.hdr);
	HeapTuple	newtup;
	Datum		values[Natts_pg_largeobject];
	char		nulls[Natts_pg_largeobject];
	char		replace[Natts_pg_largeobject];
	CatalogIndexState indstate;

	Assert(PointerIsValid(obj_desc));
	Assert(buf != NULL);

	if (nbytes <= 0)
		return 0;

	open_lo_relation();

	indstate = CatalogOpenIndexes(lo_heap_r);

	ScanKeyInit(&skey[0],
				Anum_pg_largeobject_loid,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(obj_desc->id));

	ScanKeyInit(&skey[1],
				Anum_pg_largeobject_pageno,
				BTGreaterEqualStrategyNumber, F_INT4GE,
				Int32GetDatum(pageno));

	sd = index_beginscan(lo_heap_r, lo_index_r,
						 SnapshotNow, 2, skey);

	oldtuple = NULL;
	olddata = NULL;
	neednextpage = true;

	while (nwritten < nbytes)
	{
		/*
		 * If possible, get next pre-existing page of the LO.  We assume
		 * the indexscan will deliver these in order --- but there may be
		 * holes.
		 */
		if (neednextpage)
		{
			if ((oldtuple = index_getnext(sd, ForwardScanDirection)) != NULL)
			{
				olddata = (Form_pg_largeobject) GETSTRUCT(oldtuple);
				Assert(olddata->pageno >= pageno);
			}
			neednextpage = false;
		}

		/*
		 * If we have a pre-existing page, see if it is the page we want
		 * to write, or a later one.
		 */
		if (olddata != NULL && olddata->pageno == pageno)
		{
			/*
			 * Update an existing page with fresh data.
			 *
			 * First, load old data into workbuf
			 */
			datafield = &(olddata->data);
			pfreeit = false;
			if (VARATT_IS_EXTENDED(datafield))
			{
				datafield = (bytea *)
					heap_tuple_untoast_attr((varattrib *) datafield);
				pfreeit = true;
			}
			len = getbytealen(datafield);
			Assert(len <= LOBLKSIZE);
			memcpy(workb, VARDATA(datafield), len);
			if (pfreeit)
				pfree(datafield);

			/*
			 * Fill any hole
			 */
			off = (int) (obj_desc->offset % LOBLKSIZE);
			if (off > len)
				MemSet(workb + len, 0, off - len);

			/*
			 * Insert appropriate portion of new data
			 */
			n = LOBLKSIZE - off;
			n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
			memcpy(workb + off, buf + nwritten, n);
			nwritten += n;
			obj_desc->offset += n;
			off += n;
			/* compute valid length of new page */
			len = (len >= off) ? len : off;
			VARATT_SIZEP(&workbuf.hdr) = len + VARHDRSZ;

			/*
			 * Form and insert updated tuple
			 */
			memset(values, 0, sizeof(values));
			memset(nulls, ' ', sizeof(nulls));
			memset(replace, ' ', sizeof(replace));
			values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
			replace[Anum_pg_largeobject_data - 1] = 'r';
			newtup = heap_modifytuple(oldtuple, lo_heap_r,
									  values, nulls, replace);
			simple_heap_update(lo_heap_r, &newtup->t_self, newtup);
			CatalogIndexInsert(indstate, newtup);
			heap_freetuple(newtup);

			/*
			 * We're done with this old page.
			 */
			oldtuple = NULL;
			olddata = NULL;
			neednextpage = true;
		}
		else
		{
			/*
			 * Write a brand new page.
			 *
			 * First, fill any hole
			 */
			off = (int) (obj_desc->offset % LOBLKSIZE);
			if (off > 0)
				MemSet(workb, 0, off);

			/*
			 * Insert appropriate portion of new data
			 */
			n = LOBLKSIZE - off;
			n = (n <= (nbytes - nwritten)) ? n : (nbytes - nwritten);
			memcpy(workb + off, buf + nwritten, n);
			nwritten += n;
			obj_desc->offset += n;
			/* compute valid length of new page */
			len = off + n;
			VARATT_SIZEP(&workbuf.hdr) = len + VARHDRSZ;

			/*
			 * Form and insert updated tuple
			 */
			memset(values, 0, sizeof(values));
			memset(nulls, ' ', sizeof(nulls));
			values[Anum_pg_largeobject_loid - 1] = ObjectIdGetDatum(obj_desc->id);
			values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
			values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
			newtup = heap_formtuple(lo_heap_r->rd_att, values, nulls);
			simple_heap_insert(lo_heap_r, newtup);
			CatalogIndexInsert(indstate, newtup);
			heap_freetuple(newtup);
		}
		pageno++;
	}

	index_endscan(sd);

	CatalogCloseIndexes(indstate);

	/*
	 * Advance command counter so that my tuple updates will be seen by
	 * later large-object operations in this transaction.
	 */
	CommandCounterIncrement();

	return nwritten;
}
コード例 #21
0
ファイル: hstore_op.c プロジェクト: AnLingm/gpdb
Datum
each(PG_FUNCTION_ARGS)
{
	FuncCallContext *funcctx;
	AKStore    *st;

	if (SRF_IS_FIRSTCALL())
	{
		TupleDesc	tupdesc;
		MemoryContext oldcontext;
		HStore	   *hs = PG_GETARG_HS(0);

		funcctx = SRF_FIRSTCALL_INIT();
		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
		st = (AKStore *) palloc(sizeof(AKStore));
		st->i = 0;
		st->hs = (HStore *) palloc(VARSIZE(hs));
		memcpy(st->hs, hs, VARSIZE(hs));
		funcctx->user_fctx = (void *) st;

		/* Build a tuple descriptor for our result type */
		if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
			elog(ERROR, "return type must be a row type");

		funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);

		MemoryContextSwitchTo(oldcontext);
		PG_FREE_IF_COPY(hs, 0);
	}

	funcctx = SRF_PERCALL_SETUP();
	st = (AKStore *) funcctx->user_fctx;

	if (st->i < st->hs->size)
	{
		HEntry	   *ptr = &(ARRPTR(st->hs)[st->i]);
		Datum		res,
					dvalues[2];
		char		nulls[] = {' ', ' '};
		text	   *item;
		HeapTuple	tuple;

		item = (text *) palloc(VARHDRSZ + ptr->keylen);
		SET_VARSIZE(item, VARHDRSZ + ptr->keylen);
		memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
		dvalues[0] = PointerGetDatum(item);

		if (ptr->valisnull)
		{
			dvalues[1] = (Datum) 0;
			nulls[1] = 'n';
		}
		else
		{
			int			vallen = ptr->vallen;

			item = (text *) palloc(VARHDRSZ + vallen);
			SET_VARSIZE(item, VARHDRSZ + vallen);
			memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen);
			dvalues[1] = PointerGetDatum(item);
		}
		st->i++;

		tuple = heap_formtuple(funcctx->attinmeta->tupdesc, dvalues, nulls);
		res = HeapTupleGetDatum(tuple);

		pfree(DatumGetPointer(dvalues[0]));
		if (nulls[1] != 'n')
			pfree(DatumGetPointer(dvalues[1]));

		SRF_RETURN_NEXT(funcctx, res);
	}

	pfree(st->hs);
	pfree(st);

	SRF_RETURN_DONE(funcctx);
}
コード例 #22
0
ファイル: cms_topn.c プロジェクト: SufianHassan/cms_topn
/*
 * topn is a user-facing UDF which returns the top items and their frequencies.
 * It first gets the top-n structure and converts it into the ordered array of
 * FrequentTopnItem which keeps Datums and the frequencies in the first call.
 * Then, it returns an item and its frequency according to call counter. This
 * function requires a parameter for the type because PostgreSQL has strongly
 * typed system and the type of frequent items in returning rows has to be given.
 */
Datum
topn(PG_FUNCTION_ARGS)
{
	FuncCallContext *functionCallContext = NULL;
	TupleDesc tupleDescriptor = NULL;
	Oid returningItemType = get_fn_expr_argtype(fcinfo->flinfo, 1);
	CmsTopn *cmsTopn = NULL;
	ArrayType *topnArray = NULL;
	int topnArrayLength = 0;
	Datum topnItem = 0;
	bool isNull = false;
	ArrayIterator topnIterator = NULL;
	bool hasMoreItem = false;
	int callCounter = 0;
	int maxCallCounter = 0;

	if (SRF_IS_FIRSTCALL())
	{
		MemoryContext oldcontext = NULL;
		Size topnArraySize = 0;
		TypeCacheEntry *itemTypeCacheEntry = NULL;
		int topnIndex = 0;
		Oid itemType = InvalidOid;
		FrequentTopnItem *sortedTopnArray = NULL;
		TupleDesc completeTupleDescriptor = NULL;

		functionCallContext = SRF_FIRSTCALL_INIT();
		if (PG_ARGISNULL(0))
		{
			SRF_RETURN_DONE(functionCallContext);
		}

		cmsTopn = (CmsTopn *)  PG_GETARG_VARLENA_P(0);
		topnArray = TopnArray(cmsTopn);
		topnArrayLength = ARR_DIMS(topnArray)[0];

		/* if there is not any element in the array just return */
		if (topnArrayLength == 0)
		{
			SRF_RETURN_DONE(functionCallContext);
		}

		itemType = ARR_ELEMTYPE(topnArray);
		if (itemType != returningItemType)
		{
			elog(ERROR, "not a proper cms_topn for the result type");
		}

		/* switch to consistent context for multiple calls */
		oldcontext = MemoryContextSwitchTo(functionCallContext->multi_call_memory_ctx);
		itemTypeCacheEntry = lookup_type_cache(itemType, 0);
		functionCallContext->max_calls = topnArrayLength;

		/* create an array to copy top-n items and sort them later */
		topnArraySize = sizeof(FrequentTopnItem) * topnArrayLength;
		sortedTopnArray = palloc0(topnArraySize);

		topnIterator = array_create_iterator(topnArray, 0);
		hasMoreItem = array_iterate(topnIterator, &topnItem, &isNull);
		while (hasMoreItem)
		{
			FrequentTopnItem frequentTopnItem;
			frequentTopnItem.topnItem = topnItem;
			frequentTopnItem.topnItemFrequency =
			        CmsTopnEstimateItemFrequency(cmsTopn, topnItem, itemTypeCacheEntry);
			sortedTopnArray[topnIndex] = frequentTopnItem;

			hasMoreItem = array_iterate(topnIterator, &topnItem, &isNull);
			topnIndex++;
		}

		SortTopnItems(sortedTopnArray, topnArrayLength);
		functionCallContext->user_fctx = sortedTopnArray;

		get_call_result_type(fcinfo, &returningItemType, &tupleDescriptor);
		completeTupleDescriptor = BlessTupleDesc(tupleDescriptor);
		functionCallContext->tuple_desc = completeTupleDescriptor;
		MemoryContextSwitchTo(oldcontext);
	}

	functionCallContext = SRF_PERCALL_SETUP();
	maxCallCounter = functionCallContext->max_calls;
	callCounter = functionCallContext->call_cntr;

	if (callCounter < maxCallCounter)
	{
		Datum *tupleValues = (Datum *) palloc(2 * sizeof(Datum));
		HeapTuple topnItemTuple;
		Datum topnItemDatum = 0;
		char *tupleNulls = (char *) palloc0(2 * sizeof(char));
		FrequentTopnItem *sortedTopnArray = NULL;
		TupleDesc completeTupleDescriptor = NULL;

		sortedTopnArray = (FrequentTopnItem *) functionCallContext->user_fctx;
		tupleValues[0] = sortedTopnArray[callCounter].topnItem;
		tupleValues[1] = sortedTopnArray[callCounter].topnItemFrequency;

		/* non-null attributes are indicated by a ' ' (space) */
		tupleNulls[0] = ' ';
		tupleNulls[1] = ' ';

		completeTupleDescriptor = functionCallContext->tuple_desc;
		topnItemTuple = heap_formtuple(completeTupleDescriptor, tupleValues, tupleNulls);

		topnItemDatum = HeapTupleGetDatum(topnItemTuple);
		SRF_RETURN_NEXT(functionCallContext, topnItemDatum);
	}
	else
	{
		SRF_RETURN_DONE(functionCallContext);
	}
}
コード例 #23
0
ファイル: rowtypes.c プロジェクト: KMU-embedded/mosbench-ext
/*
 * record_in		- input routine for any composite type.
 */
Datum
record_in(PG_FUNCTION_ARGS)
{
	char	   *string = PG_GETARG_CSTRING(0);
	Oid			tupType = PG_GETARG_OID(1);

#ifdef NOT_USED
	int32		typmod = PG_GETARG_INT32(2);
#endif
	HeapTupleHeader result;
	int32		tupTypmod;
	TupleDesc	tupdesc;
	HeapTuple	tuple;
	RecordIOData *my_extra;
	bool		needComma = false;
	int			ncolumns;
	int			i;
	char	   *ptr;
	Datum	   *values;
	char	   *nulls;
	StringInfoData buf;

	/*
	 * Use the passed type unless it's RECORD; we can't support input of
	 * anonymous types, mainly because there's no good way to figure out which
	 * anonymous type is wanted.  Note that for RECORD, what we'll probably
	 * actually get is RECORD's typelem, ie, zero.
	 */
	if (tupType == InvalidOid || tupType == RECORDOID)
		ereport(ERROR,
				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
		   errmsg("input of anonymous composite types is not implemented")));
	tupTypmod = -1;				/* for all non-anonymous types */
	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
	ncolumns = tupdesc->natts;

	/*
	 * We arrange to look up the needed I/O info just once per series of
	 * calls, assuming the record type doesn't change underneath us.
	 */
	my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
	if (my_extra == NULL ||
		my_extra->ncolumns != ncolumns)
	{
		fcinfo->flinfo->fn_extra =
			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
							   sizeof(RecordIOData) - sizeof(ColumnIOData)
							   + ncolumns * sizeof(ColumnIOData));
		my_extra = (RecordIOData *) fcinfo->flinfo->fn_extra;
		my_extra->record_type = InvalidOid;
		my_extra->record_typmod = 0;
	}

	if (my_extra->record_type != tupType ||
		my_extra->record_typmod != tupTypmod)
	{
		MemSet(my_extra, 0,
			   sizeof(RecordIOData) - sizeof(ColumnIOData)
			   + ncolumns * sizeof(ColumnIOData));
		my_extra->record_type = tupType;
		my_extra->record_typmod = tupTypmod;
		my_extra->ncolumns = ncolumns;
	}

	values = (Datum *) palloc(ncolumns * sizeof(Datum));
	nulls = (char *) palloc(ncolumns * sizeof(char));

	/*
	 * Scan the string.  We use "buf" to accumulate the de-quoted data for
	 * each column, which is then fed to the appropriate input converter.
	 */
	ptr = string;
	/* Allow leading whitespace */
	while (*ptr && isspace((unsigned char) *ptr))
		ptr++;
	if (*ptr++ != '(')
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("malformed record literal: \"%s\"", string),
				 errdetail("Missing left parenthesis.")));

	initStringInfo(&buf);

	for (i = 0; i < ncolumns; i++)
	{
		ColumnIOData *column_info = &my_extra->columns[i];
		Oid			column_type = tupdesc->attrs[i]->atttypid;
		char	   *column_data;

		/* Ignore dropped columns in datatype, but fill with nulls */
		if (tupdesc->attrs[i]->attisdropped)
		{
			values[i] = (Datum) 0;
			nulls[i] = 'n';
			continue;
		}

		if (needComma)
		{
			/* Skip comma that separates prior field from this one */
			if (*ptr == ',')
				ptr++;
			else
				/* *ptr must be ')' */
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
						 errmsg("malformed record literal: \"%s\"", string),
						 errdetail("Too few columns.")));
		}

		/* Check for null: completely empty input means null */
		if (*ptr == ',' || *ptr == ')')
		{
			column_data = NULL;
			nulls[i] = 'n';
		}
		else
		{
			/* Extract string for this column */
			bool		inquote = false;

			resetStringInfo(&buf);
			while (inquote || !(*ptr == ',' || *ptr == ')'))
			{
				char		ch = *ptr++;

				if (ch == '\0')
					ereport(ERROR,
							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
							 errmsg("malformed record literal: \"%s\"",
									string),
							 errdetail("Unexpected end of input.")));
				if (ch == '\\')
				{
					if (*ptr == '\0')
						ereport(ERROR,
								(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
								 errmsg("malformed record literal: \"%s\"",
										string),
								 errdetail("Unexpected end of input.")));
					appendStringInfoChar(&buf, *ptr++);
				}
				else if (ch == '\"')
				{
					if (!inquote)
						inquote = true;
					else if (*ptr == '\"')
					{
						/* doubled quote within quote sequence */
						appendStringInfoChar(&buf, *ptr++);
					}
					else
						inquote = false;
				}
				else
					appendStringInfoChar(&buf, ch);
			}

			column_data = buf.data;
			nulls[i] = ' ';
		}

		/*
		 * Convert the column value
		 */
		if (column_info->column_type != column_type)
		{
			getTypeInputInfo(column_type,
							 &column_info->typiofunc,
							 &column_info->typioparam);
			fmgr_info_cxt(column_info->typiofunc, &column_info->proc,
						  fcinfo->flinfo->fn_mcxt);
			column_info->column_type = column_type;
		}

		values[i] = InputFunctionCall(&column_info->proc,
									  column_data,
									  column_info->typioparam,
									  tupdesc->attrs[i]->atttypmod);

		/*
		 * Prep for next column
		 */
		needComma = true;
	}

	if (*ptr++ != ')')
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("malformed record literal: \"%s\"", string),
				 errdetail("Too many columns.")));
	/* Allow trailing whitespace */
	while (*ptr && isspace((unsigned char) *ptr))
		ptr++;
	if (*ptr)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
				 errmsg("malformed record literal: \"%s\"", string),
				 errdetail("Junk after right parenthesis.")));

	tuple = heap_formtuple(tupdesc, values, nulls);

	/*
	 * We cannot return tuple->t_data because heap_formtuple allocates it as
	 * part of a larger chunk, and our caller may expect to be able to pfree
	 * our result.	So must copy the info into a new palloc chunk.
	 */
	result = (HeapTupleHeader) palloc(tuple->t_len);
	memcpy(result, tuple->t_data, tuple->t_len);

	heap_freetuple(tuple);
	pfree(buf.data);
	pfree(values);
	pfree(nulls);
	ReleaseTupleDesc(tupdesc);

	PG_RETURN_HEAPTUPLEHEADER(result);
}
コード例 #24
0
ファイル: pg_proc.c プロジェクト: CraigBryan/PostgresqlFun
/* ----------------------------------------------------------------
 *		ProcedureCreate
 *
 * Note: allParameterTypes, parameterModes, parameterNames are either arrays
 * of the proper types or NULL.  We declare them Datum, not "ArrayType *",
 * to avoid importing array.h into pg_proc.h.
 * ----------------------------------------------------------------
 */
Oid
ProcedureCreate(const char *procedureName,
				Oid procNamespace,
				bool replace,
				bool returnsSet,
				Oid returnType,
				Oid languageObjectId,
				Oid languageValidator,
				const char *prosrc,
				const char *probin,
				bool isAgg,
				bool security_definer,
				bool isStrict,
				char volatility,
				oidvector *parameterTypes,
				Datum allParameterTypes,
				Datum parameterModes,
				Datum parameterNames)
{
	Oid			retval;
	int			parameterCount;
	int			allParamCount;
	Oid		   *allParams;
	bool		genericInParam = false;
	bool		genericOutParam = false;
	bool		internalInParam = false;
	bool		internalOutParam = false;
	Relation	rel;
	HeapTuple	tup;
	HeapTuple	oldtup;
	char		nulls[Natts_pg_proc];
	Datum		values[Natts_pg_proc];
	char		replaces[Natts_pg_proc];
	Oid			relid;
	NameData	procname;
	TupleDesc	tupDesc;
	bool		is_update;
	ObjectAddress myself,
				referenced;
	int			i;

	/*
	 * sanity checks
	 */
	Assert(PointerIsValid(prosrc));
	Assert(PointerIsValid(probin));

	parameterCount = parameterTypes->dim1;
	if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
		ereport(ERROR,
				(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
				 errmsg("functions cannot have more than %d arguments",
						FUNC_MAX_ARGS)));
	/* note: the above is correct, we do NOT count output arguments */

	if (allParameterTypes != PointerGetDatum(NULL))
	{
		/*
		 * We expect the array to be a 1-D OID array; verify that. We don't
		 * need to use deconstruct_array() since the array data is just going
		 * to look like a C array of OID values.
		 */
		allParamCount = ARR_DIMS(DatumGetPointer(allParameterTypes))[0];
		if (ARR_NDIM(DatumGetPointer(allParameterTypes)) != 1 ||
			allParamCount <= 0 ||
			ARR_ELEMTYPE(DatumGetPointer(allParameterTypes)) != OIDOID)
			elog(ERROR, "allParameterTypes is not a 1-D Oid array");
		allParams = (Oid *) ARR_DATA_PTR(DatumGetPointer(allParameterTypes));
		Assert(allParamCount >= parameterCount);
		/* we assume caller got the contents right */
	}
	else
	{
		allParamCount = parameterCount;
		allParams = parameterTypes->values;
	}

	/*
	 * Do not allow return type ANYARRAY or ANYELEMENT unless at least one
	 * input argument is ANYARRAY or ANYELEMENT.  Also, do not allow return
	 * type INTERNAL unless at least one input argument is INTERNAL.
	 */
	for (i = 0; i < parameterCount; i++)
	{
		switch (parameterTypes->values[i])
		{
			case ANYARRAYOID:
			case ANYELEMENTOID:
				genericInParam = true;
				break;
			case INTERNALOID:
				internalInParam = true;
				break;
		}
	}

	if (allParameterTypes != PointerGetDatum(NULL))
	{
		for (i = 0; i < allParamCount; i++)
		{
			/*
			 * We don't bother to distinguish input and output params here, so
			 * if there is, say, just an input INTERNAL param then we will
			 * still set internalOutParam.	This is OK since we don't really
			 * care.
			 */
			switch (allParams[i])
			{
				case ANYARRAYOID:
				case ANYELEMENTOID:
					genericOutParam = true;
					break;
				case INTERNALOID:
					internalOutParam = true;
					break;
			}
		}
	}

	if ((returnType == ANYARRAYOID || returnType == ANYELEMENTOID ||
		 genericOutParam) && !genericInParam)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("cannot determine result data type"),
				 errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));

	if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
				 errmsg("unsafe use of pseudo-type \"internal\""),
				 errdetail("A function returning \"internal\" must have at least one \"internal\" argument.")));

	/*
	 * don't allow functions of complex types that have the same name as
	 * existing attributes of the type
	 */
	if (parameterCount == 1 &&
		OidIsValid(parameterTypes->values[0]) &&
		(relid = typeidTypeRelid(parameterTypes->values[0])) != InvalidOid &&
		get_attnum(relid, procedureName) != InvalidAttrNumber)
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_COLUMN),
				 errmsg("\"%s\" is already an attribute of type %s",
						procedureName,
						format_type_be(parameterTypes->values[0]))));

	/*
	 * All seems OK; prepare the data to be inserted into pg_proc.
	 */

	for (i = 0; i < Natts_pg_proc; ++i)
	{
		nulls[i] = ' ';
		values[i] = (Datum) 0;
		replaces[i] = 'r';
	}

	namestrcpy(&procname, procedureName);
	values[Anum_pg_proc_proname - 1] = NameGetDatum(&procname);
	values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
	values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(GetUserId());
	values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
	values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
	values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
	values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
	values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
	values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
	values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
	values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
	values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
	if (allParameterTypes != PointerGetDatum(NULL))
		values[Anum_pg_proc_proallargtypes - 1] = allParameterTypes;
	else
		nulls[Anum_pg_proc_proallargtypes - 1] = 'n';
	if (parameterModes != PointerGetDatum(NULL))
		values[Anum_pg_proc_proargmodes - 1] = parameterModes;
	else
		nulls[Anum_pg_proc_proargmodes - 1] = 'n';
	if (parameterNames != PointerGetDatum(NULL))
		values[Anum_pg_proc_proargnames - 1] = parameterNames;
	else
		nulls[Anum_pg_proc_proargnames - 1] = 'n';
	values[Anum_pg_proc_prosrc - 1] = DirectFunctionCall1(textin,
													CStringGetDatum(prosrc));
	values[Anum_pg_proc_probin - 1] = DirectFunctionCall1(textin,
													CStringGetDatum(probin));
	/* start out with empty permissions */
	nulls[Anum_pg_proc_proacl - 1] = 'n';

	rel = heap_open(ProcedureRelationId, RowExclusiveLock);
	tupDesc = RelationGetDescr(rel);

	/* Check for pre-existing definition */
	oldtup = SearchSysCache(PROCNAMEARGSNSP,
							PointerGetDatum(procedureName),
							PointerGetDatum(parameterTypes),
							ObjectIdGetDatum(procNamespace),
							0);

	if (HeapTupleIsValid(oldtup))
	{
		/* There is one; okay to replace it? */
		Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);

		if (!replace)
			ereport(ERROR,
					(errcode(ERRCODE_DUPLICATE_FUNCTION),
			errmsg("function \"%s\" already exists with same argument types",
				   procedureName)));
		if (!pg_proc_ownercheck(HeapTupleGetOid(oldtup), GetUserId()))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
						   procedureName);

		/*
		 * Not okay to change the return type of the existing proc, since
		 * existing rules, views, etc may depend on the return type.
		 */
		if (returnType != oldproc->prorettype ||
			returnsSet != oldproc->proretset)
			ereport(ERROR,
					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					 errmsg("cannot change return type of existing function"),
					 errhint("Use DROP FUNCTION first.")));

		/*
		 * If it returns RECORD, check for possible change of record type
		 * implied by OUT parameters
		 */
		if (returnType == RECORDOID)
		{
			TupleDesc	olddesc;
			TupleDesc	newdesc;

			olddesc = build_function_result_tupdesc_t(oldtup);
			newdesc = build_function_result_tupdesc_d(allParameterTypes,
													  parameterModes,
													  parameterNames);
			if (olddesc == NULL && newdesc == NULL)
				 /* ok, both are runtime-defined RECORDs */ ;
			else if (olddesc == NULL || newdesc == NULL ||
					 !equalTupleDescs(olddesc, newdesc))
				ereport(ERROR,
						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
					errmsg("cannot change return type of existing function"),
				errdetail("Row type defined by OUT parameters is different."),
						 errhint("Use DROP FUNCTION first.")));
		}

		/* Can't change aggregate status, either */
		if (oldproc->proisagg != isAgg)
		{
			if (oldproc->proisagg)
				ereport(ERROR,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
						 errmsg("function \"%s\" is an aggregate",
								procedureName)));
			else
				ereport(ERROR,
						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
						 errmsg("function \"%s\" is not an aggregate",
								procedureName)));
		}

		/* do not change existing ownership or permissions, either */
		replaces[Anum_pg_proc_proowner - 1] = ' ';
		replaces[Anum_pg_proc_proacl - 1] = ' ';

		/* Okay, do it... */
		tup = heap_modifytuple(oldtup, tupDesc, values, nulls, replaces);
		simple_heap_update(rel, &tup->t_self, tup);

		ReleaseSysCache(oldtup);
		is_update = true;
	}
	else
	{
		/* Creating a new procedure */
		tup = heap_formtuple(tupDesc, values, nulls);
		simple_heap_insert(rel, tup);
		is_update = false;
	}

	/* Need to update indexes for either the insert or update case */
	CatalogUpdateIndexes(rel, tup);

	retval = HeapTupleGetOid(tup);

	/*
	 * Create dependencies for the new function.  If we are updating an
	 * existing function, first delete any existing pg_depend entries.
	 */
	if (is_update)
	{
		deleteDependencyRecordsFor(ProcedureRelationId, retval);
		deleteSharedDependencyRecordsFor(ProcedureRelationId, retval);
	}

	myself.classId = ProcedureRelationId;
	myself.objectId = retval;
	myself.objectSubId = 0;

	/* dependency on namespace */
	referenced.classId = NamespaceRelationId;
	referenced.objectId = procNamespace;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on implementation language */
	referenced.classId = LanguageRelationId;
	referenced.objectId = languageObjectId;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on return type */
	referenced.classId = TypeRelationId;
	referenced.objectId = returnType;
	referenced.objectSubId = 0;
	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

	/* dependency on parameter types */
	for (i = 0; i < allParamCount; i++)
	{
		referenced.classId = TypeRelationId;
		referenced.objectId = allParams[i];
		referenced.objectSubId = 0;
		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
	}

	/* dependency on owner */
	recordDependencyOnOwner(ProcedureRelationId, retval, GetUserId());

	heap_freetuple(tup);

	heap_close(rel, RowExclusiveLock);

	/* Verify function body */
	if (OidIsValid(languageValidator))
	{
		/* Advance command counter so new tuple can be seen by validator */
		CommandCounterIncrement();
		OidFunctionCall1(languageValidator, ObjectIdGetDatum(retval));
	}

	return retval;
}
コード例 #25
0
ファイル: tuptoaster.c プロジェクト: sunyangkobe/cscd43
/* ----------
 * toast_save_datum -
 *
 *	Save one single datum into the secondary relation and return
 *	a varattrib reference for it.
 * ----------
 */
static Datum
toast_save_datum(Relation rel, Datum value)
{
	Relation	toastrel;
	Relation	toastidx;
	HeapTuple	toasttup;
	InsertIndexResult idxres;
	TupleDesc	toasttupDesc;
	Datum		t_values[3];
	char		t_nulls[3];
	varattrib  *result;
	struct
	{
		struct varlena hdr;
		char		data[TOAST_MAX_CHUNK_SIZE];
	}			chunk_data;
	int32		chunk_size;
	int32		chunk_seq = 0;
	char	   *data_p;
	int32		data_todo;

	/*
	 * Create the varattrib reference
	 */
	result = (varattrib *) palloc(sizeof(varattrib));

	result->va_header = sizeof(varattrib) | VARATT_FLAG_EXTERNAL;
	if (VARATT_IS_COMPRESSED(value))
	{
		result->va_header |= VARATT_FLAG_COMPRESSED;
		result->va_content.va_external.va_rawsize =
			((varattrib *) value)->va_content.va_compressed.va_rawsize;
	}
	else
		result->va_content.va_external.va_rawsize = VARATT_SIZE(value);

	result->va_content.va_external.va_extsize =
		VARATT_SIZE(value) - VARHDRSZ;
	result->va_content.va_external.va_valueid = newoid();
	result->va_content.va_external.va_toastrelid =
		rel->rd_rel->reltoastrelid;

	/*
	 * Initialize constant parts of the tuple data
	 */
	t_values[0] = ObjectIdGetDatum(result->va_content.va_external.va_valueid);
	t_values[2] = PointerGetDatum(&chunk_data);
	t_nulls[0] = ' ';
	t_nulls[1] = ' ';
	t_nulls[2] = ' ';

	/*
	 * Get the data to process
	 */
	data_p = VARATT_DATA(value);
	data_todo = VARATT_SIZE(value) - VARHDRSZ;

	/*
	 * Open the toast relation
	 */
	toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
	toasttupDesc = toastrel->rd_att;
	toastidx = index_open(toastrel->rd_rel->reltoastidxid);

	/*
	 * Split up the item into chunks
	 */
	while (data_todo > 0)
	{
		/*
		 * Calculate the size of this chunk
		 */
		chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo);

		/*
		 * Build a tuple and store it
		 */
		t_values[1] = Int32GetDatum(chunk_seq++);
		VARATT_SIZEP(&chunk_data) = chunk_size + VARHDRSZ;
		memcpy(VARATT_DATA(&chunk_data), data_p, chunk_size);
		toasttup = heap_formtuple(toasttupDesc, t_values, t_nulls);
		if (!HeapTupleIsValid(toasttup))
			elog(ERROR, "failed to build TOAST tuple");

		simple_heap_insert(toastrel, toasttup);

		/*
		 * Create the index entry.	We cheat a little here by not using
		 * FormIndexDatum: this relies on the knowledge that the index
		 * columns are the same as the initial columns of the table.
		 *
		 * Note also that there had better not be any user-created index on
		 * the TOAST table, since we don't bother to update anything else.
		 */
		idxres = index_insert(toastidx, t_values, t_nulls,
							  &(toasttup->t_self),
							  toastrel, toastidx->rd_index->indisunique);
		if (idxres == NULL)
			elog(ERROR, "failed to insert index entry for TOAST tuple");

		/*
		 * Free memory
		 */
		pfree(idxres);
		heap_freetuple(toasttup);

		/*
		 * Move on to next chunk
		 */
		data_todo -= chunk_size;
		data_p += chunk_size;
	}

	/*
	 * Done - close toast relation and return the reference
	 */
	index_close(toastidx);
	heap_close(toastrel, RowExclusiveLock);

	return PointerGetDatum(result);
}
コード例 #26
0
/*
 * pg_lock_status - produce a view with one row per held or awaited lock mode
 */
Datum
pg_lock_status(PG_FUNCTION_ARGS)
{
	FuncCallContext *funcctx;
	PG_Lock_Status *mystatus;
	LockData   *lockData;

	if (SRF_IS_FIRSTCALL())
	{
		TupleDesc	tupdesc;
		MemoryContext oldcontext;

		/* create a function context for cross-call persistence */
		funcctx = SRF_FIRSTCALL_INIT();

		/*
		 * switch to memory context appropriate for multiple function calls
		 */
		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

		/* build tupdesc for result tuples */
		/* this had better match pg_locks view in system_views.sql */
		tupdesc = CreateTemplateTupleDesc(14, false);
		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
						   TEXTOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
						   OIDOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
						   OIDOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
						   INT4OID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
						   INT2OID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
						   TEXTOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
						   XIDOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
						   OIDOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
						   OIDOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
						   INT2OID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
						   TEXTOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
						   INT4OID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
						   TEXTOID, -1, 0);
		TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
						   BOOLOID, -1, 0);

		funcctx->tuple_desc = BlessTupleDesc(tupdesc);

		/*
		 * Collect all the locking information that we will format and send
		 * out as a result set.
		 */
		mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
		funcctx->user_fctx = (void *) mystatus;

		mystatus->lockData = GetLockStatusData();
		mystatus->currIdx = 0;

		MemoryContextSwitchTo(oldcontext);
	}

	funcctx = SRF_PERCALL_SETUP();
	mystatus = (PG_Lock_Status *) funcctx->user_fctx;
	lockData = mystatus->lockData;

	while (mystatus->currIdx < lockData->nelements)
	{
		PROCLOCK   *proclock;
		LOCK	   *lock;
		PGPROC	   *proc;
		bool		granted;
		LOCKMODE	mode = 0;
		const char *locktypename;
		char		tnbuf[32];
		Datum		values[14];
		char		nulls[14];
		HeapTuple	tuple;
		Datum		result;

		proclock = &(lockData->proclocks[mystatus->currIdx]);
		lock = &(lockData->locks[mystatus->currIdx]);
		proc = &(lockData->procs[mystatus->currIdx]);

		/*
		 * Look to see if there are any held lock modes in this PROCLOCK. If
		 * so, report, and destructively modify lockData so we don't report
		 * again.
		 */
		granted = false;
		if (proclock->holdMask)
		{
			for (mode = 0; mode < MAX_LOCKMODES; mode++)
			{
				if (proclock->holdMask & LOCKBIT_ON(mode))
				{
					granted = true;
					proclock->holdMask &= LOCKBIT_OFF(mode);
					break;
				}
			}
		}

		/*
		 * If no (more) held modes to report, see if PROC is waiting for a
		 * lock on this lock.
		 */
		if (!granted)
		{
			if (proc->waitLock == proclock->tag.myLock)
			{
				/* Yes, so report it with proper mode */
				mode = proc->waitLockMode;

				/*
				 * We are now done with this PROCLOCK, so advance pointer to
				 * continue with next one on next call.
				 */
				mystatus->currIdx++;
			}
			else
			{
				/*
				 * Okay, we've displayed all the locks associated with this
				 * PROCLOCK, proceed to the next one.
				 */
				mystatus->currIdx++;
				continue;
			}
		}

		/*
		 * Form tuple with appropriate data.
		 */
		MemSet(values, 0, sizeof(values));
		MemSet(nulls, ' ', sizeof(nulls));

		if (lock->tag.locktag_type <= LOCKTAG_LAST_TYPE)
			locktypename = LockTagTypeNames[lock->tag.locktag_type];
		else
		{
			snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
					 (int) lock->tag.locktag_type);
			locktypename = tnbuf;
		}
		values[0] = DirectFunctionCall1(textin,
										CStringGetDatum(locktypename));

		switch ((LockTagType) lock->tag.locktag_type)
		{
			case LOCKTAG_RELATION:
			case LOCKTAG_RELATION_EXTEND:
				values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
				values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
				nulls[3] = 'n';
				nulls[4] = 'n';
				nulls[5] = 'n';
				nulls[6] = 'n';
				nulls[7] = 'n';
				nulls[8] = 'n';
				nulls[9] = 'n';
				break;
			case LOCKTAG_PAGE:
				values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
				values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
				values[3] = UInt32GetDatum(lock->tag.locktag_field3);
				nulls[4] = 'n';
				nulls[5] = 'n';
				nulls[6] = 'n';
				nulls[7] = 'n';
				nulls[8] = 'n';
				nulls[9] = 'n';
				break;
			case LOCKTAG_TUPLE:
				values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
				values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
				values[3] = UInt32GetDatum(lock->tag.locktag_field3);
				values[4] = UInt16GetDatum(lock->tag.locktag_field4);
				nulls[5] = 'n';
				nulls[6] = 'n';
				nulls[7] = 'n';
				nulls[8] = 'n';
				nulls[9] = 'n';
				break;
			case LOCKTAG_TRANSACTION:
				values[6] = TransactionIdGetDatum(lock->tag.locktag_field1);
				nulls[1] = 'n';
				nulls[2] = 'n';
				nulls[3] = 'n';
				nulls[4] = 'n';
				nulls[5] = 'n';
				nulls[7] = 'n';
				nulls[8] = 'n';
				nulls[9] = 'n';
				break;
			case LOCKTAG_VIRTUALTRANSACTION:
				values[5] = VXIDGetDatum(lock->tag.locktag_field1,
										 lock->tag.locktag_field2);
				nulls[1] = 'n';
				nulls[2] = 'n';
				nulls[3] = 'n';
				nulls[4] = 'n';
				nulls[6] = 'n';
				nulls[7] = 'n';
				nulls[8] = 'n';
				nulls[9] = 'n';
				break;
			case LOCKTAG_OBJECT:
			case LOCKTAG_USERLOCK:
			case LOCKTAG_ADVISORY:
			default:			/* treat unknown locktags like OBJECT */
				values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
				values[7] = ObjectIdGetDatum(lock->tag.locktag_field2);
				values[8] = ObjectIdGetDatum(lock->tag.locktag_field3);
				values[9] = Int16GetDatum(lock->tag.locktag_field4);
				nulls[2] = 'n';
				nulls[3] = 'n';
				nulls[4] = 'n';
				nulls[5] = 'n';
				nulls[6] = 'n';
				break;
		}

		values[10] = VXIDGetDatum(proc->backendId, proc->lxid);
		if (proc->pid != 0)
			values[11] = Int32GetDatum(proc->pid);
		else
			nulls[11] = 'n';
		values[12] = DirectFunctionCall1(textin,
					  CStringGetDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock),
													  mode)));
		values[13] = BoolGetDatum(granted);

		tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
		result = HeapTupleGetDatum(tuple);
		SRF_RETURN_NEXT(funcctx, result);
	}

	SRF_RETURN_DONE(funcctx);
}
コード例 #27
0
HeapTuple
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
				Datum *Values, const char *Nulls)
{
	MemoryContext oldcxt = NULL;
	HeapTuple	mtuple;
	int			numberOfAttributes;
	Datum	   *v;
	char	   *n;
	int			i;

	if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
	{
		SPI_result = SPI_ERROR_ARGUMENT;
		return NULL;
	}

	if (_SPI_curid + 1 == _SPI_connected)		/* connected */
	{
		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
			elog(ERROR, "SPI stack corrupted");
		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
	}
	SPI_result = 0;
	numberOfAttributes = rel->rd_att->natts;
	v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
	n = (char *) palloc(numberOfAttributes * sizeof(char));

	/* fetch old values and nulls */
	heap_deformtuple(tuple, rel->rd_att, v, n);

	/* replace values and nulls */
	for (i = 0; i < natts; i++)
	{
		if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
			break;
		v[attnum[i] - 1] = Values[i];
		n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? 'n' : ' ';
	}

	if (i == natts)				/* no errors in *attnum */
	{
		mtuple = heap_formtuple(rel->rd_att, v, n);

		/*
		 * copy the identification info of the old tuple: t_ctid, t_self, and
		 * OID (if any)
		 */
		mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
		mtuple->t_self = tuple->t_self;
		mtuple->t_tableOid = tuple->t_tableOid;
		if (rel->rd_att->tdhasoid)
			HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
	}
	else
	{
		mtuple = NULL;
		SPI_result = SPI_ERROR_NOATTRIBUTE;
	}

	pfree(v);
	pfree(n);

	if (oldcxt)
		MemoryContextSwitchTo(oldcxt);

	return mtuple;
}
コード例 #28
0
ファイル: drivedist.c プロジェクト: CCheng1231/pgrouting
static int compute_driving_distance(char* sql, int source_vertex_id, 
                                    float8 distance, bool directed, 
                                    bool has_reverse_cost,
                                    path_element_t **path, int *path_count) 
{
  int SPIcode;
  void *SPIplan;
  Portal SPIportal;
  bool moredata = TRUE;
  int ntuples;
  edge_t *edges = NULL;
  int total_tuples = 0;
  edge_columns_t edge_columns = {.id= -1, .source= -1, .target= -1, 
                                 .cost= -1, .reverse_cost= -1};

  int v_max_id=0;
  int v_min_id=INT_MAX;

  char *err_msg;
  int ret = -1;
  
  int s_count = 0;
  
  register int z;
  
  DBG("start driving_distance\n");
  
  SPIcode = SPI_connect();
  if (SPIcode  != SPI_OK_CONNECT) {
    elog(ERROR, "driving_distance: couldn't open a connection to SPI");
    return -1;
  }
  
  SPIplan = SPI_prepare(sql, 0, NULL);

  if (SPIplan  == NULL) {
    elog(ERROR, "driving_distance: couldn't create query plan via SPI");
    return -1;
  }

  if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, 
                                   NULL, true)) == NULL) {  
    elog(ERROR, "driving_distance: SPI_cursor_open('%s') returns NULL", sql);
    return -1;
  }

  while (moredata == TRUE) {
    SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);


    if (edge_columns.id == -1)  {
      if (fetch_edge_columns(SPI_tuptable, &edge_columns, 
                             has_reverse_cost) == -1)
        return finish(SPIcode, ret);
    }

    ntuples = SPI_processed;
    total_tuples += ntuples;
    if (!edges)
      edges = palloc(total_tuples * sizeof(edge_t));
    else
      edges = repalloc(edges, total_tuples * sizeof(edge_t));

    if (edges == NULL) {
      elog(ERROR, "Out of memory");
      return finish(SPIcode, ret);
    }

    if (ntuples > 0) {
      int t;
      SPITupleTable *tuptable = SPI_tuptable;
      TupleDesc tupdesc = SPI_tuptable->tupdesc;
      
      for (t = 0; t < ntuples; t++) {
        HeapTuple tuple = tuptable->vals[t];
        fetch_edge(&tuple, &tupdesc, &edge_columns, 
                   &edges[total_tuples - ntuples + t]);
      }
      SPI_freetuptable(tuptable);
    } 
    else {
      moredata = FALSE;
    }
  }


  //defining min and max vertex id
      
  DBG("Total %i tuples", total_tuples);
    
  for(z=0; z<total_tuples; z++)
  {
    if(edges[z].source<v_min_id)
      v_min_id=edges[z].source;

    if(edges[z].source>v_max_id)
      v_max_id=edges[z].source;
                                            
    if(edges[z].target<v_min_id)
      v_min_id=edges[z].target;

    if(edges[z].target>v_max_id)
      v_max_id=edges[z].target;      
                                                                        
    DBG("%i <-> %i", v_min_id, v_max_id);
                                
  }

  //::::::::::::::::::::::::::::::::::::  
  //:: reducing vertex id (renumbering)
  //::::::::::::::::::::::::::::::::::::
  for(z=0; z<total_tuples; z++)
  {
    //check if edges[] contains source
    if(edges[z].source == source_vertex_id || 
       edges[z].target == source_vertex_id)
      ++s_count;

    edges[z].source-=v_min_id;
    edges[z].target-=v_min_id;
    DBG("%i - %i", edges[z].source, edges[z].target);      
  }

  if(s_count == 0)
  {
    elog(ERROR, "Start vertex was not found.");
    return -1;
  }
                          
  source_vertex_id -= v_min_id;

  profstop("extract", prof_extract);
  profstart(prof_dijkstra);
  
  DBG("Calling boost_dijkstra\n");
        
  ret = boost_dijkstra_dist(edges, total_tuples, source_vertex_id,
                            distance, directed, has_reverse_cost, 
                            path, path_count, &err_msg);
    
  DBG("Back from  boost_dijkstra\n");
        
  if (ret < 0) {
    elog(ERROR, "Error computing path: %s", err_msg);
  } 
    
  profstop("dijkstra", prof_dijkstra);
  profstart(prof_store);
    
  //::::::::::::::::::::::::::::::::
  //:: restoring original vertex id
  //::::::::::::::::::::::::::::::::
  for(z=0; z<*path_count; z++)
  {
    //DBG("vetex %i\n",(*path)[z].vertex_id);
    (*path)[z].vertex_id+=v_min_id;
  }

  return finish(SPIcode, ret);
}


PG_FUNCTION_INFO_V1(driving_distance);
Datum
driving_distance(PG_FUNCTION_ARGS)
{
  FuncCallContext     *funcctx;
  int                  call_cntr;
  int                  max_calls;
  TupleDesc            tuple_desc;
  path_element_t      *path = 0;

  /* stuff done only on the first call of the function */
  if (SRF_IS_FIRSTCALL()) {
    MemoryContext   oldcontext;
    int path_count = 0;
    int ret;
    
    // XXX profiling messages are not thread safe
    profstart(prof_total);
    profstart(prof_extract);
    
    /* create a function context for cross-call persistence */
    funcctx = SRF_FIRSTCALL_INIT();
    
    /* switch to memory context appropriate for multiple function calls */
    oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
    
    ret = compute_driving_distance(text2char(PG_GETARG_TEXT_P(0)), // sql
                                PG_GETARG_INT32(1),   // source vertex
                                PG_GETARG_FLOAT8(2),  // distance or time
                                PG_GETARG_BOOL(3),
                                PG_GETARG_BOOL(4), &path, &path_count);
    if (ret < 0) {
        elog(ERROR, "Error computing path");
    } 
    

#ifdef DEBUG
    DBG("Ret is %i", ret);
    int i;
    for (i = 0; i < path_count; i++) {
        DBG("Step %i vertex_id  %i ", i, path[i].vertex_id);
        DBG("        edge_id    %i ", path[i].edge_id);
        DBG("        cost       %f ", path[i].cost);
    }
#endif

    /* total number of tuples to be returned */
    funcctx->max_calls = path_count;
    funcctx->user_fctx = path;

    funcctx->tuple_desc = BlessTupleDesc(
                             RelationNameGetTupleDesc("pgr_costResult"));
    
    MemoryContextSwitchTo(oldcontext);
  }
  
  /* stuff done on every call of the function */
  funcctx = SRF_PERCALL_SETUP();

  call_cntr = funcctx->call_cntr;
  max_calls = funcctx->max_calls;
  tuple_desc = funcctx->tuple_desc;
  path = (path_element_t*) funcctx->user_fctx;
  
  if (call_cntr < max_calls) {   /* do when there is more left to send */
    HeapTuple    tuple;
    Datum        result;
    Datum *values;
    char* nulls;
    
    values = palloc(4 * sizeof(Datum));
    nulls = palloc(4 * sizeof(char));

    values[0] = Int32GetDatum(call_cntr);
    nulls[0] = ' ';
    values[1] = Int32GetDatum(path[call_cntr].vertex_id);
    nulls[1] = ' ';
    values[2] = Int32GetDatum(path[call_cntr].edge_id);
    nulls[2] = ' ';
    values[3] = Float8GetDatum(path[call_cntr].cost);
    nulls[3] = ' ';
      
    tuple = heap_formtuple(tuple_desc, values, nulls);
    

    /* make the tuple into a datum */
    result = HeapTupleGetDatum(tuple);
    
    /* clean up (this is not really necessary) */
    pfree(values);
    pfree(nulls);

    SRF_RETURN_NEXT(funcctx, result);
  }
  else {    /* do when there is no more left */
    if (path) free(path);
    profstop("store", prof_store);
    profstop("total", prof_total);
#ifdef PROFILE
    elog(NOTICE, "_________");
#endif
    DBG("Returning value");

    SRF_RETURN_DONE(funcctx);
  }
}
コード例 #29
0
/*
 * Create a table space
 *
 * Only superusers can create a tablespace. This seems a reasonable restriction
 * since we're determining the system layout and, anyway, we probably have
 * root if we're doing this kind of activity
 */
void
CreateTableSpace(CreateTableSpaceStmt *stmt)
{
#ifdef HAVE_SYMLINK
	Relation	rel;
	Datum		values[Natts_pg_tablespace];
	char		nulls[Natts_pg_tablespace];
	HeapTuple	tuple;
	Oid			tablespaceoid;
	char	   *location;
	char	   *linkloc;
	Oid			ownerId;

	/* validate */

	/* don't call this in a transaction block */
	PreventTransactionChain((void *) stmt, "CREATE TABLESPACE");

	/* Must be super user */
	if (!superuser())
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("permission denied to create tablespace \"%s\"",
						stmt->tablespacename),
				 errhint("Must be superuser to create a tablespace.")));

	/* However, the eventual owner of the tablespace need not be */
	if (stmt->owner)
		ownerId = get_roleid_checked(stmt->owner);
	else
		ownerId = GetUserId();

	/* Unix-ify the offered path, and strip any trailing slashes */
	location = pstrdup(stmt->location);
	canonicalize_path(location);

	/* disallow quotes, else CREATE DATABASE would be at risk */
	if (strchr(location, '\''))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_NAME),
			   errmsg("tablespace location may not contain single quotes")));

	/*
	 * Allowing relative paths seems risky
	 *
	 * this also helps us ensure that location is not empty or whitespace
	 */
	if (!is_absolute_path(location))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("tablespace location must be an absolute path")));

	/*
	 * Check that location isn't too long. Remember that we're going to append
	 * '/<dboid>/<relid>.<nnn>'  (XXX but do we ever form the whole path
	 * explicitly?	This may be overly conservative.)
	 */
	if (strlen(location) >= (MAXPGPATH - 1 - 10 - 1 - 10 - 1 - 10))
		ereport(ERROR,
				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
				 errmsg("tablespace location \"%s\" is too long",
						location)));

	/*
	 * Disallow creation of tablespaces named "pg_xxx"; we reserve this
	 * namespace for system purposes.
	 */
	if (!allowSystemTableMods && IsReservedName(stmt->tablespacename))
		ereport(ERROR,
				(errcode(ERRCODE_RESERVED_NAME),
				 errmsg("unacceptable tablespace name \"%s\"",
						stmt->tablespacename),
		errdetail("The prefix \"pg_\" is reserved for system tablespaces.")));

	/*
	 * Check that there is no other tablespace by this name.  (The unique
	 * index would catch this anyway, but might as well give a friendlier
	 * message.)
	 */
	if (OidIsValid(get_tablespace_oid(stmt->tablespacename)))
		ereport(ERROR,
				(errcode(ERRCODE_DUPLICATE_OBJECT),
				 errmsg("tablespace \"%s\" already exists",
						stmt->tablespacename)));

	/*
	 * Insert tuple into pg_tablespace.  The purpose of doing this first is to
	 * lock the proposed tablename against other would-be creators. The
	 * insertion will roll back if we find problems below.
	 */
	rel = heap_open(TableSpaceRelationId, RowExclusiveLock);

	MemSet(nulls, ' ', Natts_pg_tablespace);

	values[Anum_pg_tablespace_spcname - 1] =
		DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
	values[Anum_pg_tablespace_spcowner - 1] =
		ObjectIdGetDatum(ownerId);
	values[Anum_pg_tablespace_spclocation - 1] =
		DirectFunctionCall1(textin, CStringGetDatum(location));
	nulls[Anum_pg_tablespace_spcacl - 1] = 'n';

	tuple = heap_formtuple(rel->rd_att, values, nulls);

	tablespaceoid = simple_heap_insert(rel, tuple);

	CatalogUpdateIndexes(rel, tuple);

	heap_freetuple(tuple);

	/* Record dependency on owner */
	recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);

	/*
	 * Attempt to coerce target directory to safe permissions.	If this fails,
	 * it doesn't exist or has the wrong owner.
	 */
	if (chmod(location, 0700) != 0)
		ereport(ERROR,
				(errcode_for_file_access(),
				 errmsg("could not set permissions on directory \"%s\": %m",
						location)));

	/*
	 * Check the target directory is empty.
	 */
	if (!directory_is_empty(location))
		ereport(ERROR,
				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				 errmsg("directory \"%s\" is not empty",
						location)));

	/*
	 * Create the PG_VERSION file in the target directory.	This has several
	 * purposes: to make sure we can write in the directory, to prevent
	 * someone from creating another tablespace pointing at the same directory
	 * (the emptiness check above will fail), and to label tablespace
	 * directories by PG version.
	 */
	set_short_version(location);

	/*
	 * All seems well, create the symlink
	 */
	linkloc = (char *) palloc(10 + 10 + 1);
	sprintf(linkloc, "pg_tblspc/%u", tablespaceoid);

	if (symlink(location, linkloc) < 0)
		ereport(ERROR,
				(errcode_for_file_access(),
				 errmsg("could not create symbolic link \"%s\": %m",
						linkloc)));

	/* Record the filesystem change in XLOG */
	{
		xl_tblspc_create_rec xlrec;
		XLogRecData rdata[2];

		xlrec.ts_id = tablespaceoid;
		rdata[0].data = (char *) &xlrec;
		rdata[0].len = offsetof(xl_tblspc_create_rec, ts_path);
		rdata[0].buffer = InvalidBuffer;
		rdata[0].next = &(rdata[1]);

		rdata[1].data = (char *) location;
		rdata[1].len = strlen(location) + 1;
		rdata[1].buffer = InvalidBuffer;
		rdata[1].next = NULL;

		(void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_CREATE, rdata);
	}

	pfree(linkloc);
	pfree(location);

	/* We keep the lock on pg_tablespace until commit */
	heap_close(rel, NoLock);
#else							/* !HAVE_SYMLINK */
	ereport(ERROR,
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
			 errmsg("tablespaces are not supported on this platform")));
#endif   /* HAVE_SYMLINK */
}
コード例 #30
0
ファイル: dijkstra.c プロジェクト: dapotts/pgrouting
Datum
shortest_path(PG_FUNCTION_ARGS) {
  FuncCallContext     *funcctx;
  int                  call_cntr;
  int                  max_calls;
  TupleDesc            tuple_desc;
  pgr_path_element3_t  *ret_path = 0;

  /* stuff done only on the first call of the function */
  if (SRF_IS_FIRSTCALL()) {
      MemoryContext   oldcontext;
      int path_count = 0;

      /* create a function context for cross-call persistence */
      funcctx = SRF_FIRSTCALL_INIT();

      /* switch to memory context appropriate for multiple function calls */
      oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);


      compute_shortest_path(pgr_text2char(PG_GETARG_TEXT_P(0)),
                                  PG_GETARG_INT64(1),
                                  PG_GETARG_INT64(2),
                                  PG_GETARG_BOOL(3),
                                  PG_GETARG_BOOL(4), &ret_path, &path_count);

      /* total number of tuples to be returned */
      funcctx->max_calls = path_count;
      funcctx->user_fctx = ret_path;
      if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));

      funcctx->tuple_desc = tuple_desc;

      MemoryContextSwitchTo(oldcontext);
  }

  /* stuff done on every call of the function */
  funcctx = SRF_PERCALL_SETUP();

  call_cntr = funcctx->call_cntr;
  max_calls = funcctx->max_calls;
  tuple_desc = funcctx->tuple_desc;
  ret_path = (pgr_path_element3_t*) funcctx->user_fctx;

  /* do when there is more left to send */
  if (call_cntr < max_calls) {
      HeapTuple    tuple;
      Datum        result;
      Datum *values;
      char* nulls;

      values = palloc(6 * sizeof(Datum));
      nulls = palloc(6 * sizeof(char));

      values[0] = Int32GetDatum(ret_path[call_cntr].seq);
      nulls[0] = ' ';
      values[1] = Int32GetDatum(ret_path[call_cntr].seq);
      nulls[1] = ' ';
      values[2] = Int64GetDatum(ret_path[call_cntr].vertex);
      nulls[2] = ' ';
      values[3] = Int64GetDatum(ret_path[call_cntr].edge);
      nulls[3] = ' ';
      values[4] = Float8GetDatum(ret_path[call_cntr].cost);
      nulls[4] = ' ';
      values[5] = Float8GetDatum(ret_path[call_cntr].tot_cost);
      nulls[5] = ' ';

      tuple = heap_formtuple(tuple_desc, values, nulls);

      /* make the tuple into a datum */
      result = HeapTupleGetDatum(tuple);

      /* clean up (this is not really necessary) */
      pfree(values);
      pfree(nulls);

      SRF_RETURN_NEXT(funcctx, result);
  } else {
      /* do when there is no more left */
      if (ret_path) free(ret_path);
      SRF_RETURN_DONE(funcctx);
  }
}