本文整理汇总了C++中MemoryContextAlloc函数的典型用法代码示例。如果您正苦于以下问题:C++ MemoryContextAlloc函数的具体用法?C++ MemoryContextAlloc怎么用?C++ MemoryContextAlloc使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了MemoryContextAlloc函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。
示例1: record_eq
/*
* record_eq :
* compares two records for equality
* result :
* returns true if the records are equal, false otherwise.
*
* Note: we do not use record_cmp here, since equality may be meaningful in
* datatypes that don't have a total ordering (and hence no btree support).
*/
Datum
record_eq(PG_FUNCTION_ARGS)
{
HeapTupleHeader record1 = PG_GETARG_HEAPTUPLEHEADER(0);
HeapTupleHeader record2 = PG_GETARG_HEAPTUPLEHEADER(1);
bool result = true;
Oid tupType1;
Oid tupType2;
int32 tupTypmod1;
int32 tupTypmod2;
TupleDesc tupdesc1;
TupleDesc tupdesc2;
HeapTupleData tuple1;
HeapTupleData tuple2;
int ncolumns1;
int ncolumns2;
RecordCompareData *my_extra;
int ncols;
Datum *values1;
Datum *values2;
bool *nulls1;
bool *nulls2;
int i1;
int i2;
int j;
/* Extract type info from the tuples */
tupType1 = HeapTupleHeaderGetTypeId(record1);
tupTypmod1 = HeapTupleHeaderGetTypMod(record1);
tupdesc1 = lookup_rowtype_tupdesc(tupType1, tupTypmod1);
ncolumns1 = tupdesc1->natts;
tupType2 = HeapTupleHeaderGetTypeId(record2);
tupTypmod2 = HeapTupleHeaderGetTypMod(record2);
tupdesc2 = lookup_rowtype_tupdesc(tupType2, tupTypmod2);
ncolumns2 = tupdesc2->natts;
/* Build temporary HeapTuple control structures */
tuple1.t_len = HeapTupleHeaderGetDatumLength(record1);
ItemPointerSetInvalid(&(tuple1.t_self));
tuple1.t_tableOid = InvalidOid;
tuple1.t_data = record1;
tuple2.t_len = HeapTupleHeaderGetDatumLength(record2);
ItemPointerSetInvalid(&(tuple2.t_self));
tuple2.t_tableOid = InvalidOid;
tuple2.t_data = record2;
/*
* We arrange to look up the needed comparison info just once per series
* of calls, assuming the record types don't change underneath us.
*/
ncols = Max(ncolumns1, ncolumns2);
my_extra = (RecordCompareData *) fcinfo->flinfo->fn_extra;
if (my_extra == NULL ||
my_extra->ncolumns < ncols)
{
fcinfo->flinfo->fn_extra =
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
sizeof(RecordCompareData) - sizeof(ColumnCompareData)
+ ncols * sizeof(ColumnCompareData));
my_extra = (RecordCompareData *) fcinfo->flinfo->fn_extra;
my_extra->ncolumns = ncols;
my_extra->record1_type = InvalidOid;
my_extra->record1_typmod = 0;
my_extra->record2_type = InvalidOid;
my_extra->record2_typmod = 0;
}
if (my_extra->record1_type != tupType1 ||
my_extra->record1_typmod != tupTypmod1 ||
my_extra->record2_type != tupType2 ||
my_extra->record2_typmod != tupTypmod2)
{
MemSet(my_extra->columns, 0, ncols * sizeof(ColumnCompareData));
my_extra->record1_type = tupType1;
my_extra->record1_typmod = tupTypmod1;
my_extra->record2_type = tupType2;
my_extra->record2_typmod = tupTypmod2;
}
/* Break down the tuples into fields */
values1 = (Datum *) palloc(ncolumns1 * sizeof(Datum));
nulls1 = (bool *) palloc(ncolumns1 * sizeof(bool));
heap_deform_tuple(&tuple1, tupdesc1, values1, nulls1);
values2 = (Datum *) palloc(ncolumns2 * sizeof(Datum));
nulls2 = (bool *) palloc(ncolumns2 * sizeof(bool));
heap_deform_tuple(&tuple2, tupdesc2, values2, nulls2);
/*
* Scan corresponding columns, allowing for dropped columns in different
* places in the two rows. i1 and i2 are physical column indexes, j is
* the logical column index.
//.........这里部分代码省略.........
开发者ID:adunstan,项目名称:pg-cvs-mirror,代码行数:101,代码来源:rowtypes.c
示例2: setop_fill_hash_table
/*
* ExecSetOp for hashed case: phase 1, read input and build hash table
*/
static void
setop_fill_hash_table(SetOpState *setopstate)
{
SetOp *node = (SetOp *) setopstate->ps.plan;
PlanState *outerPlan;
int firstFlag;
bool in_first_rel PG_USED_FOR_ASSERTS_ONLY;
ExprContext *econtext = setopstate->ps.ps_ExprContext;
/*
* get state info from node
*/
outerPlan = outerPlanState(setopstate);
firstFlag = node->firstFlag;
/* verify planner didn't mess up */
Assert(firstFlag == 0 ||
(firstFlag == 1 &&
(node->cmd == SETOPCMD_INTERSECT ||
node->cmd == SETOPCMD_INTERSECT_ALL)));
/*
* Process each outer-plan tuple, and then fetch the next one, until we
* exhaust the outer plan.
*/
in_first_rel = true;
for (;;)
{
TupleTableSlot *outerslot;
int flag;
TupleHashEntryData *entry;
bool isnew;
outerslot = ExecProcNode(outerPlan);
if (TupIsNull(outerslot))
break;
/* Identify whether it's left or right input */
flag = fetch_tuple_flag(setopstate, outerslot);
if (flag == firstFlag)
{
/* (still) in first input relation */
Assert(in_first_rel);
/* Find or build hashtable entry for this tuple's group */
entry = LookupTupleHashEntry(setopstate->hashtable, outerslot,
&isnew);
/* If new tuple group, initialize counts */
if (isnew)
{
entry->additional = (SetOpStatePerGroup)
MemoryContextAlloc(setopstate->hashtable->tablecxt,
sizeof(SetOpStatePerGroupData));
initialize_counts((SetOpStatePerGroup) entry->additional);
}
/* Advance the counts */
advance_counts((SetOpStatePerGroup) entry->additional, flag);
}
else
{
/* reached second relation */
in_first_rel = false;
/* For tuples not seen previously, do not make hashtable entry */
entry = LookupTupleHashEntry(setopstate->hashtable, outerslot,
NULL);
/* Advance the counts if entry is already present */
if (entry)
advance_counts((SetOpStatePerGroup) entry->additional, flag);
}
/* Must reset expression context after each hashtable lookup */
ResetExprContext(econtext);
}
setopstate->table_filled = true;
/* Initialize to walk the hash table */
ResetTupleHashIterator(setopstate->hashtable, &setopstate->hashiter);
}
开发者ID:eubide,项目名称:postgres,代码行数:85,代码来源:nodeSetOp.c
示例3: _bt_getroot
//.........这里部分代码省略.........
metad->btm_root = rootblkno;
metad->btm_level = 0;
metad->btm_fastroot = rootblkno;
metad->btm_fastlevel = 0;
MarkBufferDirty(rootbuf);
MarkBufferDirty(metabuf);
/* XLOG stuff */
if (RelationNeedsWAL(rel))
{
xl_btree_newroot xlrec;
XLogRecPtr recptr;
XLogRecData rdata;
xlrec.node = rel->rd_node;
xlrec.rootblk = rootblkno;
xlrec.level = 0;
rdata.data = (char *) &xlrec;
rdata.len = SizeOfBtreeNewroot;
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT, &rdata);
PageSetLSN(rootpage, recptr);
PageSetTLI(rootpage, ThisTimeLineID);
PageSetLSN(metapg, recptr);
PageSetTLI(metapg, ThisTimeLineID);
}
END_CRIT_SECTION();
/*
* Send out relcache inval for metapage change (probably unnecessary
* here, but let's be safe).
*/
CacheInvalidateRelcache(rel);
/*
* swap root write lock for read lock. There is no danger of anyone
* else accessing the new root page while it's unlocked, since no one
* else knows where it is yet.
*/
LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK);
LockBuffer(rootbuf, BT_READ);
/* okay, metadata is correct, release lock on it */
_bt_relbuf(rel, metabuf);
}
else
{
rootblkno = metad->btm_fastroot;
Assert(rootblkno != P_NONE);
rootlevel = metad->btm_fastlevel;
/*
* Cache the metapage data for next time
*/
rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt,
sizeof(BTMetaPageData));
memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData));
/*
* We are done with the metapage; arrange to release it via first
* _bt_relandgetbuf call
*/
rootbuf = metabuf;
for (;;)
{
rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);
rootpage = BufferGetPage(rootbuf);
rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
if (!P_IGNORE(rootopaque))
break;
/* it's dead, Jim. step right one page */
if (P_RIGHTMOST(rootopaque))
elog(ERROR, "no live root page found in index \"%s\"",
RelationGetRelationName(rel));
rootblkno = rootopaque->btpo_next;
}
/* Note: can't check btpo.level on deleted pages */
if (rootopaque->btpo.level != rootlevel)
elog(ERROR, "root page %u of index \"%s\" has level %u, expected %u",
rootblkno, RelationGetRelationName(rel),
rootopaque->btpo.level, rootlevel);
}
/*
* By here, we have a pin and read lock on the root page, and no lock set
* on the metadata page. Return the root page's buffer.
*/
return rootbuf;
}
开发者ID:twibs4,项目名称:postgres,代码行数:101,代码来源:nbtpage.c
示例4: shm_mq_receive
//.........这里部分代码省略.........
if (rb >= needed)
{
/*
* Technically, we could consume the message length
* information at this point, but the extra write to shared
* memory wouldn't be free and in most cases we would reap no
* benefit.
*/
mqh->mqh_consume_pending = needed;
*nbytesp = nbytes;
*datap = ((char *) rawdata) + MAXALIGN(sizeof(Size));
return SHM_MQ_SUCCESS;
}
/*
* We don't have the whole message, but we at least have the whole
* length word.
*/
mqh->mqh_expected_bytes = nbytes;
mqh->mqh_length_word_complete = true;
shm_mq_inc_bytes_read(mq, MAXALIGN(sizeof(Size)));
rb -= MAXALIGN(sizeof(Size));
}
else
{
Size lengthbytes;
/* Can't be split unless bigger than required alignment. */
Assert(sizeof(Size) > MAXIMUM_ALIGNOF);
/* Message word is split; need buffer to reassemble. */
if (mqh->mqh_buffer == NULL)
{
mqh->mqh_buffer = MemoryContextAlloc(mqh->mqh_context,
MQH_INITIAL_BUFSIZE);
mqh->mqh_buflen = MQH_INITIAL_BUFSIZE;
}
Assert(mqh->mqh_buflen >= sizeof(Size));
/* Copy and consume partial length word. */
if (mqh->mqh_partial_bytes + rb > sizeof(Size))
lengthbytes = sizeof(Size) - mqh->mqh_partial_bytes;
else
lengthbytes = rb;
memcpy(&mqh->mqh_buffer[mqh->mqh_partial_bytes], rawdata,
lengthbytes);
mqh->mqh_partial_bytes += lengthbytes;
shm_mq_inc_bytes_read(mq, MAXALIGN(lengthbytes));
rb -= lengthbytes;
/* If we now have the whole word, we're ready to read payload. */
if (mqh->mqh_partial_bytes >= sizeof(Size))
{
Assert(mqh->mqh_partial_bytes == sizeof(Size));
mqh->mqh_expected_bytes = *(Size *) mqh->mqh_buffer;
mqh->mqh_length_word_complete = true;
mqh->mqh_partial_bytes = 0;
}
}
}
nbytes = mqh->mqh_expected_bytes;
if (mqh->mqh_partial_bytes == 0)
{
/*
* Try to obtain the whole message in a single chunk. If this works,
开发者ID:cshorler,项目名称:postgres,代码行数:67,代码来源:shm_mq.c
示例5: hstore_populate_record
Datum
hstore_populate_record(PG_FUNCTION_ARGS)
{
Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
HStore *hs;
HEntry *entries;
char *ptr;
HeapTupleHeader rec;
Oid tupType;
int32 tupTypmod;
TupleDesc tupdesc;
HeapTupleData tuple;
HeapTuple rettuple;
RecordIOData *my_extra;
int ncolumns;
int i;
Datum *values;
bool *nulls;
if (!type_is_rowtype(argtype))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("first argument must be a rowtype")));
if (PG_ARGISNULL(0))
{
if (PG_ARGISNULL(1))
PG_RETURN_NULL();
rec = NULL;
/*
* have no tuple to look at, so the only source of type info is the
* argtype. The lookup_rowtype_tupdesc call below will error out if we
* don't have a known composite type oid here.
*/
tupType = argtype;
tupTypmod = -1;
}
else
{
rec = PG_GETARG_HEAPTUPLEHEADER(0);
if (PG_ARGISNULL(1))
PG_RETURN_POINTER(rec);
/* Extract type info from the tuple itself */
tupType = HeapTupleHeaderGetTypeId(rec);
tupTypmod = HeapTupleHeaderGetTypMod(rec);
}
hs = PG_GETARG_HS(1);
entries = ARRPTR(hs);
ptr = STRPTR(hs);
/*
* if the input hstore is empty, we can only skip the rest if we were
* passed in a non-null record, since otherwise there may be issues with
* domain nulls.
*/
if (HS_COUNT(hs) == 0 && rec)
PG_RETURN_POINTER(rec);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
ncolumns = tupdesc->natts;
if (rec)
{
/* Build a temporary HeapTuple control structure */
tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
ItemPointerSetInvalid(&(tuple.t_self));
tuple.t_tableOid = InvalidOid;
tuple.t_data = rec;
}
/*
* 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;
//.........这里部分代码省略.........
开发者ID:Epictetus,项目名称:postgres,代码行数:101,代码来源:hstore_io.c
示例6: record_send
/*
* record_send - binary output routine for any composite type.
*/
Datum
record_send(PG_FUNCTION_ARGS)
{
HeapTupleHeader rec = PG_GETARG_HEAPTUPLEHEADER(0);
Oid tupType;
int32 tupTypmod;
TupleDesc tupdesc;
HeapTupleData tuple;
RecordIOData *my_extra;
int ncolumns;
int validcols;
int i;
Datum *values;
bool *nulls;
StringInfoData buf;
/* Extract type info from the tuple itself */
tupType = HeapTupleHeaderGetTypeId(rec);
tupTypmod = HeapTupleHeaderGetTypMod(rec);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
ncolumns = tupdesc->natts;
/* Build a temporary HeapTuple control structure */
tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
ItemPointerSetInvalid(&(tuple.t_self));
tuple.t_data = rec;
/*
* 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 = (bool *) palloc(ncolumns * sizeof(bool));
/* Break down the tuple into fields */
heap_deform_tuple(&tuple, tupdesc, values, nulls);
/* And build the result string */
pq_begintypsend(&buf);
/* Need to scan to count nondeleted columns */
validcols = 0;
for (i = 0; i < ncolumns; i++)
{
if (!tupdesc->attrs[i]->attisdropped)
validcols++;
}
pq_sendint(&buf, validcols, 4);
for (i = 0; i < ncolumns; i++)
{
ColumnIOData *column_info = &my_extra->columns[i];
Oid column_type = tupdesc->attrs[i]->atttypid;
bytea *outputbytes;
/* Ignore dropped columns in datatype */
if (tupdesc->attrs[i]->attisdropped)
continue;
pq_sendint(&buf, column_type, sizeof(Oid));
if (nulls[i])
{
/* emit -1 data length to signify a NULL */
pq_sendint(&buf, -1, 4);
continue;
}
/*
* Convert the column value to binary
*/
if (column_info->column_type != column_type)
{
//.........这里部分代码省略.........
开发者ID:AnLingm,项目名称:gpdb,代码行数:101,代码来源:rowtypes.c
示例7: array_push
//.........这里部分代码省略.........
newelem = (Datum) 0;
else
newelem = PG_GETARG_DATUM(1);
}
else if (arg1_elemid != InvalidOid)
{
if (PG_ARGISNULL(1))
v = construct_empty_array(arg1_elemid);
else
v = PG_GETARG_ARRAYTYPE_P(1);
isNull = PG_ARGISNULL(0);
if (isNull)
newelem = (Datum) 0;
else
newelem = PG_GETARG_DATUM(0);
}
else
{
/* Shouldn't get here given proper type checking in parser */
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("neither input type is an array")));
PG_RETURN_NULL(); /* keep compiler quiet */
}
element_type = ARR_ELEMTYPE(v);
if (ARR_NDIM(v) == 1)
{
lb = ARR_LBOUND(v);
dimv = ARR_DIMS(v);
if (arg0_elemid != InvalidOid)
{
/* append newelem */
int ub = dimv[0] + lb[0] - 1;
indx = ub + 1;
/* overflow? */
if (indx < ub)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
}
else
{
/* prepend newelem */
indx = lb[0] - 1;
/* overflow? */
if (indx > lb[0])
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
}
}
else if (ARR_NDIM(v) == 0)
indx = 1;
else
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("argument must be empty or one-dimensional array")));
/*
* We arrange to look up info about element type only once per series of
* calls, assuming the element type doesn't change underneath us.
*/
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
if (my_extra == NULL)
{
fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
sizeof(ArrayMetaState));
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
my_extra->element_type = ~element_type;
}
if (my_extra->element_type != element_type)
{
/* Get info about element type */
get_typlenbyvalalign(element_type,
&my_extra->typlen,
&my_extra->typbyval,
&my_extra->typalign);
my_extra->element_type = element_type;
}
typlen = my_extra->typlen;
typbyval = my_extra->typbyval;
typalign = my_extra->typalign;
result = array_set(v, 1, &indx, newelem, isNull,
-1, typlen, typbyval, typalign);
/*
* Readjust result's LB to match the input's. This does nothing in the
* append case, but it's the simplest way to implement the prepend case.
*/
if (ARR_NDIM(v) == 1)
ARR_LBOUND(result)[0] = ARR_LBOUND(v)[0];
PG_RETURN_ARRAYTYPE_P(result);
}
开发者ID:BioBD,项目名称:Hypothetical_Indexes,代码行数:101,代码来源:array_userfuncs.c
示例8: open_server_SSL
/*
* Attempt to negotiate SSL connection.
*/
static int
open_server_SSL(Port *port)
{
int r;
int err;
Assert(!port->ssl);
Assert(!port->peer);
if (!(port->ssl = SSL_new(SSL_context)))
{
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("could not initialize SSL connection: %s",
SSLerrmessage())));
close_SSL(port);
return -1;
}
if (!my_SSL_set_fd(port->ssl, port->sock))
{
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("could not set SSL socket: %s",
SSLerrmessage())));
close_SSL(port);
return -1;
}
aloop:
r = SSL_accept(port->ssl);
if (r <= 0)
{
err = SSL_get_error(port->ssl, r);
switch (err)
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
#ifdef WIN32
pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),
(err == SSL_ERROR_WANT_READ) ?
FD_READ | FD_CLOSE | FD_ACCEPT : FD_WRITE | FD_CLOSE,
INFINITE);
#endif
goto aloop;
case SSL_ERROR_SYSCALL:
if (r < 0)
ereport(COMMERROR,
(errcode_for_socket_access(),
errmsg("could not accept SSL connection: %m")));
else
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("could not accept SSL connection: EOF detected")));
break;
case SSL_ERROR_SSL:
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("could not accept SSL connection: %s",
SSLerrmessage())));
break;
case SSL_ERROR_ZERO_RETURN:
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("could not accept SSL connection: EOF detected")));
break;
default:
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("unrecognized SSL error code: %d",
err)));
break;
}
close_SSL(port);
return -1;
}
port->count = 0;
/* Get client certificate, if available. */
port->peer = SSL_get_peer_certificate(port->ssl);
/* and extract the Common Name from it. */
port->peer_cn = NULL;
if (port->peer != NULL)
{
int len;
len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),
NID_commonName, NULL, 0);
if (len != -1)
{
char *peer_cn;
peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1);
r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),
NID_commonName, peer_cn, len + 1);
peer_cn[len] = '\0';
//.........这里部分代码省略.........
开发者ID:ASchurman,项目名称:BufStrat,代码行数:101,代码来源:be-secure.c
示例9: array_position_common
/*
* array_position_common
* Common code for array_position and array_position_start
*
* These are separate wrappers for the sake of opr_sanity regression test.
* They are not strict so we have to test for null inputs explicitly.
*/
static Datum
array_position_common(FunctionCallInfo fcinfo)
{
ArrayType *array;
Oid collation = PG_GET_COLLATION();
Oid element_type;
Datum searched_element,
value;
bool isnull;
int position,
position_min;
bool found = false;
TypeCacheEntry *typentry;
ArrayMetaState *my_extra;
bool null_search;
ArrayIterator array_iterator;
if (PG_ARGISNULL(0))
PG_RETURN_NULL();
array = PG_GETARG_ARRAYTYPE_P(0);
element_type = ARR_ELEMTYPE(array);
/*
* We refuse to search for elements in multi-dimensional arrays, since we
* have no good way to report the element's location in the array.
*/
if (ARR_NDIM(array) > 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("searching for elements in multidimensional arrays is not supported")));
if (PG_ARGISNULL(1))
{
/* fast return when the array doesn't have have nulls */
if (!array_contains_nulls(array))
PG_RETURN_NULL();
searched_element = (Datum) 0;
null_search = true;
}
else
{
searched_element = PG_GETARG_DATUM(1);
null_search = false;
}
position = (ARR_LBOUND(array))[0] - 1;
/* figure out where to start */
if (PG_NARGS() == 3)
{
if (PG_ARGISNULL(2))
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("initial position should not be NULL")));
position_min = PG_GETARG_INT32(2);
}
else
position_min = (ARR_LBOUND(array))[0];
/*
* We arrange to look up type info for array_create_iterator only once per
* series of calls, assuming the element type doesn't change underneath us.
*/
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
if (my_extra == NULL)
{
fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
sizeof(ArrayMetaState));
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
my_extra->element_type = ~element_type;
}
if (my_extra->element_type != element_type)
{
get_typlenbyvalalign(element_type,
&my_extra->typlen,
&my_extra->typbyval,
&my_extra->typalign);
typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("could not identify an equality operator for type %s",
format_type_be(element_type))));
my_extra->element_type = element_type;
fmgr_info(typentry->eq_opr_finfo.fn_oid, &my_extra->proc);
}
//.........这里部分代码省略.........
开发者ID:PJMODOS,项目名称:postgres,代码行数:101,代码来源:array_userfuncs.c
示例10: elog
static
TableStatSnapshot *get_table_stat_snapshot()
{
int ret;
SPIPlanPtr planptr;
HASHCTL ctl;
TableStatSnapshot *snapshot;
if ((ret = SPI_connect()) < 0)
elog(ERROR, "could not connect to the SPI: %d", ret);
planptr = SPI_prepare("SELECT "
" relid, seq_scan, seq_tup_read, "
/* idx_* columns might be NULL if there are no indexes on the table */
" COALESCE(idx_scan, 0), COALESCE(idx_tup_fetch, 0), "
" n_tup_ins, n_tup_upd, n_tup_del "
"FROM "
" pg_stat_xact_user_tables "
"WHERE "
" relid <> 'call_graph.TableAccessBuffer'::regclass AND "
" relid <> 'call_graph.CallGraphBuffer'::regclass AND "
" GREATEST(seq_scan, idx_scan, n_tup_ins, n_tup_upd, n_tup_del) > 0 ",
0, NULL);
if (!planptr)
elog(ERROR, "could not prepare an SPI plan");
ret = SPI_execp(planptr, NULL, NULL, 0);
if (ret < 0)
elog(ERROR, "SPI_execp() failed: %d", ret);
/*
* We need to use TopTransactionContext explicitly for any allocations or else
* our memory will disappear after we call SPI_finish().
*/
snapshot = MemoryContextAlloc(TopTransactionContext, sizeof(TableStatSnapshot));
/* create the hash table */
memset(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(TableStatHashKey);
ctl.entrysize = sizeof(TableStatHashElem);
ctl.hash = tag_hash;
/* use TopTransactionContext for the hash table */
ctl.hcxt = TopTransactionContext;
snapshot->hash_table = hash_create("snapshot_hash_table", 32, &ctl, HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
if (ret > 0)
{
SPITupleTable *tuptable;
TupleDesc tupdesc;
int i;
int proc;
tuptable = SPI_tuptable;
if (!tuptable)
elog(ERROR, "SPI_tuptable == NULL");
tupdesc = tuptable->tupdesc;
proc = SPI_processed;
for (i = 0; i < proc; ++i)
{
HeapTuple tuple = tuptable->vals[i];
bool isnull;
bool found;
TableStatHashKey key;
TableStatHashElem* elem;
key.relid = DatumGetObjectId(SPI_getbinval(tuple, tupdesc, 1, &isnull));
Assert(!isnull);
elem = hash_search(snapshot->hash_table, (void *) &key, HASH_ENTER, &found);
if (found)
elog(ERROR, "oops");
else
{
elem->key = key;
elem->seq_scan = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 2, &found));
elem->seq_tup_read = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 3, &found));
elem->idx_scan = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 4, &found));
elem->idx_tup_fetch = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 5, &found));
elem->n_tup_ins = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 6, &found));
elem->n_tup_upd = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 7, &found));
elem->n_tup_del = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 8, &found));
}
}
snapshot->num_tables = proc;
}
SPI_finish();
/* freeze the hash table; nobody's going to modify it anymore */
hash_freeze(snapshot->hash_table);
return snapshot;
}
开发者ID:postsql,项目名称:call_graph,代码行数:96,代码来源:call_graph.c
示例11: GetComboCommandId
/*
* Get a combo command id that maps to cmin and cmax.
*
* We try to reuse old combo command ids when possible.
*/
static CommandId
GetComboCommandId(CommandId cmin, CommandId cmax)
{
CommandId combocid;
ComboCidKeyData key;
ComboCidEntry entry;
bool found;
/*
* Create the hash table and array the first time we need to use combo
* cids in the transaction.
*/
if (comboHash == NULL)
{
HASHCTL hash_ctl;
memset(&hash_ctl, 0, sizeof(hash_ctl));
hash_ctl.keysize = sizeof(ComboCidKeyData);
hash_ctl.entrysize = sizeof(ComboCidEntryData);
hash_ctl.hash = tag_hash;
hash_ctl.hcxt = TopTransactionContext;
comboHash = hash_create("Combo CIDs",
CCID_HASH_SIZE,
&hash_ctl,
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
comboCids = (ComboCidKeyData *)
MemoryContextAlloc(TopTransactionContext,
sizeof(ComboCidKeyData) * CCID_ARRAY_SIZE);
sizeComboCids = CCID_ARRAY_SIZE;
usedComboCids = 0;
}
/* Lookup or create a hash entry with the desired cmin/cmax */
/* We assume there is no struct padding in ComboCidKeyData! */
key.cmin = cmin;
key.cmax = cmax;
entry = (ComboCidEntry) hash_search(comboHash,
(void *) &key,
HASH_ENTER,
&found);
if (found)
{
/* Reuse an existing combo cid */
return entry->combocid;
}
/*
* We have to create a new combo cid. Check that there's room for it in
* the array, and grow it if there isn't.
*/
if (usedComboCids >= sizeComboCids)
{
/* We need to grow the array */
int newsize = sizeComboCids * 2;
comboCids = (ComboCidKeyData *)
repalloc(comboCids, sizeof(ComboCidKeyData) * newsize);
sizeComboCids = newsize;
}
combocid = usedComboCids;
comboCids[combocid].cmin = cmin;
comboCids[combocid].cmax = cmax;
usedComboCids++;
entry->combocid = combocid;
return combocid;
}
开发者ID:pgresql,项目名称:postgres-xl,代码行数:79,代码来源:combocid.c
示例12: json_populate_recordset
/*
* SQL function json_populate_recordset
*
* set fields in a set of records from the argument json,
* which must be an array of objects.
*
* similar to json_populate_record, but the tuple-building code
* is pushed down into the semantic action handlers so it's done
* per object in the array.
*/
Datum
json_populate_recordset(PG_FUNCTION_ARGS)
{
Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
text *json;
bool use_json_as_text;
ReturnSetInfo *rsi;
MemoryContext old_cxt;
Oid tupType;
int32 tupTypmod;
HeapTupleHeader rec;
TupleDesc tupdesc;
RecordIOData *my_extra;
int ncolumns;
JsonLexContext *lex;
JsonSemAction sem;
PopulateRecordsetState state;
use_json_as_text = PG_ARGISNULL(2) ? false : PG_GETARG_BOOL(2);
if (!type_is_rowtype(argtype))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("first argument must be a rowtype")));
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
(rsi->allowedModes & SFRM_Materialize) == 0 ||
rsi->expectedDesc == NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that "
"cannot accept a set")));
rsi->returnMode = SFRM_Materialize;
/*
* get the tupdesc from the result set info - it must be a record type
* because we already checked that arg1 is a record type.
*/
(void) get_call_result_type(fcinfo, NULL, &tupdesc);
state = palloc0(sizeof(populateRecordsetState));
sem = palloc0(sizeof(jsonSemAction));
/* make these in a sufficiently long-lived memory context */
old_cxt = MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
state->ret_tdesc = CreateTupleDescCopy(tupdesc);
BlessTupleDesc(state->ret_tdesc);
state->tuple_store =
tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
false, work_mem);
MemoryContextSwitchTo(old_cxt);
/* if the json is null send back an empty set */
if (PG_ARGISNULL(1))
PG_RETURN_NULL();
json = PG_GETARG_TEXT_P(1);
if (PG_ARGISNULL(0))
rec = NULL;
else
rec = PG_GETARG_HEAPTUPLEHEADER(0);
tupType = tupdesc->tdtypeid;
tupTypmod = tupdesc->tdtypmod;
ncolumns = tupdesc->natts;
lex = makeJsonLexContext(json, true);
/*
* 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;
//.........这里部分代码省略.........
开发者ID:TesterRandolph,项目名称:postgres-x2,代码行数:101,代码来源:jsonfuncs.c
示例13: json_populate_record
//.........这里部分代码省略.........
json_hash = get_json_object_as_hash(json, "json_populate_record", use_json_as_text);
/*
* if the input json is empty, we can only skip the rest if we were passed
* in a non-null record, since otherwise there may be issues with domain
* nulls.
*/
if (hash_get_num_entries(json_hash) == 0 && rec)
PG_RETURN_POINTER(rec);
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
ncolumns = tupdesc->natts;
if (rec)
{
/* Build a temporary HeapTuple control structure */
tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
ItemPointerSetInvalid(&(tuple.t_self));
tuple.t_tableOid = InvalidOid;
tuple.t_data = rec;
}
/*
* 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 = (bool *) palloc(ncolumns * sizeof(bool));
if (rec)
{
/* Break down the tuple into fields */
heap_deform_tuple(&tuple, tupdesc, values, nulls);
}
else
{
for (i = 0; i < ncolumns; ++i)
{
values[i] = (Datum) 0;
nulls[i] = true;
开发者ID:TesterRandolph,项目名称:postgres-x2,代码行数:67,代码来源:jsonfuncs.c
示例14: buildGpDtxProtocolCommand
/*
* Build a dtx protocol command string to be dispatched to QE.
*/
static char *
buildGpDtxProtocolCommand(struct CdbDispatcherState *ds,
DispatchCommandDtxProtocolParms * pDtxProtocolParms,
int *finalLen)
{
int dtxProtocolCommand = (int) pDtxProtocolParms->dtxProtocolCommand;
int flags = pDtxProtocolParms->flags;
char *dtxProtocolCommandLoggingStr = pDtxProtocolParms->dtxProtocolCommandLoggingStr;
char *gid = pDtxProtocolParms->gid;
int gxid = pDtxProtocolParms->gxid;
char *serializedDtxContextInfo = pDtxProtocolParms->serializedDtxContextInfo;
int serializedDtxContextInfoLen = pDtxProtocolParms->serializedDtxContextInfoLen;
int tmp = 0;
int len = 0;
int loggingStrLen = strlen(dtxProtocolCommandLoggingStr) + 1;
int gidLen = strlen(gid) + 1;
int total_query_len = 1 /* 'T' */ +
sizeof(len) +
sizeof(dtxProtocolCommand) +
sizeof(flags) +
sizeof(loggingStrLen) +
loggingStrLen +
sizeof(gidLen) +
gidLen +
sizeof(gxid) +
sizeof(serializedDtxContextInfoLen) +
serializedDtxContextInfoLen;
char *shared_query = NULL;
char *pos = NULL;
if (ds->dispatchStateContext == NULL)
ds->dispatchStateContext = AllocSetContextCreate(TopMemoryContext,
"Dispatch Context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
shared_query = MemoryContextAlloc(ds->dispatchStateContext, total_query_len);
pos = shared_query;
*pos++ = 'T';
pos += sizeof(len); /* placeholder for message length */
tmp = htonl(dtxProtocolCommand);
memcpy(pos, &tmp, sizeof(tmp));
pos += sizeof(tmp);
tmp = htonl(flags);
memcpy(pos, &tmp, sizeof(tmp));
pos += sizeof(tmp);
tmp = htonl(loggingStrLen);
memcpy(pos, &tmp, sizeof(tmp));
pos += sizeof(tmp);
memcpy(pos, dtxProtocolCommandLoggingStr, loggingStrLen);
pos += loggingStrLen;
tmp = htonl(gidLen);
memcpy(pos, &tmp, sizeof(tmp));
pos += sizeof(tmp);
memcpy(pos, gid, gidLen);
pos += gidLen;
tmp = htonl(gxid);
memcpy(pos, &tmp, sizeof(tmp));
pos += sizeof(tmp);
tmp = htonl(serializedDtxContextInfoLen);
memcpy(pos, &tmp, sizeof(tmp));
pos += sizeof(tmp);
if (serializedDtxContextInfoLen > 0)
{
memcpy(pos, serializedDtxContextInfo, serializedDtxContextInfoLen);
pos += serializedDtxContextInfoLen;
}
len = pos - shared_query - 1;
/*
* fill in length placeholder
*/
tmp = htonl(len);
memcpy(shared_query + 1, &tmp, sizeof(tmp));
if (finalLen)
*finalLen = len + 1;
return shared_query;
}
开发者ID:asubramanya,项目名称:gpdb,代码行数:98,代码来源:cdbdisp_dtx.c
示例15: record_recv
/*
* 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;
bool *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 = (bool *) palloc(ncolumns * sizeof(bool));
/* 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;
//.........这里部分代码省略.........
开发者ID:AnLingm,项目名称:gpdb,代码行数:101,代码来源:rowtypes.c
示例16: array_positions
/*-----------------------------------------------------------------------------
* array_positions :
* return an array of positions of a value in an array.
*
* IS NOT DISTINCT FROM semantics are used for comparisons. Returns NULL when
* the input array is NULL. When the value is not found in the array, returns
* an empty array.
*
* This is not strict so we have to test for null inputs explicitly.
*-----------------------------------------------------------------------------
*/
Datum
array_positions(PG_FUNCTION_ARGS)
{
ArrayType *array;
Oid collation = PG_GET_COLLATION();
Oid element_type;
Datum searched_element,
value;
bool isnull;
int position;
TypeCacheEntry *typentry;
ArrayMetaState *my_extra;
bool null_search;
ArrayIterator array_iterator;
ArrayBuildState *astate = NULL;
if (PG_ARGISNULL(0))
PG_RETURN_NULL();
array = PG_GETARG_ARRAYTYPE_P(0);
element_type = ARR_ELEMTYPE(array);
position = (ARR_LBOUND(array))[0] - 1;
/*
* We refuse to search for elements in multi-dimensional arrays, since we
* have no good way to report the element's location in the array.
*/
if (ARR_NDIM(array) > 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("searching for elements in multidimensional arrays is not supported")));
astate = initArrayResult(INT4OID, CurrentMemoryContext, false);
if (PG_ARGISNULL(1))
{
/* fast return when the array doesn't have have nulls */
if (!array_contains_nulls(array))
PG_RETURN_DATUM(makeArrayResult(astate, CurrentMemoryContext));
searched_element = (Datum) 0;
null_search = true;
}
else
{
searched_element = PG_GETARG_DATUM(1);
null_search = false;
}
/*
* We arrange to look up type info for array_create_iterator only once per
* series of calls, assuming the element type doesn't change underneath us.
*/
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
if (my_extra == NULL)
{
fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
sizeof(ArrayMetaState));
my_extra = (ArrayMetaState *) fcinfo->flinfo->fn_extra;
my_extra->element_type = ~element_type;
}
if (my_extra->element_type != element_type)
{
get_typlenbyvalalign(element_type,
&my_extra->typlen,
&my_extra->typbyval,
&my_extra->typalign);
typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO);
if (!OidIsValid(typentry->eq_opr_finfo.fn_oid))
ereport(ERROR,
(errcode(ERRCO
|
请发表评论