⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbxpostg.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
字号:
/****************************************************************************
*																			*
*						cryptlib Postgres Mapping Routines					*
*						Copyright Peter Gutmann 1996-1999					*
*																			*
****************************************************************************/

/* TODO:

  - All of the functions are only about 98% complete (I lost the use of the
	Postgres systems before I was finished).
  - The code could be rewritten to use dlopen() in a similar manner to the
	ODBC linking under Windows.
*/

#include <stdio.h>
#include <string.h>
#include "crypt.h"
#include "keyset/keyset.h"

/****************************************************************************
*																			*
*							Unix Database Access Functions					*
*																			*
****************************************************************************/

#ifdef USE_POSTGRES

/* Postgres has a few odd variations on standard SQL.  It implements a number
   of SQL primitives as inbuilt functions rather than proper primitives,
   which means they're case-sensitive.  In order for them to be recognised we
   have to convert them to lowercase before we can execute them (the only one
   we actually use is COUNT).  In addition, for CREATE INDEX statements it
   requires a USING clause (this may be a bug in the 1.08 parser rather than
   a feature, but it also allows us to specify the use of a hash index which
   is the best choice for the guaranteed-unique values we're building the
   index on).

   The following function looks for these special cases and converts the
   query into the format required by Postgres */

static void convertQuery( char *query, const char *command )
	{
	char *strPtr;

	strcpy( query, command );
	if( !strncmp( command, "CREATE TABLE", 12 ) )
		{
		char *blobName = strstr( query, " BLOB " );

		if( blobName != NULL )
			{
			memmove( blobName + 15, blobName + 6, strlen( blobName + 6 ) );
			strncpy( blobName, " VARCHAR(2048) ", 15 );
			}
		}
	if( ( strPtr = strstr( query, "COUNT" ) ) != NULL )
		strncpy( strPtr, "count", 5 );
	if( ( strPtr = strstr( query, "CREATE INDEX" ) ) != NULL )
		{
		strPtr = strchr( query, '(' );
		memmove( strPtr + 11, strPtr, strlen( strPtr ) + 1 );
		strncpy( strPtr, "USING hash ", 11 );
		strPtr = strchr( query, ')' );
		memmove( strPtr + 9, strPtr, strlen( strPtr ) + 1 );
		strncpy( strPtr, " text_ops", 9 );
		}
	}

/* Get information on a Postgres error */

static int getErrorInfo( DBMS_STATE_INFO *dbmsInfo, const int defaultStatus )
	{
	/* Postgres has an annoying non-unified error indication system in which
	   an error code can mean different things depending on what the current
	   usage context is, so we need to get error information in a context-
	   specific manner */
	if( dbmsInfo->pgResult )
		{
		strncpy( dbmsInfo->errorMessage, PQcmdStatus( dbmsInfo->pgResult ),
				 MAX_ERRMSG_SIZE - 1 );
		dbmsInfo->errorCode = PQresultStatus( dbmsInfo->pgResult );

		/* Now that we've got the information, clear the result */
		PQclear( dbmsInfo->pgResult );
		dbmsInfo->pgResult = NULL;
		}
	else
		{
		strncpy( dbmsInfo->errorMessage, PQerrorMessage( dbmsInfo->pgConnection ),
				 MAX_ERRMSG_SIZE - 1 );
		dbmsInfo->errorCode = PQstatus( dbmsInfo->pgConnection );

		/* At the PGconn level, the only information Postgres can return is
		   "connection OK" or "connection bad", so we have to pick apart the
		   returned error message to find out what went wrong.  This is
		   pretty nasty since it may break if the error messages are ever
		   changed */
		if( strstr( dbmsInfo->errorMessage, "no such class" ) != NULL || \
			strstr( dbmsInfo->errorMessage, "not found" ) != NULL )
			{
			dbmsInfo->errorMessage[ 0 ] = '\0';
			return( CRYPT_ERROR_NOTFOUND );
			}
		}
	dbmsInfo->errorMessage[ MAX_ERRMSG_SIZE - 1 ] = '\0';

	return( defaultStatus );
	}

/* Open and close a connection to a Postgres server */

static int openDatabase( DBMS_STATE_INFO *dbmsInfo, const char *name,
						 const int options, int *featureFlags )
	{
	int status;

	UNUSED( user );
	UNUSED( password );
	UNUSED( options );

	/* Connect to the Postgres server */
	dbmsInfo->pgConnection = PQsetdb( server, NULL, NULL, NULL, name );
	if( PQstatus( dbmsInfo->pgConnection ) == CONNECTION_BAD )
		{
		PQfinish( dbmsInfo->pgConnection );
		dbmsInfo->pgConnection = NULL;
		return( CRYPT_ERROR_OPEN );
		}
	*featureFlags = DBMS_HAS_NONE;

	return( CRYPT_OK );
	}

static void closeDatabase( DBMS_STATE_INFO *dbmsInfo )
	{
	PQfinish( dbmsInfo->pgConnection );
	dbmsInfo->pgConnection = NULL;
	}

/* Perform a transaction which updates the database without returning any
   data */

static int performUpdate( DBMS_STATE_INFO *dbmsInfo, const char *command,
						  const void *boundData, const int boundDataLength,
						  const time_t boundDate )
	{
	char query[ MAX_SQL_QUERY_SIZE ];

	assert( boundData == NULL );

/* !!!! Need to convert date data, see dbxmysql.c !!!! */

	/* Submit the query to the Postgres server */
	convertQuery( query, command );
	dbmsInfo->pgResult = PQexec( dbmsInfo->pgConnection, query );
	if( dbmsInfo->pgResult == NULL )
		{
		DEBUG( puts( "performUpdate:PQexec() failed" ) );
		return( getErrorInfo( dbmsInfo, CRYPT_ERROR_WRITE ) );
		}

	/* Since this doesn't return any results, all we need to do is clear the
	   result to free the PGresult storage */
	PQclear( dbmsInfo->pgResult );
	dbmsInfo->pgResult = NULL;

	return( CRYPT_OK );
	}

/* Perform a transaction which returns information */

static int performQuery( DBMS_STATE_INFO *dbmsInfo, const char *command,
						 char *data, int *dataLength,
						 const DBMS_QUERY_TYPE queryType )
	{
	char query[ MAX_SQL_QUERY_SIZE ];
	int status = CRYPT_OK;

	/* If this assertion triggers, you need to add handling for the other
	   query types.  See keyset/keyset.h and keyset/dbxodbc.c for guidance */
	assert( queryType == DBMS_QUERY_NORMAL );

	/* Submit the query to the Postgres server */
	convertQuery( query, command );
	dbmsInfo->pgResult = PQexec( dbmsInfo->pgConnection, query );
	if( dbmsInfo->pgResult == NULL )
		return( getErrorInfo( dbmsInfo, CRYPT_ERROR_READ ) );

	/* Make sure the query completed successfully */
	if( PQresultStatus( dbmsInfo->pgResult ) != PGRES_TUPLES_OK )
		{
		status = getErrorInfo( dbmsInfo, CRYPT_ERROR_NOTFOUND );
		PQclear( dbmsInfo->pgResult );
		dbmsInfo->pgResult = NULL;
		return( status );
		}

	/* Get the result of the query and clear the result */
/*	*dataLength = PQgetlength( dbmsInfo->pgResult, 0, 0 ); */
/* !!!! Is this the right function !!!! */
	*dataLength = PQfsize( dbmsInfo->pgResult, 0 );
	if( *dataLength > MAX_CERT_SIZE )
		{
		*dataLength = 0;
		status = CRYPT_ERROR_OVERFLOW;
		}
	else
		strcpy( data, PQgetvalue( dbmsInfo->pgResult, 1, 1 ) );
	PQclear( dbmsInfo->pgResult );
	dbmsInfo->pgResult = NULL;

	return( CRYPT_OK );
	}

/* Perform a transaction which checks for the existence of an object */

static int performCheck( DBMS_STATE_INFO *dbmsInfo, const char *command )
	{
	char query[ MAX_SQL_QUERY_SIZE ];
	int count, status;

	/* Submit the query to the Postgres server */
	convertQuery( query, command );
	dbmsInfo->pgResult = PQexec( dbmsInfo->pgConnection, query );
	if( dbmsInfo->pgResult == NULL )
		return( getErrorInfo( dbmsInfo, CRYPT_ERROR_READ ) );

	/* Check whether the query completed successfully */
	status = PQresultStatus( dbmsInfo->pgResult );
	if( status != PGRES_TUPLES_OK )
		status = getErrorInfo( dbmsInfo, CRYPT_ERROR_NOTFOUND );
	else
		status = CRYPT_OK;
	PQclear( dbmsInfo->pgResult );
	dbmsInfo->pgResult = NULL;
	return( status );
	}

/* Fetch extended error information from the database state info */

static void performErrorQuery( DBMS_STATE_INFO *dbmsInfo, int *errorCode,
							   char *errorMessage )
	{
	*errorCode = dbmsInfo->errorCode;
	strcpy( errorMessage, dbmsInfo->errorMessage );
	}

/* Pull in the shared database RPC routines */

#include "dbx_rpc.c"

#endif /* USE_POSTGRES */

⌨️ 快捷键说明

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