//
// (C) Copyright 2003-2009 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data.Odbc;
using System.Windows.Forms;
using System.Resources;
using System.Collections;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Data;
namespace Revit.SDK.Samples.RDBLink.CS
{
///
/// Provides method to pop up ODBC data source selection dialog.
///
public class SQLDriver
{
#region Fields
//driver completion modes
const ushort SQL_DRIVER_NOPROMPT = 0;
const ushort SQL_DRIVER_COMPLETE = 1;
const ushort SQL_DRIVER_PROMPT = 2;
const ushort SQL_DRIVER_COMPLETE_REQUIRED = 3;
const short SQL_NTS = -3;
/* FreeStmt() options */
const short SQL_CLOSE = 0;
const short SQL_DROP = 1;
const short SQL_UNBIND = 2;
const short SQL_RESET_PARAMS = 3;
//return values
const short SQL_SUCCESS = 0;
const short SQL_SUCCESS_WITH_INFO = 1;
const short SQL_STILL_EXECUTING = 2;
const short SQL_NEED_DATA = 99;
const short SQL_NO_DATA = 100;
const short SQL_ERROR = (-1);
const short SQL_INVALID_HANDLE = (-2);
//handles
static IntPtr environmentHandle = IntPtr.Zero;
static IntPtr connectionHandle = IntPtr.Zero;
static IntPtr stmtHandle = IntPtr.Zero;
//allocated flag
static bool isAllocated;
#endregion
#region Methods
#region Win32API
///
/// Get current window handle
///
/// Current window handle
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
///
/// SQLDriverConnect is an alternative to SQLConnect. It supports data sources that
/// require more connection information than the three arguments in SQLConnect,
/// dialog boxes to prompt the user for all connection information,
/// and data sources that are not defined in the system information.
///
/// Connection handle.
/// Window handle.
/// A full connection string, a partial connection string,
/// or an empty string.
/// Length of *InConnectionString, in characters.
/// A buffer for the completed connection string.
/// Length of the *OutConnectionString buffer.
/// A buffer in which to return the total number of characters
/// (excluding the null-termination character)
/// available to return in *OutConnectionString.
/// flag that indicates whether the Driver Manager or
/// driver must prompt for more connection information.
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_ERROR,
/// or SQL_INVALID_HANDLE.
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
static extern short SQLDriverConnect(IntPtr hdbc,
IntPtr hwnd,
string szConnStrIn,
short cbConnStrIn,
StringBuilder szConnStrOut,
short cbConnStrOutMax,
out short pcbConnStrOut,
ushort fDriverCompletion);
///
/// Releases a connection handle and frees all memory associated with the handle.
///
/// ConnectionHandle
/// SQL_SUCCESS, SQL_ERROR, or SQL_INVALID_HANDLE.
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
static extern short SQLFreeConnect(IntPtr ConnectionHandle);
///
/// closes the connection associated with a specific connection handle.
///
/// ConnectionHandle
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
static extern short SQLDisconnect(IntPtr ConnectionHandle);
///
/// Frees an given ODBC Environment handle
///
/// EnvironmentHandle
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
static extern short SQLFreeEnv(IntPtr EnvironmentHandle);
///
/// Allocates memory for an environment handle and initializes the ODBC call level
/// interface for use by an application.
///
/// EnvironmentHandle
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR
[DllImport("odbc32.dll")]
static extern short SQLAllocEnv(out IntPtr EnvironmentHandle);
///
/// Allocates memory for a connection handle within the environment.
///
/// EnvironmentHandle
/// ConnectionHandle
[DllImport("odbc32.dll")]
static extern short SQLAllocConnect(IntPtr EnvironmentHandle, out IntPtr ConnectionHandle);
///
/// Allocates a new statement handle and associates it with the connection
/// specified by the connection handle.
///
/// Connection handle
/// Statement handle
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR
[DllImport("odbc32.dll")]
static extern short SQLAllocStmt(IntPtr ConnectionHandle, out IntPtr StmtHandle);
///
/// Free (or Reset) a Statement Handle,
/// Ends processing on the statement referenced by the statement handle.
/// Use this function to: Close a cursor,Reset parameters
/// and Unbind columns from variables.
///
/// Statement handle.
/// Option specifying the manner
/// of freeing the statement handle.
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR
[DllImport("odbc32.dll")]
static extern short SQLFreeStmt(IntPtr StmtHandle, short Option);
///
/// Execute SQL statement directly.
///
/// Statement handle
/// Statement content
/// Statement text length
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
static extern short SQLExecDirect(IntPtr StatementHandle,
string StatementText, int TextLength);
///
/// Returns a list of table names and associated information
/// stored in the system catalogs of the connected data source.
///
/// Statement handle
/// Buffer that may contain a pattern-value
/// to qualify the result set. Catalog is the first part of a three-part table name.
/// This must be a NULL pointer or a zero length string.
/// Length of CatalogName. This must be set to 0.
/// Buffer that may contain a pattern-value to qualify
/// the result set by schema name.
/// Length of SchemaName.
/// Buffer that may contain a pattern-value
/// to qualify the result set by table name.
/// Length of TableName.
/// Buffer that may contain a value list to qualify
/// the result set by table type.
/// Size of Table type.
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE, or SQL_ERROR
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
static extern short SQLTables(IntPtr StatementHandle, string CatalogName,
short NameLength1, string SchemaName, short NameLength2, string TableName,
short NameLength3, string TableType, short NameLength4);
///
/// Returns a list of columns in the specified tables.
///
/// Statement handle.
/// Catalog name
/// Catalog name length
/// Schema name
/// Schema name length
/// Table name
/// Table name length
/// Column name
/// Column name length
///
[DllImport("odbc32.dll", CharSet = CharSet.Unicode)]
static extern short SQLColumns(IntPtr StatementHandle,
string CatalogName, short NameLength1, string SchemaName, short NameLength2,
string TableName, short NameLength3, string ColumnName, short NameLength4);
///
/// Advances the cursor to the next row of the result set, and retrieves any bound columns.
///
/// Statement handle.
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_INVALID_HANDLE,
/// SQL_NO_DATA_FOUND, or SQL_ERROR.
[DllImport("odbc32.dll")]
static extern short SQLFetch(IntPtr StatementHandle);
///
/// Closes the open cursor on a statement handle.
///
/// Statement handle.
/// SQL_SUCCESS, SQL_INVALID_HANDLE, or SQL_ERROR
[DllImport("odbc32.dll")]
static extern short SQLCloseCursor(IntPtr StatementHandle);
///
/// Returns general information (including supported data conversions)
/// about the DBMS to which the application is connected.
///
/// Database connection handle
/// The type of information desired. The argument
/// must be one of the values in the first column of the tables in Data
/// Types and Data Conversion.
/// Pointer to buffer where this function stores
/// the necessary information.
/// Maximum size of the buffer pointed to by
/// rgbInfoValue.
/// Pointer to location where this function returns
/// the total number of bytes available to return the desired information.
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO , SQL_INVALID_HANDLE,
/// or SQL_ERROR
[DllImport("odbc32.dll", EntryPoint = "SQLGetInfo")]
static extern short SQLGetInfo(IntPtr sqlHdbc, short fInfoType,
[Out] StringBuilder rgbInfoValue, short cbInfoValueMax, out short pcbInfoValue);
#endregion
///
/// Verify value is SQL_SUCCESS or SQL_SUCCESS_WITH_INFO
///
/// value to verify
/// true if value is SQL_SUCCESS or SQL_SUCCESS_WITH_INFO
static bool IsOK(int value)
{
return value == SQL_SUCCESS || value == SQL_SUCCESS_WITH_INFO;
}
///
/// Initializes environment, allocate memory for environment and connection
///
/// true if initialize successfully
static bool Initialize()
{
if (!isAllocated)
{
if (!IsOK(SQLAllocEnv(out environmentHandle)))
{
return false;
}
if (!IsOK(SQLAllocConnect(environmentHandle, out connectionHandle)))
{
return false;
}
isAllocated = true;
}
return true;
}
///
/// Connect a database and return the connection string
///
/// A full connection string, a partial connection string,
/// or an empty string.
/// flag that indicates whether the Driver Manager or
/// driver must prompt for more connection information.
/// The completed connection string
/// SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_ERROR,
/// or SQL_INVALID_HANDLE.
static int Connect(string in_connect, ushort driverCompletion, ref string retConnStr)
{
retConnStr = string.Empty;
const short MAX_CONNECT_LEN = 1024;
StringBuilder out_connect = new StringBuilder(MAX_CONNECT_LEN);
short len = 0;
int retval = SQL_ERROR;
// initializes environment
if (!Initialize())
return retval;
// pop up dialog for user to select data source
retval = SQLDriverConnect(connectionHandle,
GetActiveWindow(),
in_connect,
(short)in_connect.Length,
out_connect,
MAX_CONNECT_LEN,
out len,
driverCompletion);
retConnStr = out_connect.ToString();
if (IsOK(SQLAllocStmt(connectionHandle, out stmtHandle)))
{
}
return retval;
}
///
/// Execute SQL statement.
///
/// SQL statement.
public bool ExecuteSQL(string sqlStmt)
{
short status = SQLExecDirect(stmtHandle, sqlStmt, sqlStmt.Length);
return IsOK(status);
}
///
/// Return whether the table exist in database.
///
/// Table name.
/// True of False.
public bool TableExist(string tableName)
{
short status = SQLTables(stmtHandle, null, 0, null, 0, tableName, SQL_NTS, null, 0);
if (!IsOK(status))
{
SQLCloseCursor(stmtHandle);
return false;
}
else
{
status = SQLFetch(stmtHandle);
if (IsOK(status))
{
SQLCloseCursor(stmtHandle);
return true;
}
else
{
SQLCloseCursor(stmtHandle);
return false;
}
}
}
///
/// Judge whether the column exist in data table or not.
///
/// Data table name
/// Column name
/// True or False
public bool ColumnExist(string tableName, string columnName)
{
short status = SQLColumns(stmtHandle, null, 0, null, 0,
tableName, SQL_NTS, columnName, SQL_NTS);
if (!IsOK(status))
{
SQLCloseCursor(stmtHandle);
return false;
}
else
{
status = SQLFetch(stmtHandle);
if (IsOK(status))
{
SQLCloseCursor(stmtHandle);
return true;
}
else
{
SQLCloseCursor(stmtHandle);
return false;
}
}
}
///
/// Close connection and free memory
///
public void Terminate()
{
if (stmtHandle.ToInt32() != 0)
{
SQLFreeStmt(stmtHandle, SQL_CLOSE);
stmtHandle = IntPtr.Zero;
}
if (connectionHandle.ToInt32() != 0)
{
SQLDisconnect(connectionHandle);
}
if (connectionHandle.ToInt32() != 0)
{
SQLFreeConnect(connectionHandle);
connectionHandle = IntPtr.Zero;
}
if (environmentHandle.ToInt32() != 0)
{
SQLFreeEnv(environmentHandle);
environmentHandle = IntPtr.Zero;
}
isAllocated = false;
}
///
/// Pop up data source dialog to select a data source and return connection string.
///
/// Connection string of selected data source
/// Selected database type
public DatabaseType SelectDatabase(ref string connectStr)
{
int state = SQLDriver.Connect("", SQLDriver.SQL_DRIVER_PROMPT, ref connectStr);
if (state != SQLDriver.SQL_SUCCESS && state != SQLDriver.SQL_SUCCESS_WITH_INFO)
{
return DatabaseType.Invalid;
}
short MaxLength = 1000;
StringBuilder value = new StringBuilder(MaxLength);
short SQL_DBMS_NAME = 17;
short retv = 0;
SQLGetInfo(connectionHandle, SQL_DBMS_NAME, value, MaxLength, out retv);
switch (value.ToString())
{
case "Microsoft SQL Server":
return DatabaseType.SQLServer;
case "ACCESS":
return DatabaseType.MSAccess;
default:
return DatabaseType.Invalid;
}
}
#endregion
}
///
/// Indicates supported databases
///
public enum DatabaseType
{
///
/// Default
///
Invalid,
///
/// SQLServer is supported
///
SQLServer,
///
/// Microsoft Access is supported
///
MSAccess
}
}