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

📄 sql-wrap.c

📁 OpenLdap是LDAP的开源项目
💻 C
字号:
/* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/sql-wrap.c,v 1.28.2.9 2007/08/22 21:37:58 ando Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 1999-2007 The OpenLDAP Foundation. * Portions Copyright 1999 Dmitry Kovalev. * Portions Copyright 2002 Pierangelo Masarati. * Portions Copyright 2004 Mark Adamson. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by Dmitry Kovalev for inclusion * by OpenLDAP Software.  Additional significant contributors include * Pierangelo Masarati and Mark Adamson. */#include "portable.h"#include <stdio.h>#include "ac/string.h"#include <sys/types.h>#include "slap.h"#include "proto-sql.h"#define MAX_ATTR_LEN 16384typedef struct backsql_db_conn {	unsigned long	ldap_cid;	SQLHDBC		dbh;} backsql_db_conn;voidbacksql_PrintErrors( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT sth, int rc ){	SQLCHAR	msg[SQL_MAX_MESSAGE_LENGTH];		/* msg. buffer    */	SQLCHAR	state[SQL_SQLSTATE_SIZE];		/* statement buf. */	SDWORD	iSqlCode;				/* return code    */	SWORD	len = SQL_MAX_MESSAGE_LENGTH - 1;	/* return length  */ 	Debug( LDAP_DEBUG_TRACE, "Return code: %d\n", rc, 0, 0 );	for ( ; rc = SQLError( henv, hdbc, sth, state, &iSqlCode, msg,		SQL_MAX_MESSAGE_LENGTH - 1, &len ), BACKSQL_SUCCESS( rc ); )	{		Debug( LDAP_DEBUG_TRACE,			"   nativeErrCode=%d SQLengineState=%s msg=\"%s\"\n",			(int)iSqlCode, state, msg );	}}RETCODEbacksql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char *query, int timeout ){	RETCODE		rc;	rc = SQLAllocStmt( dbh, sth );	if ( rc != SQL_SUCCESS ) {		return rc;	}#ifdef BACKSQL_TRACE	Debug( LDAP_DEBUG_TRACE, "==>backsql_Prepare()\n", 0, 0, 0 );#endif /* BACKSQL_TRACE */#ifdef BACKSQL_MSSQL_WORKAROUND	{		char		drv_name[ 30 ];		SWORD		len;		SQLGetInfo( dbh, SQL_DRIVER_NAME, drv_name, sizeof( drv_name ), &len );#ifdef BACKSQL_TRACE		Debug( LDAP_DEBUG_TRACE, "backsql_Prepare(): driver name=\"%s\"\n",				drv_name, 0, 0 );#endif /* BACKSQL_TRACE */		ldap_pvt_str2upper( drv_name );		if ( !strncmp( drv_name, "SQLSRV32.DLL", STRLENOF( "SQLSRV32.DLL" ) ) ) {			/*			 * stupid default result set in MS SQL Server			 * does not support multiple active statements			 * on the same connection -- so we are trying 			 * to make it not to use default result set...			 */			Debug( LDAP_DEBUG_TRACE, "_SQLprepare(): "				"enabling MS SQL Server default result "				"set workaround\n", 0, 0, 0 );			rc = SQLSetStmtOption( *sth, SQL_CONCURRENCY, 					SQL_CONCUR_ROWVER );			if ( rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {				Debug( LDAP_DEBUG_TRACE, "backsql_Prepare(): "					"SQLSetStmtOption(SQL_CONCURRENCY,"					"SQL_CONCUR_ROWVER) failed:\n", 					0, 0, 0 );				backsql_PrintErrors( SQL_NULL_HENV, dbh, *sth, rc );				SQLFreeStmt( *sth, SQL_DROP );				return rc;			}		}	}#endif /* BACKSQL_MSSQL_WORKAROUND */	if ( timeout > 0 ) {		Debug( LDAP_DEBUG_TRACE, "_SQLprepare(): "			"setting query timeout to %d sec.\n", 			timeout, 0, 0 );		rc = SQLSetStmtOption( *sth, SQL_QUERY_TIMEOUT, timeout );		if ( rc != SQL_SUCCESS ) {			backsql_PrintErrors( SQL_NULL_HENV, dbh, *sth, rc );			SQLFreeStmt( *sth, SQL_DROP );			return rc;		}	}#ifdef BACKSQL_TRACE	Debug( LDAP_DEBUG_TRACE, "<==backsql_Prepare() calling SQLPrepare()\n",			0, 0, 0 );#endif /* BACKSQL_TRACE */	return SQLPrepare( *sth, (SQLCHAR *)query, SQL_NTS );}RETCODEbacksql_BindRowAsStrings_x( SQLHSTMT sth, BACKSQL_ROW_NTS *row, void *ctx ){	RETCODE		rc;	SQLCHAR		colname[ 64 ];	SQLSMALLINT	name_len, col_type, col_scale, col_null;	UDWORD		col_prec;	int		i;	if ( row == NULL ) {		return SQL_ERROR;	}#ifdef BACKSQL_TRACE	Debug( LDAP_DEBUG_TRACE, "==> backsql_BindRowAsStrings()\n", 0, 0, 0 );#endif /* BACKSQL_TRACE */		rc = SQLNumResultCols( sth, &row->ncols );	if ( rc != SQL_SUCCESS ) {#ifdef BACKSQL_TRACE		Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings(): "			"SQLNumResultCols() failed:\n", 0, 0, 0 );#endif /* BACKSQL_TRACE */				backsql_PrintErrors( SQL_NULL_HENV, SQL_NULL_HDBC, sth, rc );	} else {#ifdef BACKSQL_TRACE		Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: "			"ncols=%d\n", (int)row->ncols, 0, 0 );#endif /* BACKSQL_TRACE */		row->col_names = (BerVarray)ber_memcalloc_x( row->ncols + 1, 				sizeof( struct berval ), ctx );		if ( !row->col_names ) goto nomem3;		row->cols = (char **)ber_memcalloc_x( row->ncols + 1, 				sizeof( char * ), ctx );		if ( !row->cols ) goto nomem2;		row->col_prec = (UDWORD *)ber_memcalloc_x( row->ncols,				sizeof( UDWORD ), ctx );		if ( !row->col_prec ) goto nomem1;		row->value_len = (SQLINTEGER *)ber_memcalloc_x( row->ncols,				sizeof( SQLINTEGER ), ctx );		if ( !row->value_len ) {			ber_memfree_x( row->col_prec, ctx );			row->col_prec = NULL;nomem1:		ber_memfree_x( row->cols, ctx );			row->cols = NULL;nomem2:		ber_memfree_x( row->col_names, ctx );			row->col_names = NULL;nomem3:		Debug( LDAP_DEBUG_ANY, "backsql_BindRowAsStrings: "				"out of memory\n", 0, 0, 0 );			return LDAP_NO_MEMORY;		}		for ( i = 1; i <= row->ncols; i++ ) {			rc = SQLDescribeCol( sth, (SQLSMALLINT)i, &colname[ 0 ],					(SQLUINTEGER)( sizeof( colname ) - 1 ),					&name_len, &col_type,					&col_prec, &col_scale, &col_null );			/* FIXME: test rc? */			ber_str2bv_x( (char *)colname, 0, 1,					&row->col_names[ i - 1 ], ctx );#ifdef BACKSQL_TRACE			Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: "				"col_name=%s, col_prec[%d]=%d\n",				colname, (int)i, (int)col_prec );#endif /* BACKSQL_TRACE */			if ( col_type != SQL_CHAR && col_type != SQL_VARCHAR )			{				col_prec = MAX_ATTR_LEN;			}			row->cols[ i - 1 ] = (char *)ber_memcalloc_x( col_prec + 1,					sizeof( char ), ctx );			row->col_prec[ i - 1 ] = col_prec;			rc = SQLBindCol( sth, (SQLUSMALLINT)i,					 SQL_C_CHAR,					 (SQLPOINTER)row->cols[ i - 1 ],					 col_prec + 1,					 &row->value_len[ i - 1 ] );			/* FIXME: test rc? */		}		BER_BVZERO( &row->col_names[ i - 1 ] );		row->cols[ i - 1 ] = NULL;	}#ifdef BACKSQL_TRACE	Debug( LDAP_DEBUG_TRACE, "<== backsql_BindRowAsStrings()\n", 0, 0, 0 );#endif /* BACKSQL_TRACE */	return rc;}RETCODEbacksql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row ){	return backsql_BindRowAsStrings_x( sth, row, NULL );}RETCODEbacksql_FreeRow_x( BACKSQL_ROW_NTS *row, void *ctx ){	if ( row->cols == NULL ) {		return SQL_ERROR;	}	ber_bvarray_free_x( row->col_names, ctx );	ber_memvfree_x( (void **)row->cols, ctx );	ber_memfree_x( row->col_prec, ctx );	ber_memfree_x( row->value_len, ctx );	return SQL_SUCCESS;}RETCODEbacksql_FreeRow( BACKSQL_ROW_NTS *row ){	return backsql_FreeRow_x( row, NULL );}static intbacksql_cmp_connid( const void *v_c1, const void *v_c2 ){	const backsql_db_conn *c1 = v_c1, *c2 = v_c2;	if ( c1->ldap_cid > c2->ldap_cid ) {		return 1;	}		if ( c1->ldap_cid < c2->ldap_cid ) {		return -1;	}		return 0;}static voidbacksql_close_db_conn( void *v_conn ){	backsql_db_conn	*conn = 	(backsql_db_conn *)v_conn;	unsigned long	cid = conn->ldap_cid;	Debug( LDAP_DEBUG_TRACE, "==>backsql_close_db_conn(%lu)\n",		cid, 0, 0 );	/*	 * Default transact is SQL_ROLLBACK; commit is required only	 * by write operations, and it is explicitly performed after	 * each atomic operation succeeds.	 */	/* TimesTen */	SQLTransact( SQL_NULL_HENV, conn->dbh, SQL_ROLLBACK );	SQLDisconnect( conn->dbh );	SQLFreeConnect( conn->dbh );	ch_free( conn );	Debug( LDAP_DEBUG_TRACE, "<==backsql_close_db_conn(%lu)\n",		cid, 0, 0 );}intbacksql_conn_destroy(	backsql_info	*bi ){	avl_free( bi->sql_db_conns, backsql_close_db_conn );	return 0;}intbacksql_init_db_env( backsql_info *bi ){	RETCODE		rc;	int		ret = SQL_SUCCESS;		Debug( LDAP_DEBUG_TRACE, "==>backsql_init_db_env()\n", 0, 0, 0 );	rc = SQLAllocEnv( &bi->sql_db_env );	if ( rc != SQL_SUCCESS ) {		Debug( LDAP_DEBUG_TRACE, "init_db_env: SQLAllocEnv failed:\n",				0, 0, 0 );		backsql_PrintErrors( SQL_NULL_HENV, SQL_NULL_HDBC,				SQL_NULL_HENV, rc );		ret = SQL_ERROR;	}	Debug( LDAP_DEBUG_TRACE, "<==backsql_init_db_env()=%d\n", ret, 0, 0 );	return ret;}intbacksql_free_db_env( backsql_info *bi ){	Debug( LDAP_DEBUG_TRACE, "==>backsql_free_db_env()\n", 0, 0, 0 );	(void)SQLFreeEnv( bi->sql_db_env );	bi->sql_db_env = SQL_NULL_HENV;	/*	 * stop, if frontend waits for all threads to shutdown 	 * before calling this -- then what are we going to delete?? 	 * everything is already deleted...	 */	Debug( LDAP_DEBUG_TRACE, "<==backsql_free_db_env()\n", 0, 0, 0 );	return SQL_SUCCESS;}static intbacksql_open_db_conn( backsql_info *bi, unsigned long ldap_cid, backsql_db_conn **pdbc ){	/* TimesTen */	char			DBMSName[ 32 ];	SQLHDBC			dbh = SQL_NULL_HDBC;	backsql_db_conn		*dbc;	int			rc;	assert( pdbc != NULL );	*pdbc = NULL; 	Debug( LDAP_DEBUG_TRACE, "==>backsql_open_db_conn(%lu)\n",		ldap_cid, 0, 0 );	rc = SQLAllocConnect( bi->sql_db_env, &dbh );	if ( !BACKSQL_SUCCESS( rc ) ) {		Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): "			"SQLAllocConnect() failed:\n", ldap_cid, 0, 0 );		backsql_PrintErrors( bi->sql_db_env, SQL_NULL_HDBC,				SQL_NULL_HENV, rc );		return LDAP_UNAVAILABLE;	}	rc = SQLConnect( dbh,			(SQLCHAR*)bi->sql_dbname, SQL_NTS,			(SQLCHAR*)bi->sql_dbuser, SQL_NTS,			(SQLCHAR*)bi->sql_dbpasswd, SQL_NTS );	if ( rc != SQL_SUCCESS ) {		Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): "			"SQLConnect() to database \"%s\" %s.\n",			ldap_cid, bi->sql_dbname,			rc == SQL_SUCCESS_WITH_INFO ?			"succeeded with info" : "failed" );		backsql_PrintErrors( bi->sql_db_env, dbh, SQL_NULL_HENV, rc );		if ( rc != SQL_SUCCESS_WITH_INFO ) {			SQLFreeConnect( dbh );			return LDAP_UNAVAILABLE;		}	}	/* 	 * TimesTen : Turn off autocommit.  We must explicitly	 * commit any transactions. 	 */	SQLSetConnectOption( dbh, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF );	/* 	 * See if this connection is to TimesTen.  If it is,	 * remember that fact for later use.	 */	/* Assume until proven otherwise */	bi->sql_flags &= ~BSQLF_USE_REVERSE_DN;	DBMSName[ 0 ] = '\0';	rc = SQLGetInfo( dbh, SQL_DBMS_NAME, (PTR)&DBMSName,			sizeof( DBMSName ), NULL );	if ( rc == SQL_SUCCESS ) {		if ( strcmp( DBMSName, "TimesTen" ) == 0 ||				strcmp( DBMSName, "Front-Tier" ) == 0 ) {			Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): "				"TimesTen database!\n", ldap_cid, 0, 0 );			bi->sql_flags |= BSQLF_USE_REVERSE_DN;		}	} else {		Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): "			"SQLGetInfo() failed.\n", ldap_cid, 0, 0 );		backsql_PrintErrors( bi->sql_db_env, dbh, SQL_NULL_HENV, rc );	}	/* end TimesTen */	dbc = (backsql_db_conn *)ch_calloc( 1, sizeof( backsql_db_conn ) );	dbc->ldap_cid = ldap_cid;	dbc->dbh = dbh;	*pdbc = dbc;	Debug( LDAP_DEBUG_TRACE, "<==backsql_open_db_conn(%lu)\n", ldap_cid, 0, 0 );	return rc;}intbacksql_free_db_conn( Operation *op ){	backsql_info		*bi = (backsql_info *)op->o_bd->be_private;	backsql_db_conn		tmp = { 0 },				*conn;	Debug( LDAP_DEBUG_TRACE, "==>backsql_free_db_conn()\n", 0, 0, 0 );	tmp.ldap_cid = op->o_connid;	ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex );	conn = avl_delete( &bi->sql_db_conns, &tmp, backsql_cmp_connid );	ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex );	/*	 * we have one thread per connection, as I understand -- so we can	 * get this out of critical section	 */	if ( conn != NULL ) {		Debug( LDAP_DEBUG_TRACE, "backsql_free_db_conn(): "			"closing db connection %lu (%p)\n",			op->o_connid, (void *)conn, 0 );		backsql_close_db_conn( (void *)conn );	}	Debug( LDAP_DEBUG_TRACE, "<==backsql_free_db_conn()\n", 0, 0, 0 );	return conn ? SQL_SUCCESS : SQL_ERROR;}intbacksql_get_db_conn( Operation *op, SQLHDBC *dbh ){	backsql_info		*bi = (backsql_info *)op->o_bd->be_private;	backsql_db_conn		*dbc,				tmp = { 0 };	int			rc = LDAP_SUCCESS;	Debug( LDAP_DEBUG_TRACE, "==>backsql_get_db_conn()\n", 0, 0, 0 );	assert( dbh != NULL );	*dbh = SQL_NULL_HDBC;	tmp.ldap_cid = op->o_connid;	/*	 * we have one thread per connection, as I understand -- 	 * so we do not need locking here	 */	ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex );	dbc = avl_find( bi->sql_db_conns, &tmp, backsql_cmp_connid );	ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex );	if ( !dbc ) {		rc = backsql_open_db_conn( bi, op->o_connid, &dbc );		if ( rc != LDAP_SUCCESS) {			Debug( LDAP_DEBUG_TRACE, "backsql_get_db_conn(): "				"could not get connection handle "				"-- returning NULL\n", 0, 0, 0 );			return rc;		} else {			int	ret;			Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): "				"connected, adding to tree.\n",				op->o_connid, 0, 0 );			ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex );			ret = avl_insert( &bi->sql_db_conns, dbc, backsql_cmp_connid, avl_dup_error );			ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex );			if ( ret != 0 ) {				Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(%lu): "					"duplicate connection ID.\n",					op->o_connid, 0, 0 );				backsql_close_db_conn( (void *)dbc );				dbc = NULL;				return LDAP_OTHER;			}		}	}	*dbh = dbc->dbh;	Debug( LDAP_DEBUG_TRACE, "<==backsql_get_db_conn()\n", 0, 0, 0 );	return LDAP_SUCCESS;}

⌨️ 快捷键说明

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