fe-exec.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,443 行 · 第 1/4 页

C
2,443
字号
	else		return NULL;}/* * PQfnumber: find column number given column name * * The column name is parsed as if it were in a SQL statement, including * case-folding and double-quote processing.  But note a possible gotcha: * downcasing in the frontend might follow different locale rules than * downcasing in the backend... * * Returns -1 if no match.  In the present backend it is also possible * to have multiple matches, in which case the first one is found. */intPQfnumber(const PGresult *res, const char *field_name){	char	   *field_case;	bool		in_quotes;	char	   *iptr;	char	   *optr;	int			i;	if (!res)		return -1;	/*	 * Note: it is correct to reject a zero-length input string; the proper	 * input to match a zero-length field name would be "".	 */	if (field_name == NULL ||		field_name[0] == '\0' ||		res->attDescs == NULL)		return -1;	/*	 * Note: this code will not reject partially quoted strings, eg	 * foo"BAR"foo will become fooBARfoo when it probably ought to be	 * an error condition.	 */	field_case = strdup(field_name);	if (field_case == NULL)		return -1;				/* grotty */	in_quotes = false;	optr = field_case;	for (iptr = field_case; *iptr; iptr++)	{		char	c = *iptr;		if (in_quotes)		{			if (c == '"')			{				if (iptr[1] == '"')				{					/* doubled quotes become a single quote */					*optr++ = '"';					iptr++;				}				else					in_quotes = false;			}			else				*optr++ = c;		}		else if (c == '"')		{			in_quotes = true;		}		else		{			if (isupper((unsigned char) c))				c = tolower((unsigned char) c);			*optr++ = c;		}	}	*optr = '\0';	for (i = 0; i < res->numAttributes; i++)	{		if (strcmp(field_case, res->attDescs[i].name) == 0)		{			free(field_case);			return i;		}	}	free(field_case);	return -1;}OidPQftable(const PGresult *res, int field_num){	if (!check_field_number(res, field_num))		return InvalidOid;	if (res->attDescs)		return res->attDescs[field_num].tableid;	else		return InvalidOid;}intPQftablecol(const PGresult *res, int field_num){	if (!check_field_number(res, field_num))		return 0;	if (res->attDescs)		return res->attDescs[field_num].columnid;	else		return 0;}intPQfformat(const PGresult *res, int field_num){	if (!check_field_number(res, field_num))		return 0;	if (res->attDescs)		return res->attDescs[field_num].format;	else		return 0;}OidPQftype(const PGresult *res, int field_num){	if (!check_field_number(res, field_num))		return InvalidOid;	if (res->attDescs)		return res->attDescs[field_num].typid;	else		return InvalidOid;}intPQfsize(const PGresult *res, int field_num){	if (!check_field_number(res, field_num))		return 0;	if (res->attDescs)		return res->attDescs[field_num].typlen;	else		return 0;}intPQfmod(const PGresult *res, int field_num){	if (!check_field_number(res, field_num))		return 0;	if (res->attDescs)		return res->attDescs[field_num].atttypmod;	else		return 0;}char *PQcmdStatus(PGresult *res){	if (!res)		return NULL;	return res->cmdStatus;}/* * PQoidStatus - *	if the last command was an INSERT, return the oid string *	if not, return "" */char *PQoidStatus(const PGresult *res){	/*	 * This must be enough to hold the result. Don't laugh, this is better	 * than what this function used to do.	 */	static char buf[24];	size_t		len;	if (!res || !res->cmdStatus || strncmp(res->cmdStatus, "INSERT ", 7) != 0)		return "";	len = strspn(res->cmdStatus + 7, "0123456789");	if (len > 23)		len = 23;	strncpy(buf, res->cmdStatus + 7, len);	buf[len] = '\0';	return buf;}/* * PQoidValue - *	a perhaps preferable form of the above which just returns *	an Oid type */OidPQoidValue(const PGresult *res){	char	   *endptr = NULL;	unsigned long result;	if (!res || !res->cmdStatus || strncmp(res->cmdStatus, "INSERT ", 7) != 0)		return InvalidOid;#ifdef WIN32	SetLastError(0);#else	errno = 0;#endif	result = strtoul(res->cmdStatus + 7, &endptr, 10);	if (!endptr || (*endptr != ' ' && *endptr != '\0') || errno == ERANGE)		return InvalidOid;	else		return (Oid) result;}/* * PQcmdTuples - *	If the last command was an INSERT/UPDATE/DELETE/MOVE/FETCH, return a *	string containing the number of inserted/affected tuples. If not, *	return "". * *	XXX: this should probably return an int */char *PQcmdTuples(PGresult *res){	char	   *p;	if (!res)		return "";	if (strncmp(res->cmdStatus, "INSERT ", 7) == 0)	{		p = res->cmdStatus + 6;		p++;		/* INSERT: skip oid */		while (*p != ' ' && *p)			p++;	}	else if (strncmp(res->cmdStatus, "DELETE ", 7) == 0 ||			 strncmp(res->cmdStatus, "UPDATE ", 7) == 0)		p = res->cmdStatus + 6;	else if (strncmp(res->cmdStatus, "FETCH ", 6) == 0)		p = res->cmdStatus + 5;	else if (strncmp(res->cmdStatus, "MOVE ", 5) == 0)		p = res->cmdStatus + 4;	else		return "";	p++;	if (*p == 0)	{		pqInternalNotice(&res->noticeHooks,						 "could not interpret result from server: %s",						 res->cmdStatus);		return "";	}	return p;}/* * PQgetvalue: *	return the value of field 'field_num' of row 'tup_num' */char *PQgetvalue(const PGresult *res, int tup_num, int field_num){	if (!check_tuple_field_number(res, tup_num, field_num))		return NULL;	return res->tuples[tup_num][field_num].value;}/* PQgetlength: *	returns the actual length of a field value in bytes. */intPQgetlength(const PGresult *res, int tup_num, int field_num){	if (!check_tuple_field_number(res, tup_num, field_num))		return 0;	if (res->tuples[tup_num][field_num].len != NULL_LEN)		return res->tuples[tup_num][field_num].len;	else		return 0;}/* PQgetisnull: *	returns the null status of a field value. */intPQgetisnull(const PGresult *res, int tup_num, int field_num){	if (!check_tuple_field_number(res, tup_num, field_num))		return 1;				/* pretend it is null */	if (res->tuples[tup_num][field_num].len == NULL_LEN)		return 1;	else		return 0;}/* PQsetnonblocking: *	sets the PGconn's database connection non-blocking if the arg is TRUE *	or makes it non-blocking if the arg is FALSE, this will not protect *	you from PQexec(), you'll only be safe when using the non-blocking API. *	Needs to be called only on a connected database connection. */intPQsetnonblocking(PGconn *conn, int arg){	bool	barg;	if (!conn || conn->status == CONNECTION_BAD)		return -1;	barg = (arg ? TRUE : FALSE);	/* early out if the socket is already in the state requested */	if (barg == conn->nonblocking)		return (0);	/*	 * to guarantee constancy for flushing/query/result-polling behavior	 * we need to flush the send queue at this point in order to guarantee	 * proper behavior. this is ok because either they are making a	 * transition _from_ or _to_ blocking mode, either way we can block	 * them.	 */	/* if we are going from blocking to non-blocking flush here */	if (pqFlush(conn))		return (-1);	conn->nonblocking = barg;	return (0);}/* * return the blocking status of the database connection *		TRUE == nonblocking, FALSE == blocking */intPQisnonblocking(const PGconn *conn){	return (pqIsnonblocking(conn));}/* try to force data out, really only useful for non-blocking users */intPQflush(PGconn *conn){	return (pqFlush(conn));}/* *		PQfreemem - safely frees memory allocated * * Needed mostly by Win32, unless multithreaded DLL (/MD in VC6) * Used for freeing memory from PQescapeByte()a/PQunescapeBytea() */voidPQfreemem(void *ptr){	free(ptr);}/* * PQfreeNotify - free's the memory associated with a PGnotify * * This function is here only for binary backward compatibility. * New code should use PQfreemem().  A macro will automatically map * calls to PQfreemem.	It should be removed in the future.  bjm 2003-03-24 */#undef PQfreeNotifyvoid		PQfreeNotify(PGnotify *notify);voidPQfreeNotify(PGnotify *notify){	PQfreemem(notify);}/* * Escaping arbitrary strings to get valid SQL literal strings. * * Replaces "\\" with "\\\\" and "'" with "''". * * length is the length of the source string.  (Note: if a terminating NUL * is encountered sooner, PQescapeString stops short of "length"; the behavior * is thus rather like strncpy.) * * For safety the buffer at "to" must be at least 2*length + 1 bytes long. * A terminating NUL character is added to the output string, whether the * input is NUL-terminated or not. * * Returns the actual length of the output (not counting the terminating NUL). */size_tPQescapeString(char *to, const char *from, size_t length){	const char *source = from;	char	   *target = to;	size_t		remaining = length;	while (remaining > 0 && *source != '\0')	{		switch (*source)		{			case '\\':				*target++ = '\\';				*target++ = '\\';				break;			case '\'':				*target++ = '\'';				*target++ = '\'';				break;			default:				*target++ = *source;				break;		}		source++;		remaining--;	}	/* Write the terminating NUL character. */	*target = '\0';	return target - to;}/* *		PQescapeBytea	- converts from binary string to the *		minimal encoding necessary to include the string in an SQL *		INSERT statement with a bytea type column as the target. * *		The following transformations are applied *		'\0' == ASCII  0 == \\000 *		'\'' == ASCII 39 == \' *		'\\' == ASCII 92 == \\\\ *		anything < 0x20, or > 0x7e ---> \\ooo *                                      (where ooo is an octal expression) */unsigned char *PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen){	const unsigned char *vp;	unsigned char *rp;	unsigned char *result;	size_t		i;	size_t		len;	/*	 * empty string has 1 char ('\0')	 */	len = 1;	vp = bintext;	for (i = binlen; i > 0; i--, vp++)	{		if (*vp < 0x20 || *vp > 0x7e)			len += 5;			/* '5' is for '\\ooo' */		else if (*vp == '\'')			len += 2;		else if (*vp == '\\')			len += 4;		else			len++;	}	rp = result = (unsigned char *) malloc(len);	if (rp == NULL)		return NULL;	vp = bintext;	*bytealen = len;	for (i = binlen; i > 0; i--, vp++)	{		if (*vp < 0x20 || *vp > 0x7e)		{			(void) sprintf(rp, "\\\\%03o", *vp);			rp += 5;		}		else if (*vp == '\'')		{			rp[0] = '\\';			rp[1] = '\'';			rp += 2;		}		else if (*vp == '\\')		{			rp[0] = '\\';			rp[1] = '\\';			rp[2] = '\\';			rp[3] = '\\';			rp += 4;		}		else			*rp++ = *vp;	}	*rp = '\0';	return result;}#define ISFIRSTOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '3')#define ISOCTDIGIT(CH) ((CH) >= '0' && (CH) <= '7')#define OCTVAL(CH) ((CH) - '0')/* *		PQunescapeBytea - converts the null terminated string representation *		of a bytea, strtext, into binary, filling a buffer. It returns a *		pointer to the buffer (or NULL on error), and the size of the *		buffer in retbuflen. The pointer may subsequently be used as an *		argument to the function free(3). It is the reverse of PQescapeBytea. * *		The following transformations are made: *		\\	 == ASCII 92 == \ *		\ooo == a byte whose value = ooo (ooo is an octal number) *		\x	 == x (x is any character not matched by the above transformations) */unsigned char *PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen){	size_t		strtextlen,				buflen;	unsigned char *buffer,			   *tmpbuf;	size_t		i,				j;	if (strtext == NULL)		return NULL;	strtextlen = strlen(strtext);	/*	 * Length of input is max length of output, but add one to avoid	 * unportable malloc(0) if input is zero-length.	 */	buffer = (unsigned char *) malloc(strtextlen + 1);	if (buffer == NULL)		return NULL;	for (i = j = 0; i < strtextlen; )	{		switch (strtext[i])		{			case '\\':				i++;				if (strtext[i] == '\\')					buffer[j++] = strtext[i++];				else				{					if ((ISFIRSTOCTDIGIT(strtext[i])) &&						(ISOCTDIGIT(strtext[i + 1])) &&						(ISOCTDIGIT(strtext[i + 2])))					{						int		byte;						byte = OCTVAL(strtext[i++]);						byte = (byte << 3) + OCTVAL(strtext[i++]);						byte = (byte << 3) + OCTVAL(strtext[i++]);						buffer[j++] = byte;					}				}				/*				 * Note: if we see '\' followed by something that isn't				 * a recognized escape sequence, we loop around having				 * done nothing except advance i.  Therefore the something				 * will be emitted as ordinary data on the next cycle.				 * Corner case: '\' at end of string will just be discarded.				 */				break;			default:				buffer[j++] = strtext[i++];				break;		}	}	buflen = j;					/* buflen is the length of the dequoted								 * data */	/* Shrink the buffer to be no larger than necessary */	/* +1 avoids unportable behavior when buflen==0 */	tmpbuf = realloc(buffer, buflen + 1);	/* It would only be a very brain-dead realloc that could fail, but... */	if (!tmpbuf)	{		free(buffer);		return NULL;	}	*retbuflen = buflen;	return tmpbuf;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?