pgtclcmds.c

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

C
2,082
字号
	-getTuple tupleNumber				returns the values of the tuple in a list	-tupleArray tupleNumber arrayName				stores the values of the tuple in array arrayName, indexed				by the attributes returned	-attributes				returns a list of the name/type pairs of the tuple attributes	-lAttributes				returns a list of the {name type len} entries of the tuple				attributes	-clear		clear the result buffer. Do not reuse after this **********************************/intPg_result(ClientData cData, Tcl_Interp *interp, int argc, CONST84 char *argv[]){	PGresult   *result;	const char *opt;	int			i;	int			tupno;	CONST84 char *arrVar;	char		nameBuffer[256];	const char *appendstr;	if (argc < 3 || argc > 5)	{		Tcl_AppendResult(interp, "Wrong # of arguments\n", 0);		goto Pg_result_errReturn;		/* append help info */	}	result = PgGetResultId(interp, argv[1]);	if (result == (PGresult *) NULL)	{		Tcl_AppendResult(interp, "\n",						 argv[1], " is not a valid query result", 0);		return TCL_ERROR;	}	opt = argv[2];	if (strcmp(opt, "-status") == 0)	{		Tcl_AppendResult(interp, PQresStatus(PQresultStatus(result)), 0);		return TCL_OK;	}	else if (strcmp(opt, "-error") == 0)	{		Tcl_SetResult(interp, (char *) PQresultErrorMessage(result),					  TCL_STATIC);		return TCL_OK;	}	else if (strcmp(opt, "-conn") == 0)		return PgGetConnByResultId(interp, argv[1]);	else if (strcmp(opt, "-oid") == 0)	{		sprintf(interp->result, "%u", PQoidValue(result));		return TCL_OK;	}	else if (strcmp(opt, "-clear") == 0)	{		PgDelResultId(interp, argv[1]);		PQclear(result);		return TCL_OK;	}	else if (strcmp(opt, "-numTuples") == 0)	{		sprintf(interp->result, "%d", PQntuples(result));		return TCL_OK;	}	else if (strcmp(opt, "-cmdTuples") == 0)	{		sprintf(interp->result, "%s", PQcmdTuples(result));		return TCL_OK;	}	else if (strcmp(opt, "-numAttrs") == 0)	{		sprintf(interp->result, "%d", PQnfields(result));		return TCL_OK;	}	else if (strcmp(opt, "-assign") == 0)	{		if (argc != 4)		{			Tcl_AppendResult(interp, "-assign option must be followed by a variable name", 0);			return TCL_ERROR;		}		arrVar = argv[3];		/*		 * this assignment assigns the table of result tuples into a giant		 * array with the name given in the argument. The indices of the		 * array are of the form (tupno,attrName). Note we expect field		 * names not to exceed a few dozen characters, so truncating to		 * prevent buffer overflow shouldn't be a problem.		 */		for (tupno = 0; tupno < PQntuples(result); tupno++)		{			for (i = 0; i < PQnfields(result); i++)			{				sprintf(nameBuffer, "%d,%.200s", tupno, PQfname(result, i));				if (Tcl_SetVar2(interp, arrVar, nameBuffer,#ifdef TCL_ARRAYS								tcl_value(PQgetvalue(result, tupno, i)),#else								PQgetvalue(result, tupno, i),#endif								TCL_LEAVE_ERR_MSG) == NULL)					return TCL_ERROR;			}		}		Tcl_AppendResult(interp, arrVar, 0);		return TCL_OK;	}	else if (strcmp(opt, "-assignbyidx") == 0)	{		if (argc != 4 && argc != 5)		{			Tcl_AppendResult(interp, "-assignbyidx option requires an array name and optionally an append string", 0);			return TCL_ERROR;		}		arrVar = argv[3];		appendstr = (argc == 5) ? (const char *) argv[4] : "";		/*		 * this assignment assigns the table of result tuples into a giant		 * array with the name given in the argument.  The indices of the		 * array are of the form (field0Value,attrNameappendstr). Here, we		 * still assume PQfname won't exceed 200 characters, but we dare		 * not make the same assumption about the data in field 0 nor the		 * append string.		 */		for (tupno = 0; tupno < PQntuples(result); tupno++)		{			const char *field0 =#ifdef TCL_ARRAYS			tcl_value(PQgetvalue(result, tupno, 0));#else			PQgetvalue(result, tupno, 0);#endif			char	   *workspace = malloc(strlen(field0) + strlen(appendstr) + 210);			for (i = 1; i < PQnfields(result); i++)			{				sprintf(workspace, "%s,%.200s%s", field0, PQfname(result, i),						appendstr);				if (Tcl_SetVar2(interp, arrVar, workspace,#ifdef TCL_ARRAYS								tcl_value(PQgetvalue(result, tupno, i)),#else								PQgetvalue(result, tupno, i),#endif								TCL_LEAVE_ERR_MSG) == NULL)				{					free(workspace);					return TCL_ERROR;				}			}			free(workspace);		}		Tcl_AppendResult(interp, arrVar, 0);		return TCL_OK;	}	else if (strcmp(opt, "-getTuple") == 0)	{		if (argc != 4)		{			Tcl_AppendResult(interp, "-getTuple option must be followed by a tuple number", 0);			return TCL_ERROR;		}		tupno = atoi(argv[3]);		if (tupno < 0 || tupno >= PQntuples(result))		{			Tcl_AppendResult(interp, "argument to getTuple cannot exceed number of tuples - 1", 0);			return TCL_ERROR;		}#ifdef TCL_ARRAYS		for (i = 0; i < PQnfields(result); i++)			Tcl_AppendElement(interp, tcl_value(PQgetvalue(result, tupno, i)));#else		for (i = 0; i < PQnfields(result); i++)			Tcl_AppendElement(interp, PQgetvalue(result, tupno, i));#endif		return TCL_OK;	}	else if (strcmp(opt, "-tupleArray") == 0)	{		if (argc != 5)		{			Tcl_AppendResult(interp, "-tupleArray option must be followed by a tuple number and array name", 0);			return TCL_ERROR;		}		tupno = atoi(argv[3]);		if (tupno < 0 || tupno >= PQntuples(result))		{			Tcl_AppendResult(interp, "argument to tupleArray cannot exceed number of tuples - 1", 0);			return TCL_ERROR;		}		for (i = 0; i < PQnfields(result); i++)		{			if (Tcl_SetVar2(interp, argv[4], PQfname(result, i),#ifdef TCL_ARRAYS							tcl_value(PQgetvalue(result, tupno, i)),#else							PQgetvalue(result, tupno, i),#endif							TCL_LEAVE_ERR_MSG) == NULL)				return TCL_ERROR;		}		return TCL_OK;	}	else if (strcmp(opt, "-attributes") == 0)	{		for (i = 0; i < PQnfields(result); i++)			Tcl_AppendElement(interp, PQfname(result, i));		return TCL_OK;	}	else if (strcmp(opt, "-lAttributes") == 0)	{		for (i = 0; i < PQnfields(result); i++)		{			/* start a sublist */			if (i > 0)				Tcl_AppendResult(interp, " {", 0);			else				Tcl_AppendResult(interp, "{", 0);			Tcl_AppendElement(interp, PQfname(result, i));			sprintf(nameBuffer, "%ld", (long) PQftype(result, i));			Tcl_AppendElement(interp, nameBuffer);			sprintf(nameBuffer, "%ld", (long) PQfsize(result, i));			Tcl_AppendElement(interp, nameBuffer);			/* end the sublist */			Tcl_AppendResult(interp, "}", 0);		}		return TCL_OK;	}	else	{		Tcl_AppendResult(interp, "Invalid option\n", 0);		goto Pg_result_errReturn;		/* append help info */	}Pg_result_errReturn:	Tcl_AppendResult(interp,					 "pg_result result ?option? where option is\n",					 "\t-status\n",					 "\t-error\n",					 "\t-conn\n",					 "\t-oid\n",					 "\t-numTuples\n",					 "\t-cmdTuples\n",					 "\t-numAttrs\n"					 "\t-assign arrayVarName\n",					 "\t-assignbyidx arrayVarName ?appendstr?\n",					 "\t-getTuple tupleNumber\n",					 "\t-tupleArray tupleNumber arrayVarName\n",					 "\t-attributes\n"					 "\t-lAttributes\n"					 "\t-clear\n",					 (char *) 0);	return TCL_ERROR;}/********************************** * pg_execute send a query string to the backend connection and process the result syntax: pg_execute ?-array name? ?-oid varname? connection query ?loop_body? the return result is the number of tuples processed. If the query returns tuples (i.e. a SELECT statement), the result is placed into variables **********************************/intPg_execute(ClientData cData, Tcl_Interp *interp, int argc, CONST84 char *argv[]){	Pg_ConnectionId *connid;	PGconn	   *conn;	PGresult   *result;	int			i;	int			tupno;	int			ntup;	int			loop_rc;	CONST84 char *oid_varname = NULL;	CONST84 char *array_varname = NULL;	char		buf[64];	char	   *usage = "Wrong # of arguments\n"	"pg_execute ?-array arrayname? ?-oid varname? "	"connection queryString ?loop_body?";	/*	 * First we parse the options	 */	i = 1;	while (i < argc)	{		if (argv[i][0] != '-')			break;		if (strcmp(argv[i], "-array") == 0)		{			/*			 * The rows should appear in an array vs. to single variables			 */			i++;			if (i == argc)			{				Tcl_SetResult(interp, usage, TCL_VOLATILE);				return TCL_ERROR;			}			array_varname = argv[i++];			continue;		}		if (strcmp(argv[i], "-oid") == 0)		{			/*			 * We should place PQoidValue() somewhere			 */			i++;			if (i == argc)			{				Tcl_SetResult(interp, usage, TCL_VOLATILE);				return TCL_ERROR;			}			oid_varname = argv[i++];			continue;		}		Tcl_AppendResult(interp, "Unknown option '", argv[i], "'", NULL);		return TCL_ERROR;	}	/*	 * Check that after option parsing at least 'connection' and 'query'	 * are left	 */	if (argc - i < 2)	{		Tcl_SetResult(interp, usage, TCL_VOLATILE);		return TCL_ERROR;	}	/*	 * Get the connection and make sure no COPY command is pending	 */	conn = PgGetConnectionId(interp, argv[i++], &connid);	if (conn == (PGconn *) NULL)		return TCL_ERROR;	if (connid->res_copyStatus != RES_COPY_NONE)	{		Tcl_SetResult(interp, "Attempt to query while COPY in progress", TCL_STATIC);		return TCL_ERROR;	}	/*	 * Execute the query	 */	result = PQexec(conn, argv[i++]);	/*	 * Transfer any notify events from libpq to Tcl event queue.	 */	PgNotifyTransferEvents(connid);	/*	 * Check for errors	 */	if (result == NULL)	{		Tcl_SetResult(interp, PQerrorMessage(conn), TCL_VOLATILE);		return TCL_ERROR;	}	/*	 * Set the oid variable to the returned oid of an INSERT statement if	 * requested (or 0 if it wasn't an INSERT)	 */	if (oid_varname != NULL)	{		char		oid_buf[32];		sprintf(oid_buf, "%u", PQoidValue(result));		if (Tcl_SetVar(interp, oid_varname, oid_buf,					   TCL_LEAVE_ERR_MSG) == NULL)		{			PQclear(result);			return TCL_ERROR;		}	}	/*	 * Decide how to go on based on the result status	 */	switch (PQresultStatus(result))	{		case PGRES_TUPLES_OK:			/* fall through if we have tuples */			break;		case PGRES_EMPTY_QUERY:		case PGRES_COMMAND_OK:		case PGRES_COPY_IN:		case PGRES_COPY_OUT:			/* tell the number of affected tuples for non-SELECT queries */			Tcl_SetResult(interp, PQcmdTuples(result), TCL_VOLATILE);			PQclear(result);			return TCL_OK;		default:			/* anything else must be an error */			Tcl_ResetResult(interp);			Tcl_AppendElement(interp, PQresStatus(PQresultStatus(result)));			Tcl_AppendElement(interp, PQresultErrorMessage(result));			PQclear(result);			return TCL_ERROR;	}	/*	 * We reach here only for queries that returned tuples	 */	if (i == argc)	{		/*		 * We don't have a loop body. If we have at least one result row,		 * we set all the variables to the first one and return.		 */		if (PQntuples(result) > 0)		{			if (execute_put_values(interp, array_varname, result, 0) != TCL_OK)			{				PQclear(result);				return TCL_ERROR;			}		}		sprintf(buf, "%d", PQntuples(result));		Tcl_SetResult(interp, buf, TCL_VOLATILE);		PQclear(result);		return TCL_OK;	}	/*	 * We have a loop body. For each row in the result set put the values	 * into the Tcl variables and execute the body.	 */	ntup = PQntuples(result);	for (tupno = 0; tupno < ntup; tupno++)	{		if (execute_put_values(interp, array_varname, result, tupno) != TCL_OK)		{			PQclear(result);			return TCL_ERROR;		}		loop_rc = Tcl_Eval(interp, argv[i]);		/* The returncode of the loop body controls the loop execution */		if (loop_rc == TCL_OK || loop_rc == TCL_CONTINUE)			/* OK or CONTINUE means start next loop invocation */			continue;		if (loop_rc == TCL_RETURN)		{			/* RETURN means hand up the given interpreter result */			PQclear(result);			return TCL_RETURN;		}		if (loop_rc == TCL_BREAK)			/* BREAK means leave the loop */			break;		PQclear(result);		return TCL_ERROR;	}	/*	 * At the end of the loop we put the number of rows we got into the	 * interpreter result and clear the result set.	 */	sprintf(buf, "%d", ntup);	Tcl_SetResult(interp, buf, TCL_VOLATILE);	PQclear(result);	return TCL_OK;}/********************************** * execute_put_values Put the values of one tuple into Tcl variables named like the column names, or into an array indexed by the column names. **********************************/static intexecute_put_values(Tcl_Interp *interp, CONST84 char *array_varname,				   PGresult *result, int tupno){	int			i;	int			n;	char	   *fname;	char	   *value;	/*	 * For each column get the column name and value and put it into a Tcl	 * variable (either scalar or array item)	 */	n = PQnfields(result);	for (i = 0; i < n; i++)	{

⌨️ 快捷键说明

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