//
// DTSPump.h
//	Header file for the OLEDB DTSDataPump Service Provider.
//	Copyright 1997 Microsoft Corporation
//
#ifndef DTSDataPump_H_
#pragma option push -b -a8 -pc -A- /*P_O_Push*/
#define DTSDataPump_H_

#ifndef DTSDataPumpVersion_Major
	#define DTSDataPumpVersion_Major 1
	#define DTSDataPumpVersion_Minor 0
#endif // DTSDataPumpVersion_Major

#ifndef DTSDataPump_VersionOnly

// The default Blob size used in this version of the DataPump.
// May be overridden on a per-Transform or per-column basis.
#define DTS_DEFAULT_INMEMORY_BLOB_SIZE (1024 * 1024)

// Default number of successful InsertRows which will be Committed if supported by provider.
// Currently set to 0 which means not to do a commit until all rows have been transferred.
#define DTS_DEFAULT_InsertCommitSize	0

///////////////////////////////////////////////////////////////////////////////////////
// CPP and OleAut Enumerations and constants.
///////////////////////////////////////////////////////////////////////////////////////
#ifndef DTSDataPump_CONSTANTS_
#define DTSDataPump_CONSTANTS_

// To avoid the need to cast on bitwise operations (which defeats typesafety anyway),
// define the datatype as DWORD for C/CPP.  OleAut languages don't do typechecking
// and organize by the enum name.
#ifdef DTSDataPump_ODL_
	#define DP_ENUM_BEGIN(tdef, hstring)	[helpcontext(H_##tdef), helpstring(hstring)] enum tdef
		// item = value, ...
	#define DP_ENUM_END(tdef)				tdef, *LP##tdef
#else
	#define DP_ENUM_BEGIN(tdef, hstring)	DWORD tdef, *LP##tdef; enum tag##tdef
		// item = value, ...
	#define DP_ENUM_END(tdef)				
#endif

typedef DP_ENUM_BEGIN(DTSDataPumpError, "Error ranges for DTSDataPump execution") {
	DTSDataPump_E_NotImplemented				= 0x2000,
	DTSDataPump_E_RowsetsAlreadySet				= 0x2001,
	DTSDataPump_E_TransformsAlreadySet			= 0x2002,
	DTSDataPump_E_DestRowsetNotSupplied			= 0x2003,
	DTSDataPump_E_RowsetsNotSupplied			= 0x2004,
	DTSDataPump_E_SourceColumnsRequired			= 0x2005,
	DTSDataPump_E_ColCountButNoCols				= 0x2006,
	DTSDataPump_E_MismatchColOrdAndName			= 0x2007,
	DTSDataPump_E_ColumnNameNotFound			= 0x2008,
	DTSDataPump_E_ColumnOutOfRange				= 0x2009,
	DTSDataPump_E_DestColumnAlreadySpecified	= 0x200a,
	DTSDataPump_E_IDataConvertRequired			= 0x200b,
	DTSDataPump_E_NullVariantIUnknown			= 0x200c,
	DTSDataPump_E_NotReentrant					= 0x200d,
	DTSDataPump_E_RowsetChangeMustInsert		= 0x200e,
	DTSDataPump_E_DataPumpNotReentrant			= 0x200f,
	DTSDataPump_E_DestColumnReadOnly			= 0x2010,
	DTSDataPump_E_MustSpecifyDestOrTransform	= 0x2011,
	DTSDataPump_E_BadTransformFlag				= 0x2012,
	DTSDataPump_E_BadTransformStatusReturned	= 0x2013,
	DTSDataPump_E_TransformServerException		= 0x2014,
	DTSDataPump_E_CannotRebindColumn			= 0x2015,
	DTSDataPump_E_InvalidFetchBufferSize		= 0x2016,
	DTSDataPump_E_InvalidDTSBindMode			= 0x2017,
	DTSDataPump_E_SourceBlobBinding				= 0x2018,
	DTSDataPump_E_NonBlobStorageBind			= 0x2019,
	DTSDataPump_E_LookupDupName					= 0x201a,

	DTSDataPump_E_DestinationBlobBinding		= 0x2020,

	DTSDataPump_E_Copy_NeedSrcAndDestColumns	= 0x2024,
	DTSDataPump_E_Copy_ValidateSchemaError		= 0x2025,

	DTSDataPump_E_Convert_DestNotNull			= 0x2026,
	DTSDataPump_E_Convert_BadBindInfo			= 0x2027,
	DTSDataPump_E_Convert_DestOverflow			= 0x2028,
	DTSDataPump_E_Convert_SourceInvalidVariant	= 0x2029,
	DTSDataPump_E_Convert_SourceInvalidLength	= 0x202a,
	DTSDataPump_E_Convert_ConversionInvalid		= 0x202b,
	DTSDataPump_E_Convert_ConversionFailed		= 0x202c,
	DTSDataPump_E_Convert_ProviderOwnedTypeMismatch	= 0x202d,
	DTSDataPump_E_Convert_BlobStorageNoInterface	= 0x202e,

	DTSDataPump_E_AxScript_RequiredParams		= 0x2040,
	DTSDataPump_E_AxScript_ValidateSchemaError	= 0x2041,
	DTSDataPump_E_AxScript_ParseError			= 0x2042,
	DTSDataPump_E_AxScript_BadTransformFunction	= 0x2043,
	DTSDataPump_E_AxScript_CantChangeSrcCols	= 0x2044,
	DTSDataPump_E_AxScript_CantResetAfterInitialize	= 0x2045,
	DTSDataPump_E_AxScript_CantInitializeEngine	= 0x2046,
	DTSDataPump_E_AxScript_RunTimeError			= 0x2047,

	DTSDataPump_E_AutoBufferInterfaceNotSupported	= 0x2051,
	DTSDataPump_E_InvalidSpecifyBlobDefaults	= 0x2051,
	DTSDataPump_E_LineageVariableNotFound		= 0x2052,
	DTSDataPump_E_LastRowCantBeLessThanFirst	= 0x2053,

	DTSDataPump_E_DDQ_NeedTransformStatus		= 0x2060,
	DTSDataPump_E_DDQ_NeedInsertQuery			= 0x2061,
	DTSDataPump_E_DDQ_NeedUpdateQuery			= 0x2062,
	DTSDataPump_E_DDQ_NeedDeleteQuery			= 0x2063,
	DTSDataPump_E_DDQ_NeedUserQuery				= 0x2064,
	DTSDataPump_E_DDQ_InformationNotSet			= 0x2065,
	DTSDataPump_E_DDQ_BadTransformStatusContext	= 0x2065,
	DTSDataPump_E_DDQ_DestColumnNotTransformed	= 0x2066,
	DTSDataPump_E_DDQ_DestColumnNeedsLength		= 0x2067,
	DTSDataPump_E_DDQ_DestDoesNotSupportSQL		= 0x2068,

} DP_ENUM_END(DTSDataPumpError);

// These allow definition of how the transform will proceed.
typedef DP_ENUM_BEGIN(DTSTransformFlags, "Flags (int or long) controlling Transform") {
	// No flags are specified; essentially, the conversion must be between exact types.
	// Note that this allows string <--> nonstring conversions, because every nonstring datatype
	// has a meaningful string representation.  This may be overridden by RequireExactType,
	// which is even stricter.
	DTSTransformFlag_Strict						= 0x00000000,

	// This flag means that IDTSDataPumpTransform::ValidateSchema should allow the transfer to proceed 
	// even if there are potential overflows, under the assumption that the consumer is aware of this but
	// knows the source values are all (or mostly) within the destination column’s range.  Any overflows during
	// transformation will cause the row to be exceptioned.  This flag is generally of interest only to 
	// the IID_IDTSDataPumpTransformCopy implementation, as this is a direct copy, whereas other
	// implementations would probably convert the values or determine validity on a specific case-by-case basis.
	// This value is also used for date/time conversions which result in loss, such as DATE -> DBTIME,
	// where a subset of the source value is still meaningful.
	DTSTransformFlag_AllowDemotion 				= 0x00000001,

	// This flag means that IDTSDataPumpTransform::ValidateSchema should allow the transfer to proceed 
	// when there is promotion in the data range when moving from the source to the destination types,
	// such as I2->I4 or I4->float/double.  Note that in some cases, such as I4->R4, the data range
	// increases but at the loss of some digits of precision.
	// If AllowLossless is specified, this is allowed by the Transform.
	DTSTransformFlag_AllowPromotion 			= 0x00000002,

	// This flag allows column (w)char or byte data to be truncated silently, such as when moving data
	// from a char(60) to a char(40) column.  AllowDemotion is implied but overflow will be
	// silently truncated instead of causing an error.
	DTSTransformFlag_AllowStringTruncation 		= 0x00000004,

	// This flag means that IDTSDataPumpTransform::ValidateSchema should allow the transfer to proceed 
	// even in the event that the source is a floating-point or numeric/decimal type and the destination
	// is an integral type.  This is a numeric flavour of AllowDemotion and will not cause an error 
	// (integer overflow will still be an error; i.e. left-of-decimal digits are significant).
	DTSTransformFlag_AllowNumericTruncation		= 0x00000008,

	// This flag means that IDTSDataPumpTransform::ValidateSchema should allow the transfer to proceed 
	// even if the source column allows NULL values and the destination column does not.  As with
	// AllowDemotion, errors may be encountered during a transform.
	// If AllowLossless is specified, this is allowed by the Transform if going from nonNULLable to NULLable.
	DTSTransformFlag_AllowNullChange			= 0x00000010,

	// This flag means that IDTSDataPumpTransform::ValidateSchema should allow the transfer to proceed 
	// even in the event that the source and destination have a signed vs. unsigned mismatch.  As with
	// AllowDemotion, errors may be encountered during a transform.
	// If AllowLossless is specified, this is allowed by the Transform when going from unsigned to signed
	// with promotion (e.g. UI2 -> I4).
	DTSTransformFlag_AllowSignChange			= 0x00000020,

	// Require that the destination column's datatype be exactly the same as the source column's
	// (including length or precision/scale, fixed vs. variable length, sign, and nullability).
	// This overrides any other flags specified for column conversion validation.
	// Cannot be specified with ForceConvert.
	DTSTransformFlag_RequireExactType			= 0x00000040,

	// Allow the conversion to proceed at all times, even when the source and destination types are
	// fundamentally different.  Currently this applies to:
	//		<nonchar> <--> bytes:		Does a bitwise copy; caveats apply for endian, machine representations.
	//		int/real <--> date:			DATE is a double so this just converts between int and double.
	//		real <--> date:				DATE is a double so this just copies.
	// Cannot be specified with RequireExactType.
	DTSTransformFlag_ForceConvert				= 0x00000080,

	// Causes the TransformServer to not ClearBindingData() the destination-row storage
	// for the columns in this Transform during OnRowComplete().  This allows the
	// destination row's values to be reused by the next transform.
	DTSTransformFlag_PreserveDestRows			= 0x00000100,

	// Causes the TransformServer to allow all conversions for which a lossless conversion is
	// possible - e.g. Promotion, nonNULLable -> NULLable, unsigned -> promoted signed.
	DTSTransformFlag_AllowLosslessConversion	= 0x00000200,

	// No flags are specified; essentially, the conversion must be between exact types.
	// Note that this allows string <--> nonstring conversions, because every nonstring datatype
	// has a meaningful string representation.  This may be overridden by RequireExactType.
	DTSTransformFlag_Default					= (DTSTransformFlag_AllowDemotion | DTSTransformFlag_AllowPromotion | DTSTransformFlag_AllowStringTruncation | DTSTransformFlag_AllowNumericTruncation | DTSTransformFlag_AllowNullChange | DTSTransformFlag_AllowSignChange)

} DP_ENUM_END(DTSTransformFlags);

// Status returned from a Transform operation.
// All "normal" errors from DTSDataPumpTransform::Execute should be returned as
// one of these flags, with a SUCCEEDED HRESULT (possibly with the addition of
// OLEDB Error Records via the IDTSErrorRecords interface passed to 
// IDTSDataPumpTransform::AddVariable).  A FAILED HRESULT returned from
// DTSDataPumpTransform::Execute indicates an unrecoverable error and aborts
// the DataPump.
typedef DP_ENUM_BEGIN(DTSTransformStatus, "Return value (int or long) from ActiveX Scripting Transform") {
	// Default; conversions (if any) succeeded; write the row to destination if
	// specified, without calling any error handlers.  Default is to do Insert;
	// this may be overridden for data-driven queries by other flags to do Insert,
	// Update, Delete, or UserQuery for a user-defined ad-hoc query.
	DTSTransformStat_OK							= 0x00000001,

	// Success with additional info, which the app may want to process further
	// by reading its pvTransformUserData (if it shares that knowledge with the
	// transform server) or thru OLEDB Error Records; therefore, the Pump will 
	// call the ErrorSink if one was specified, but does not increment the error
	// row count.  The DTSTransformStatus result of the operation is passed to
	// the ErrorSink, so the app can switch on this bit.
	DTSTransformStat_Info						= 0x00001000,

	// Write row if destination specified; also call ErrorSink with Info.
	DTSTransformStat_OKInfo						= 0x00001001,

	// Abort further processing of this row, for non-error reasons.
	DTSTransformStat_SkipRow					= 0x00000002,

	// Abort further processing of this row, and calls ErrorSink with Info.
	DTSTransformStat_SkipRowInfo				= 0x00001002,

	// Do not fetch the next row; re-execute all transforms against the current
	// source and destination rows.  No initialization is done to the destination
	// row, so this could be used to generate multiple output rows from a single
	// input row.  Subsequent transforms are still executed unless a SkipRow* flag
	// is also present.
	DTSTransformStat_SkipFetch					= 0x00000004,

	// Do not write the current row to destination.  Usually used to fetch the next
	// source row to generate a simple aggregate.  Subsequent transforms are still
	// executed unless a SkipRow* flag is also present.  DTSTransformStat_SkipInsert
	// forces DTSTransformFlag_PreserveDestRows behaviour for the row for which it
	// is specified.
	DTSTransformStat_SkipInsert					= 0x00000008,

	// The following 4 flags are not compatible together.  They execute the
	// similarly-named statement passed to SetRowsetAndQueries on the Destination,
	// with values from the currently transformed Destination Row.
	DTSTransformStat_InsertQuery				= 0x00000010,
	DTSTransformStat_UpdateQuery				= 0x00000020,
	DTSTransformStat_DeleteQuery				= 0x00000040,
	DTSTransformStat_UserQuery					= 0x00000080,

	// May be bit-OR'd into the following error returns.
	DTSTransformStat_Error						= 0x00002000,

	// Abort further processing of this row due to error and call the error sink,
	// but do not write to exception file.  Should be handled by the ErrorSink.
	DTSTransformStat_ErrorSkipRow				= 0x00002002,

	// Abort further processing of this row as an exception and call the error sink,
	// and write this row to exception file.  Should be handled by the ErrorSink.
	// Note this bit does not map to any non-error bits.
	DTSTransformStat_ExceptionRow				= 0x00002100,

	// Or’d with prior bits to abort processing any further rows and return
	// DTSTransformExec_AbortPump from IDTSDataPump::Execute().  
	// This does not include the Error bit so &'ing with it will only return
	// TRUE for this bit.
	DTSTransformStat_AbortPump					= 0x00004000,

	// Transform determined that this row is the last one to be operated on,
	// so allows the pump to be aborted "normally" (without signifying an error).
	// May be or'd with other bits to skip the current row; otherwise it will go
	// to the next transforms and then write it to destination (in accordance with
	// how the following transforms specify).
	DTSTransformStat_NoMoreRows					= 0x00008000,

} DP_ENUM_END(DTSTransformStatus);

// Status returned from an IDataPump::Execute operation.
typedef DP_ENUM_BEGIN(DTSExecuteStatus, "Return value (int or long) from DataPump Execution") {
	// All rows copied (or skipped) without error.
	DTSTransformExec_OK							= 0x00000000,

	// Bit-OR’d into the following error returns.
	DTSTransformExec_Error						= 0x00001000,	// Bit-or’d into following

	// Pump continued to completion but errors were encountered
	DTSTransformExec_OKErrors					= 0x00001001,

	// Pump aborted because too many rows had errors.
	DTSTransformExec_ErrorCountExceeded			= 0x00001002,

	// Pump aborted due to Transform request or ErrorSink return.
	DTSTransformExec_AbortPump					= 0x00001004,
} DP_ENUM_END(DTSExecuteStatus);

#endif	// DTSDataPump_CONSTANTS_

////////////////////////////////////////////
// CPP-only definitions
////////////////////////////////////////////

#ifndef DTSDataPump_ODL_

// Define parameter usage.
#define DP_IN
#define DP_OUT
#define DP_INOUT

#ifdef NONAMELESSUNION
#define DP_UNION_NAME(u)	u
#else
#define DP_UNION_NAME(u)
#endif

// For safety, struct initialization values are set in ctors for C++ clients.
#if !defined(__cplusplus) && !defined(DP_NO_AUTOCTOR)
#define DP_NO_AUTOCTOR
#endif

// These are the conversion flags indicating what may happen during an individual column
// Convert() call, and accounts for the column lengths, nullability, sign, etc.
// See DTSTransformFlags for a more detailed discussion of the similarly-named TransformFlag
// which will allow conversion to proceed when these conditions are present.
//	Keys:
//		<T> - TransformFlag is available to explicitly allow this.
//		<E>	- Error may be encountered during Convert()
//		<F> - Fatal; Convert() will error as unsupported or with overflow.
//
typedef DP_ENUM_BEGIN(DTSConvertFlags, "DTSConvertFlags") {
	// The conversion is between columns of identical type, length or precision/scale,
	// and nullability, or is between text and another type, with the text being of
	// sufficient length for a representation of that datatype.  Errors should not be
	// encountered during Convert() unless a text conversion contains invalid data.
	DTSConvertFlag_ExactType					= 0x00000000,

	// The conversion will promote the range of data from source to destination
	// (e.g. I4 -> I2, [var]char -> longer [var]char, numeric(x, y) -> numeric(x+1, y+1)).
	// <T>
	DTSConvertFlag_Promotion					= 0x00000001,
	
	// Conversion will demote (e.g. I4 -> I2); overflow error possible.
	// <T, E> 
	DTSConvertFlag_Demotion						= 0x00000002,
	
	// Conversion may do string or byte truncation; truncation error possible if
	// this flag is not specified on Convert().
	// <T, E>
	DTSConvertFlag_StringTruncation				= 0x00000004,
	
	// Conversion may do integral rounding from float or numeric, or move a larger
	// scale into a smaller scale (both cases resulting in truncation of digits to
	// the right of the decimal point).  This is also flagged when moving from integral
	// or numeric to float/double when source precision is greater than FLT/DBL_DIG.
	// <T> 
	DTSConvertFlag_NumericTruncation			= 0x00000008,
	
	// Conversion may try to put NULL source data into a NonNULL destination column,
	// which will error, or vice-versa, which will be safe.
	// <T, E>
	DTSConvertFlag_NullChange					= 0x00000010,
	
	// Conversion may try to put a signed value int/float into an unsigned destination, 
	// or vice-versa.  This may error if the source value is negative and destination
	// is unsigned, or if the source is unsigned and its value is larger than the
	// signed destination's maximum signed value (overflow).
	// <T, E>
	DTSConvertFlag_SignChange					= 0x00000020,
	
	// Destination column size is too short for a meaningful conversion from source
	// column type.
	// <F>
	DTSConvertFlag_DestTooShort					= 0x00000040,
	
	// Source column size is too short for a meaningful conversion to destination
	// column type.
	// <F>
	DTSConvertFlag_SourceTooShort				= 0x00000080,
	
	// Source and destination datatypes are not really compatible, but conversion can be forced.
	// <T>
	DTSConvertFlag_ForceConvert					= 0x00000100,
	
	// Conversion fails because of bad or incompatible column types.
	// <F>
	DTSConvertFlag_Unsupported					= 0x00001000,

} DP_ENUM_END(DTSConvertFlags);

// Binding modes for column data; returned from IDTSDataPumpTransform::ValidateSchema
// via DTSTransformColumnInfo.  Normally the DataPump default handling does not need to
// be changed, but for Blob ((DBCOLUMNFLAGS_ISLONG) columns, custom Transforms are able
// to adjust bindings to maximize performance.
//
typedef DP_ENUM_BEGIN(DTSBindMode, "DTSBindMode") {
	// Indicates data should be bound "in-memory, out of line".  Currently this is only supported
	// by the OLEDB specification for variable-length types: DBTYPE_((W)STR|BYTES); therefore,
	// the DataPump will error if it is specified for other types.  DTSBindMode_(Client|Provider)Owned
	// must be specified with DTSBindMode_Byref.
	// 
	// For source, the returned data will be a direct pointer to the provider's data if
	// DTSBindMode_ProviderOwned is specified (in which case it must not be free'd or written to),
	// or a CoTaskMemAlloc()'d pointer if DTSBindMode_ClientOwned is specified (in which case it
	// is the client's property and must be freed).
	//
	// For destination, the transformation server must place the data pointer in
	// pDestColumnInfo->pvRowData.  If DTSBindMode_ClientOwned is specified, then the data
	// is assumed to require freeing after the InsertRow operation completes.  The DataPump
	// will never perform a non-Byref, in-memory destination binding for a Blob, so this flag
	// must be specified unless a Storage Object is used.
	//
	DTSBindMode_Byref							= 0x00000001,

	// Default "in-memory, inline" binding mode; space for the source and destination data, including
	// the full length of a DBTYPE_((W)STR|BYTES) column, is allocated in rgColumnData[ii].pvData and
	// passed to IDTSDataPumpTransform::Execute.
	//
	// For a BLOB (DBCOLUMNFLAGS_ISLONG) column, IDTSDataPumpTransform::ValidateSchema returns
	// the length to use for this binding in ppDTSColBinding[ii].cbInMemoryBlobSize.  This will
	// result in a separate allocation for that Blob column (i.e. multiple Blobs are not
	// allocated within a single contiguous row).
	//
	// On fetch from Source, the DBSTATUS in the binding will indicate whether the data was
	// truncated; it is up to the Transform server how (or if) this is handled.
	//
	// For performance reasons, this flag should not be specified for non-Blob (W)STR|BYTES
	// source columns; DTSBindMode_Byref_ProviderOwned is the default, to use a pointer to the
	// provider's data cache and avoid an unnecessary copy.
	//
	// For DBTYPE_BSTR and DBTYPE_VARIANT, this specifies that the binding is DBMEMOWNER_CLIENTOWNED
	// (without BYREF), and the client is responsible for freeing it (e.g. IDTSDataConvert::ClearBindingData).
	//
	DTSBindMode_ClientOwned						= 0x00000002,

	// For Source DBTYPE_((W)STR|BYTES), this flag causes the OLEDB binding to be done as DBTYPE_BYREF
	// with DBMEMOWNER_CLIENTOWNED, resulting in a CoTaskMemAlloc which the client is
	// responsible for freeing (e.g. via IDTSDataConvert::ClearBindingData).  For a BLOB
	// column, the length to use for this binding is returned from ValidateSchema() in 
	// ppDTSColBinding[ii].cbInMemoryBlobSize.  On fetch from Source, the DBSTATUS in the binding
	// will indicate whether the data was truncated; it is up to the Transform server how (or if)
	// this is handled.
	//
	// This flag causes each row to have a separate CoTaskMemAlloc for the source column.  This is
	// somewhat less efficient than the other in-memory options, and thus should only be used by
	// a Transform which wants to assume ownership of that allocation.  The Transform is responsible
	// for tracking and freeing the allocation (and for ensuring that OnRowComplete does not free
	// it if it is to be used in subsequent Transforms).
	//
	// For destination columns, this is the "safest" way to pass an in-memory pointer, as some providers
	// may not allow ProviderOwned on a destination (such as with Blob columns).  The Transform must
	// ensure that it does not double-free a pointer.
	//
	DTSBindMode_Byref_ClientOwned				= 0x00000003,

	// By itself, ProviderOwned is seldom used by itself except for BSTR, which does not always
	// support Byref.  It is primarily for DBTYPE_((W)STR|BYTES) with Byref, to reduce allocations
	// and/or copies, as described below.  It may not be supported by providers for other datatypes.
	//
	DTSBindMode_ProviderOwned					= 0x00000004,

	// This flag causes source columns to be bound to return a pointer into the provider's memory
	// space for DBTYPE_((W)STR|BYTES).  This pointer is read-only and must not be freed.
	//
	// For Blob columns, the Source Provider may not support (Byref_)ProviderOwned Blobs; this
	// would require that the entire Blob be buffered contiguously.  Therefore, unless you have
	// specific knowledge of the provider, this flag is discouraged.
	//
	// For DBTYPE_BSTR, the BYREF specification may not be supported, and may require DBMEMOWNER_PROVIDEROWNED
	// (without BYREF).  The client must not free the data.
	//
	// For other types, including DBTYPE_VARIANT, OLEDB raises an error for this specification
	// when creating an accessor.
	//
	// For the destination, specifying ProviderOwned requires that the data be shallow-copied into
	// the destination binding to avoid memory leaks (this is automatically done by IDTSDataConvert::
	// ConvertToBinding).
	//
	DTSBindMode_Byref_ProviderOwned				= 0x00000005,

	// This indicates whether the Pump should buffer Source Blob Storage Objects.  For most cases,
	// this should be left _BufferDefault; for performance reasons, the DataPump will only buffer
	// where it is necessary to avoid data loss.  This is in the following cases:
	//	DTSBindMode_Blob_BufferAlways
	//	DTSBindMode_Blob_BufferDefault, provider doesn't allow multiple SO's, and any of following:
	//		The column is referenced in a subsequent transform.
	//		The column is not the rightmost column of all transforms up to and including it.
	//
	// The DataPump can buffer from a source provider's ISequentialStream or ILockBytes, and
	// exposes both these interfaces on its own object.  Because it is a buffer, the object's data
	// can be edited via Write(At) to reduce memory requirements in the TransformServer (allowing the
	// source object to be placed in the destination row, if the destination supports Storage Objects).
	//
	// DTSBindMode_Blob_* is ignored for in-memory binding, which is an implicit buffering.
	DTSBindMode_Blob_BufferDefault				= 0x00000010,
	DTSBindMode_Blob_BufferAlways				= 0x00000020,
	DTSBindMode_Blob_BufferNever				= 0x00000040,

	// This indicates whether to use a Structured Storage object for binding a BLOB column.  The Transform
	// Server should indicate which interface it wants in DTSBindInfo::fStorageObject, on return from
	// ValidateSchema().  The DataPump supports the following behaviour:
	//    Custom Transformations:
	//       For Source, if the DataPump does not buffer, only the provider-supported Storage Object interfaces
	//			are available.  Generally this will always include ISequentialStream.  See comments regarding
	//			DTSBindMode_Blob_Buffer*; if the DataPump buffers the Blob data, it supports only ISequentialStream
	//			and ILockBytes.
	//          If the source does not support storage objects, then the Transform Server must not request a
	//			Storage Object, and must bind the source data as in-memory, specifying DTSBindInfo::cbInMemoryBlobSize.
	//       For Destination, the Transform Server supplies the Storage object placed into the row, and must
	//			specify one interface from fProviderStorageObjects for the DataPump to bind the destination.
	//          If the destination does not support storage objects, then the TransformServer must not request
	//			a Storage Object, and must bind the destination data as in-memory, ClientOwned or ProviderOwned,
	//			specifying DTSBindInfo::cbInMemoryBlobSize.
	//    Default (DataPump-supplied) TransformCopy:
	//       If either Source or Destination do not support ISequentialStream, then the DataPump will bind both
	//          as ClientOwned in-memory, using the source column's DTSBindInfo::cbInMemoryBlobSize.
	//			Otherwise, the DataPump will bind to the providers as ISequentialStream, with default buffering.
	//			See also comments regarding DTSBindMode_Blob_Buffer*; this can be specified to override the
	//			Pump's default handling even in the TransformCopy case.
	//
	// DTSBindMode_Blob_StorageObject cannot be specified with non-DTSBindMode_Blob_* flags.
	DTSBindMode_Blob_StorageObject				= 0x00000100,
} DP_ENUM_END(DTSBindMode);

// Indicates which of the DataPump defaults are to be overridden on a single AddTransform().
typedef DP_ENUM_BEGIN(DTSSpecifyBlobDefaults, "Specify overrides of DataPump Blob-handling defaults") {
	DTSBlobDefault_DataPumpDefaults		= 0x0000,	// None (initialization)
	DTSBlobDefault_BufferSource			= 0x0001,	// Override DTSBindMode_Blob_BufferDefault for source Blob Storage Objects
	DTSBlobDefault_InMemorySize			= 0x0002,	// Override DTS_DEFAULT_INMEMORY_BLOB_SIZE.
	DTSBlobDefault_ForceInMemory 		= 0x0004,	// Force Blobs to be InMemory (no Storage Objects) for this Transform.
													// Forces DTSTransformColumnInfo.fProviderStorageObjects
													// sent to the Transformer to be 0.
	DTSBlobDefault_ForceMultipleStorageObjects	= 0x0008,	// Forces DTSTransformColumnInfo.dtsProviderFlags sent to the
													// Transformer to include DTSProviderFlag_Blob_MultipleStorageObjects.
													// This could be an optimization if the Source provider supports multiple
													// storage objects and the destination is known to support them only
													// multiple blobs for insert, since the OLEDB spec does not distinguish
													// between multiple-StorageObject support for GetData vs. SetData/Insert.
} DP_ENUM_END(DTSSpecifyBlobDefaults);

// Flags indicating known Provider Blob capabilities; their absence indicates
// corresponding Provider restrictions or requirements.
typedef DP_ENUM_BEGIN(DTSProviderFlags, "Provider behaviour characteristics") {
	DTSProviderFlag_None					= 0x00000000,	// None

	DTSProviderFlag_ProviderOwned			= 0x00000001,	// Provider supports Byref binding (some may not).

	DTSProviderFlag_Blob_InsertNoLength		= 0x00000100,	// Blob Inserts do not require length to be prespecified
	DTSProviderFlag_Blob_Revisitable		= 0x00000200,	// Provider guarantees that Blob data is not skipped when succeeding columns fetched
	DTSProviderFlag_Blob_Rewindable			= 0x00000400,	// Provider guarantees Blob data supports random access
	DTSProviderFlag_Blob_ProviderOwned		= 0x00000800,	// Provider allows the PROVIDEROWNED flag for use with Blobs
	DTSProviderFlag_Blob_MultipleStorageObjects = 0x00001000,		// Provider supports multiple storage objects per row.
	DTSProviderFlag_Blob_NonBlockingStorageObjects = 0x00002000,	// Provider supports multiple nonblocking storage objects per row.
} DP_ENUM_END(DTSProviderFlags);

// The actual structure passed to AddTransform to specify overriding Blob defaults.
// This is most useful for the default TransformCopy case, but can also be used by
// a client who predetermines (e.g. via a query) the maximum Blob size in the coming
// result set, for the most efficient memory allocations.
#ifndef DP_NO_AUTOCTOR
	struct DTSTransformBlobDefaults {
#else   // DP_NO_AUTOCTOR
	typedef struct {
#endif  // DP_NO_AUTOCTOR
		DTSSpecifyBlobDefaults dtsSpecifyMask;		// Which of the following items to override.
		BOOL bBufferSource;							// If dtsSpecifyMask & DTSBlobDefault_BufferSource;
													// TRUE or FALSE forces Pump to buffer source Blobs or not.
		ULONG cbInMemorySize;						// If dtsSpecifyMask & DTSBlobDefault_InMemorySize;
													// overrides DTS_DEFAULT_INMEMORY_BLOB_SIZE.  Size in bytes.
#ifndef DP_NO_AUTOCTOR
		DTSTransformBlobDefaults()
				: dtsSpecifyMask(DTSBlobDefault_DataPumpDefaults)
			{	}
	};
#else   // DP_NO_AUTOCTOR
	} DTSTransformBlobDefaults;
#endif  // DP_NO_AUTOCTOR
typedef DTSTransformBlobDefaults *LPDTSTransformBlobDefaults;
typedef const DTSTransformBlobDefaults *LPCDTSTransformBlobDefaults;

// Specifies an individual column passed to AddTransform.  The column may be specified by
// name, or if the name is NULL, by an ordinal (this makes unnamed columns easier for the
// consumer to specify).
typedef struct {
	LPOLESTR pwzColumnName;						// Name of column
	ULONG ulColumnOrdinal;						// Ordinal of column if name is NULL; 1-based for OLEDB consistency.
} DTSTransformColumnSpecification, *LPDTSTransformColumnSpecification;
typedef const DTSTransformColumnSpecification *LPCDTSTransformColumnSpecification;

// Specifies a list of columns passed to AddTransform.
#ifndef DP_NO_AUTOCTOR
	struct DTSTransformColumnsSpecification {
#else   // DP_NO_AUTOCTOR
	typedef struct {
#endif  // DP_NO_AUTOCTOR

		ULONG cSourceColumns;						// Specify source columns
		LPCDTSTransformColumnSpecification pSourceColumns;
		ULONG cDestinationColumns;					// Specify destination columns
		LPCDTSTransformColumnSpecification pDestinationColumns;
		DTSTransformBlobDefaults BlobDefaults;		// Blob default overrides if specified

#ifndef DP_NO_AUTOCTOR
		DTSTransformColumnsSpecification() 
				: cSourceColumns(0)
				, pSourceColumns(NULL)
				, cDestinationColumns(0)
				, pDestinationColumns(NULL)
			{	}
	};
#else   // DP_NO_AUTOCTOR
	} DTSTransformColumnsSpecification;
#endif   // DP_NO_AUTOCTOR
typedef DTSTransformColumnsSpecification *LPDTSTransformColumnsSpecification;
typedef const DTSTransformColumnsSpecification *LPCDTSTransformColumnsSpecification;

// Specifies a query and list of columns for IDTSDataDrivenQuery.
#ifndef DP_NO_AUTOCTOR
	struct DTSTransformQuerySpecification {
#else   // DP_NO_AUTOCTOR
	typedef struct {
#endif  // DP_NO_AUTOCTOR

		LPCOLESTR wzQuery;								// The Parameterized Query
		ULONG cColumns;									// Specify count of columns
		LPCDTSTransformColumnSpecification pColumns;	// Specify column mapping to parameters, in order found in query.

#ifndef DP_NO_AUTOCTOR
		DTSTransformQuerySpecification() 
				: wzQuery(NULL)
				, cColumns(0)
				, pColumns(NULL)
			{	}
	};
#else   // DP_NO_AUTOCTOR
	} DTSTransformQuerySpecification;
#endif   // DP_NO_AUTOCTOR
typedef DTSTransformQuerySpecification *LPDTSTransformQuerySpecification;
typedef const DTSTransformQuerySpecification *LPCDTSTransformQuerySpecification;

// Transform-server specifiable binding information.  An array of these structures is passed to
// ValidateSchema() with default values (possibly derived from DTSTransformBlobDefaults overrides),
// and the Transform Server can set the values.  Because source columns can appear multiple times
// in the same or different transactions, the last specification wins; therefore, a TransformServer's
// Execute() method should gracefully handle a source binding different from what it specified in
// ValidateSchema().
typedef struct {
	DTSBindMode eBindMode;						// Per above.  For Blobs, specifying a Buffering mode overrides
												// the DataPump and any DTSTransformBlobDefaults default.
	DWORD fStorageObject;						// For DTSBindMode_Blob_StorageObject; one of DBPROPVAL_SS_*.  If
												// specified, eBindMode must be DTSBindMode_Blob_StorageObject.
	ULONG cbInMemoryBlobSize;					// For DTSBindMode of inmemory Blobs.  Setting this value overrides
												// the DataPump and any DTSTransformBlobDefaults default.  Size in bytes.
} DTSBindInfo;

// This is a single column definition, binding, and data item for DTSTransformColumnInfo.
typedef struct {
	const DBCOLUMNINFO *pDBColumnInfo;			// Pointer to source or destination DBCOLUMNINFO for this column.
	const DBBINDING *pDBBinding;				// Pointer to source or destination DBBINDING for this column.
												// wType == DBTYPE_EMPTY if this column is not referenced in any transform.
	DTSBindInfo *pDTSBindInfo;					// Pointer to source or destination DTSBindInfo for this column.
	LPBYTE pvData;								// Data space for this column, indexed by pDBBinding offsets.
												// NULL if this column was not referenced in any Transform.
} DTSColumnData;

// The DBCOLUMNFLAGS and pwszName are in DBCOLUMNINFO and not DBBINDING;
// therefore pass both structures to transform code.  The COM Transform server uses the
// binding info to access the pvRowData.  This structure is passed to ITransformExecute::
// Execute to expose the source and destination columns specified by the Transform.
typedef struct {
	DWORD fProviderStorageObjects;				// DBPROPVAL_SS_*; Blob Storage Object interfaces supported
												// by source or destination provider.  Will be 0 if none supported,
												// or if DTSTransformBlobDefaults::bForceBlobsInMemory is specified.
	DTSProviderFlags dtsProviderFlags;			// Provider characterstics, e.g Blob Flags.
	ULONG cColumns;								// Count of columns in rgColumns
	DTSColumnData *rgColumnData;				// Column schema and binding information
	ULONG cPriorBlobStorageObjects;				// Number of Blobs bound as Storage Objects in prior transforms.
												// Can be used with DTSProviderFlag_Blob_MultipleStorageObjects
												// to determine if the current Transform can use a storage object.
} DTSTransformColumnInfo, *LPDTSTransformColumnInfo;
typedef const DTSTransformColumnInfo *LPCDTSTransformColumnInfo;

typedef enum {
	DTSGuid_Variant,
	DTSGuid_Guid,
	DTSGuid_OleStr
} DTSGuidType;

typedef struct {
	DTSGuidType eType;							// Indexes union.
	union {
		GUID Guid;								// GUID form
		VARIANT Variant;						// BSTR == progid or clsid (differentiated by looking for ‘.’ in name)
												// BYTE/LONG == guid encoding (e.g. Repository))
												// UNKNOWN == pointer to IID_IDTSDataPumpTransform
		LPOLESTR OleStr;						// Progid or clsid (differentiated by looking for ‘.’ in name)
	} DP_UNION_NAME(u);
} DTSGuid;

#define DTS_DEFAULT_LookupCacheSize		100

// Specifies a query and list of columns for IDTSDataDrivenQuery.
#ifndef DP_NO_AUTOCTOR
	struct DTSTransformLookupSpecification {
#else   // DP_NO_AUTOCTOR
	typedef struct {
#endif  // DP_NO_AUTOCTOR

		LPCOLESTR wzName;								// Name of the Lookup (for disambiguation)
		LPCOLESTR wzQuery;								// The Parameterized Query
		IUnknown *pIUnkSession;							// Session to use for the Lookup
		ULONG cMaxCacheRows;							// Number of rows to cache

#ifndef DP_NO_AUTOCTOR
		DTSTransformLookupSpecification() 
				: wzName(NULL)
				, wzQuery(NULL)
				, pIUnkSession(NULL)
				, cMaxCacheRows(DTS_DEFAULT_LookupCacheSize)
			{	}
	};
#else   // DP_NO_AUTOCTOR
	} DTSTransformLookupSpecification;
#endif   // DP_NO_AUTOCTOR
typedef DTSTransformLookupSpecification *LPDTSTransformLookupSpecification;
typedef const DTSTransformLookupSpecification *LPCDTSTransformLookupSpecification;

///////////////////////////////////////////////////////////////////////////////////////
// Class and IID definitions
///////////////////////////////////////////////////////////////////////////////////////

// Forward-define all interfaces.
#define DP_FWD_DEFINE_INTERFACE(itf)					\
	interface itf;										\
	typedef interface itf * LP##itf;

// Repeat the IUnknown and IDispatch members because C doesn't provide inheritance.
#ifndef DTSDataPump_Unknown_Base
#define DTSDataPump_Unknown_Base()															\
		STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;				\
		STDMETHOD_(ULONG,AddRef) (THIS) PURE;												\
		STDMETHOD_(ULONG,Release) (THIS) PURE;
#endif
#ifndef DTSDataPump_Dispatch_Base
#define DTSDataPump_Dispatch_Base(itf)														\
		DTSDataPump_Unknown_Base()															\
		STDMETHOD(GetTypeInfoCount)(UINT FAR* pcTypeInfo) PURE;								\
		STDMETHOD(GetTypeInfo)(UINT iTypeInfo, LCID lcid, ITypeInfo FAR* FAR* ppTI) PURE;	\
		STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR FAR* rgszNames, UINT cNames,			\
								LCID lcid, DISPID FAR* rgdispid) PURE;						\
		STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,			\
								DISPPARAMS FAR* pdispparams, LPVARIANT pvarResult,			\
								LPEXCEPINFO pexcepinfo, UINT FAR* puArgErr) PURE;
#endif
#ifndef DTSDataPump_IDispatch
#define DTSDataPump_IDispatch IDispatch
#endif

// Include <initguid.h> to define ownership of these GUIDs.
// {xxxxxxxx-740b-11d0-ae7b-00aa004a34d5}
#define DEFINE_DTSDataPumpGUID(name, lval) \
      DEFINE_GUID(name, 0x##lval, 0x740b, 0x11d0, 0xae, 0x7b, 0x0, 0xaa, 0x0, 0x4a, 0x34, 0xd5);

// DTSPump-supplied classes and interfaces.
DP_FWD_DEFINE_INTERFACE(IDTSDataPump)
#define Progid_DTSDataPump			OLESTR("DTS.DataPump")
DEFINE_DTSDataPumpGUID(CLSID_DTSDataPump, 10010100)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPump, 10010101)

#define Progid_DTSErrorLookup		OLESTR("DTS.ErrorLookup")
DEFINE_DTSDataPumpGUID(CLSID_DTSErrorLookup, 10010102)

DP_FWD_DEFINE_INTERFACE(IDTSDataConvert)
#define Progid_DTSDataConvert		OLESTR("DTS.DataConvert")
DEFINE_DTSDataPumpGUID(CLSID_DTSDataConvert, 10010103)
DEFINE_DTSDataPumpGUID(IID_IDTSDataConvert, 10010104)
DEFINE_DTSDataPumpGUID(IID_IDTSDataDrivenQuery, 10010105)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpSpecifyLookups, 10010106)

// DTS Typelib IID's.
DEFINE_DTSDataPumpGUID(LIBID_DataPump, 10010200)
DP_FWD_DEFINE_INTERFACE(IDTSDataPumpColumns)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpColumns, 10010201)
DP_FWD_DEFINE_INTERFACE(IDTSDataPumpColumn)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpColumn, 10010202)
DEFINE_DTSDataPumpGUID(IID_IDTSErrorRecords, 10010203)
DP_FWD_DEFINE_INTERFACE(IDTSDataPumpLookups)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpLookups, 10010204)
DP_FWD_DEFINE_INTERFACE(IDTSDataPumpLookup)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpLookup, 10010205)
DP_FWD_DEFINE_INTERFACE(IDTSDataPumpLookupVariant)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpLookupVariant, 10010206)

// Repository Storage IIDs.
DEFINE_DTSDataPumpGUID(IID_IDTSRepositoryProvider, 100202F1)
DEFINE_DTSDataPumpGUID(IID_IDTSRepositoryStorage, 100202F2)

/////////////////////////////////////////////////////////////////////////////////
// Category id of DTS custom transforms.
/////////////////////////////////////////////////////////////////////////////////
DEFINE_DTSDataPumpGUID(CATID_DTSCustomXform, 10010100)	//we will use the same id as the pump clsid.

// Consumer-supplied classes and interfaces.
DP_FWD_DEFINE_INTERFACE(IDTSDataPumpTransform)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpTransform, 10010300)

DP_FWD_DEFINE_INTERFACE(IDTSDataPumpErrorSink)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpErrorSink, 10010301)

DP_FWD_DEFINE_INTERFACE(IDTSDataPumpProgressSink)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpProgressSink, 10010302)

DP_FWD_DEFINE_INTERFACE(IDTSDataDrivenQuerySink)
DEFINE_DTSDataPumpGUID(IID_IDTSDataDrivenQuerySink, 10010303)

// DTSDataPump-supplied COM Transform Servers
// A "Transformation Server" coclass consists of:
//		coclass TTransformServer {
//			required IDTSDataPumpTransform;
//
//			// The following are optional if the TransformServer has no custom
//			// properties requiring editing.  If it has, these are required.
//			optional <Custom OleAut properties interface>;
//			optional ISpecifyPropertyPages;
//				optional IPropertyPage;
//			optional IPersistPropertyBag;
//		}

#define Progid_DTSDataPumpTransformCopy		OLESTR("DTS.DataPumpTransformCopy")
DEFINE_DTSDataPumpGUID(CLSID_DTSDataPumpTransformCopy, 10010400)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpTransformCopy, 10010401)
// No custom properties, therefore no custom interface or IID.

#define Progid_DTSDataPumpTransformScript	OLESTR("DTS.DataPumpTransformScript")
DEFINE_DTSDataPumpGUID(CLSID_DTSDataPumpTransformScript, 10010501);
DP_FWD_DEFINE_INTERFACE(IDTSDataPumpTransformScriptProperties)
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpTransformScriptProperties, 10010502);
DEFINE_DTSDataPumpGUID(IID_IDTSDataPumpTransformScript, 10010503);

//optional interface to be implemented by custom transform providers - used by DTS UI to configure the transforms
DEFINE_DTSDataPumpGUID(IID_IDTSCustomTransformUI, 10010601);


////////////////////////////////////////////////////////////////////////////////////////
//
//	DataPump-supplied Transform variables.
//
// These are passed to IDTSDataPumpTransform::AddVariable.  They are all of type
// VT_VARIANT.  IDTSErrorRecords (interface defined below) allows any transform
// to append OLEDB Error Records to IErrorInfo for the current thread.  The name
// "DTSErrorRecords" is what is passed to IDTSDataPumpTransform::AddVariable; the
// VT_DISPATCH ma be QI'd (or cast) to IDTSErrorRecords.  This object is also
// inserted into ActiveX Scripting namespaces invoked by the Pump.  All DTS-generated
// variables are inserted into ActiveX scripting namespaces as non-global variables
// (i.e. their methods must be qualified with the object name).
//
//		Name					Type
//		----					----
//		DTSError				DTS.Error
#define wzDTSErrorRecords	OLESTR("DTSErrorRecords")

//
// These are inserted by name into the global namespace of an ActiveX scripting transform.
// View the type library to see the type definitions.  Note that the return value from the
// method (FunctionEntry) must be an integral type.
//
//		Name					Type
//		----					----
//		DTSSource				DTS.Columns
//		DTSDestination			DTS.Columns
//		(return value)			adInt or adSmallInt (DTSTransformStatus)
//

//
// These are inserted by name into the global namespace of an ActiveX scripting transform,
// as well as being passed to IDTSDataPumpTransform::AddVariable.
//
//		Name					Type
//		----					----
//		DTSLookups				DTS.Lookups
#define wzDTSLookups		OLESTR("DTSLookups")

// These are the DTS-Package-supplied global variables, if the Pump is being run from
// the Package.
#define wzDTSGlobalVariables		OLESTR("DTSGlobalVariables")

// These are special pseudo-columnnames corresponding to Lineage.  They are also
// the names of the corresponding GlobalVariables; TransformCopy will automatically
// map them over to the specified destination column.  These names must not be used
// by source column names.
#define wzDTSLineage_FullString		OLESTR("DTSLineage_Full")
#define wzDTSLineage_IntegerCRC		OLESTR("DTSLineage_Short")

////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////
//
//	DataPump-supplied interface definitions.
//
////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////
// IDTSDataPump - Primary interface to specify source and destination rowsets,
// add Transforms, and Execute() the transfer.  AddTransform will error if
// SetRowsets has not been called, and SetRowsets will error if any transforms
// have been added (because ValidateSchema has been done on them already).
// InitNew() reinitializes the IDTSDataPump object.  Execute returns E_FAIL if aborted,
// DB_E_ERRORSOCCURRED if max error count exceeded; DB_S_ERRORSOCCURRED if errors
// less than the max allowed occurred, possible provider-specific errors, or NOERROR
// if completed with no errors.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPump
DECLARE_INTERFACE_(IDTSDataPump, IUnknown)
{
	DTSDataPump_Unknown_Base()

	STDMETHOD(InitNew)(THIS) PURE;
	STDMETHOD(GetRowsets)(THIS_ 
			DP_OUT IRowset **ppSrcRowset,
			DP_OUT IRowsetChange **ppDestRowsetChange
		) PURE;
	STDMETHOD(SetRowsets)(THIS_ 
			DP_IN IRowset *pSrcRowset,							// Must be able to retrieve these rows
			DP_IN IRowsetChange *pDestRowsetChange				// Must have DBPROP_UPDATABILITY: DPBROP_UP_INSERT
		) PURE;
	STDMETHOD(SetProgressRowCount)(THIS_
			DP_IN ULONG cIn										// Interval for IDTSDataPumpProgressSink::OnIntervalComplete; default == 1000
		) PURE;
	STDMETHOD(SetMaximumErrorRowCount)(THIS_
			DP_IN ULONG cIn										// Maximum allowable error rows; default = 0 (abort on first error row).
		) PURE;
	STDMETHOD(SetFetchBufferSize)(THIS_
			DP_IN ULONG cIn										// Size of the GetNextRows HROW buffer (default = 1)
		) PURE;
	STDMETHOD(SetInsertCommitSize)(THIS_
			DP_IN ULONG cIn										// Number of successful InsertRows between "Commits", if supported by provider (default == 0; all rows in one batch).
		) PURE;
	STDMETHOD(AddTransform)(THIS_ 
			DP_IN LPCOLESTR pwzName,							// Transform name
			DP_IN LPBYTE pvUserData,							// Will be passed to Sink if event occurs on Transform.
			DP_IN LPCDTSTransformColumnsSpecification pColumns,	// Source and destination columns
			DP_IN DTSGuid ServerClsid,							// COM server ProgID or CLSID or IUnknown
			DP_IN VARIANT ServerParameters,						// Parameters to server for this transform
			DP_IN DTSTransformFlags dwFlags,					// Transformation column-validation flags
			DP_IN IStorage *pIStorage							// Pointer to persistent storage of Transform properties
		) PURE;
	STDMETHOD(AddTransformVariable)(THIS_ 
			DP_IN LPCOLESTR pwzName,							// Variable name
			DP_IN BOOL bGlobal,									// For ActiveX scripts, indicates whether this variable's
																// methods must be qualified by the object name.
			DP_IN VARIANT Variable								// Variable value; passed to and updatable by Transform
		) PURE;
	STDMETHOD(Execute)(THIS_ 
			DP_IN LPBYTE pvUserData,							// User data passed back to Sinks.
			DP_OUT ULARGE_INTEGER *puliRowsComplete,			// Total number of source rows processed (including those skipped).
			DP_OUT ULONG *pulErrorRows,							// Total number of error rows encountered.
			DP_OUT LPDTSExecuteStatus pExecStatus				// Pump return status.
		) PURE;
	STDMETHOD(SetFirstRow)(THIS_
			DP_IN ULARGE_INTEGER cIn							// First source row to copy. Default is 1 (first row).
		) PURE;
	STDMETHOD(SetLastRow)(THIS_
			DP_IN ULARGE_INTEGER cIn							// Last source row to copy. Default is 0 (copy all rows).
		) PURE;
};

///////////////////////////////////////
// IDTSDataDrivenQuery - Allows specification of individual queries instead
// of simple Insert at the Destination.  QI'd from IDTSDataPump.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataDrivenQuery
DECLARE_INTERFACE_(IDTSDataDrivenQuery, IUnknown)
{
	DTSDataPump_Unknown_Base()

	// The following four pairs of properties and methods should be called in the
	// order listed.

	// Specify and retrieve the source rowset from which data will be read.
	STDMETHOD(SetSourceRowset)(THIS_ 
			DP_IN IRowset *pSrcRowset
		) PURE;
	STDMETHOD(GetSourceRowset)(THIS_ 
			DP_OUT IRowset **ppSrcRowset
		) PURE;

	// Specify and retrieve the destination session and column schema; this defines how the
	// parameters to the queries will be bound.  Specifying the schema is done in one of two ways:
	//	- If cColumnDescs is 0, then rgColumnDescs is ignored and pDestConnection must
	//	  be a Rowset.  Rowset information will be retrieved, but the Rowset itself will not
	//	  be retained.  The Session will be retrieved from the Rowset and retained.
	//	- If cColumnDescs is not 0, then rgColumnDescs must not be NULL and pDestConnection
	//	  must be a Session.  The destination column definitions are created from the DBCOLUMNDESCs.
	//
	STDMETHOD(SetDestinationInfo)(THIS_
			DP_IN IUnknown *pDestConnection,
			DP_IN ULONG cColumnDescs,
			DP_IN DBCOLUMNDESC rgColumnDescs[]
		) PURE;
	// pcColumns, prgInfo, and ppStringsBuffer are allocated as in IColumnsInfo::GetColumnInfo.
	STDMETHOD(GetDestinationInfo)(THIS_
			DP_IN REFIID riidSession, 
			DP_OUT IUnknown **ppIUnkSession,
			DP_OUT ULONG *pcColumns,
			DP_OUT DBCOLUMNINFO **prgInfo,
			DP_OUT OLECHAR **ppStringsBuffer
		) PURE;

	// Specify and retrieve the destination queries and their column mappings to parameters.
	// Unused queries may be NULL, in which case a Transform return status of DTSTransformStat_*Query
	// indicating an unset query will result in an error.
	STDMETHOD(SetDestinationQueries)(THIS_ 
			DP_IN LPCDTSTransformQuerySpecification pInsertQuerySpec,
			DP_IN LPCDTSTransformQuerySpecification pUpdateQuerySpec,
			DP_IN LPCDTSTransformQuerySpecification pDeleteQuerySpec,
			DP_IN LPCDTSTransformQuerySpecification pUserQuerySpec
		) PURE;
	// Each pointer is a single CoTaskMemAlloc containing space for the base QuerySpecification structure,
	// the array of column info, and the string buffer.  Internal pointers are based (with alignment)
	// according to this allocated space.
	STDMETHOD(GetDestinationQueries)(THIS_ 
			DP_OUT LPDTSTransformQuerySpecification *ppInsertQuerySpec,
			DP_OUT LPDTSTransformQuerySpecification *ppUpdateQuerySpec,
			DP_OUT LPDTSTransformQuerySpecification *ppDeleteQuerySpec,
			DP_OUT LPDTSTransformQuerySpecification *ppUserQuerySpec
		) PURE;
};

///////////////////////////////////////
// IDTSDataPumpLookups - Allows specification of Lookups for TransformServer use.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpSpecifyLookups
DECLARE_INTERFACE_(IDTSDataPumpSpecifyLookups, IUnknown)
{
	DTSDataPump_Unknown_Base()

	// Specify and retrieve the lookup specifications for this DataPump instance.
	STDMETHOD(SetLookups)(THIS_ 
			DP_IN ULONG cLookups,
			DP_IN LPCDTSTransformLookupSpecification pLookups
		) PURE;
	// The pointer is a single CoTaskMemAlloc containing space for the base LookupSpecification structure
	// and the string buffer.  Internal pointers are based (with alignment) according to this allocated space.
	// pIUnkSession is AddRef'd and must be released.
	STDMETHOD(GetLookups)(THIS_ 
			DP_IN ULONG *pcLookups,
			DP_IN LPDTSTransformLookupSpecification *ppLookups
		) PURE;
};

///////////////////////////////////////
// IDTSDataConvert - The DTS data-conversion interface.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataConvert
DECLARE_INTERFACE_(IDTSDataConvert, IDataConvert)
{
	DTSDataPump_Unknown_Base()

	//////////////////////////////////////////////////////
	// IDataConvert interface members (msdadc.h required).
	//////////////////////////////////////////////////////

	// Copies or converts data from one DBTYPE to another.  If wDstType includes DBTYPE_BYREF,
	// it must be a variable-length type (DBTYPE_((W)STR|BYTES)) or this method will error.
	// Otherwise, for all DBTYPE_BYREF destination conversions, this method CoTaskMemAlloc(s)
	// the destination data pointer, and it is the caller's responsibility to CoTaskMemFree it.
	// This method should not be used to place data into the DataPump's destination binding;
	// instead, use the ConvertToBinding method.
	STDMETHOD(DataConvert)( 
			DP_IN DBTYPE wSrcType,
			DP_IN DBTYPE wDstType,
			DP_IN ULONG cbSrcLength,
			DP_INOUT ULONG *pcbDstLength,
			DP_IN void *pSrc,
			DP_OUT void *pDst,
			DP_IN ULONG cbDstMaxLength,
			DP_IN DBSTATUS dbsSrcStatus,
			DP_OUT DBSTATUS *pdbsStatus,
			DP_IN BYTE bPrecision,
			DP_IN BYTE bScale,
			DP_IN DBDATACONVERT dwFlags
		) PURE;

	// Determines if two types are potentially compatible.  See GetConvertFlags
	// for more detailed information about what the conversion may encounter.
	STDMETHOD(CanConvert)( 
			DP_IN DBTYPE wSrcType,
			DP_IN DBTYPE wDstType
		) PURE;

	// Returns the required conversion size in bytes.  May base this on pcbSrcLength
	// and/or pSrc, if supplied, to get per-data-item information.
	//
	// DBTYPE_BSTR is considered a fixed type; its binding length is sizeof(BSTR).
	// To determine the length necessary to pre-allocate a BSTR, pass in DBTYPE_STR
	// for the destination type - for this type, character count == byte count.
	// Alternatively, use WSTR and divide the return by sizeof(WCHAR).
	//
	STDMETHOD(GetConversionSize)( 
			DP_IN DBTYPE wSrcType,
			DP_IN DBTYPE wDstType,
			DP_IN ULONG *pcbSrcLength,
			DP_OUT ULONG *pcbDstLength,
			DP_IN void *pSrc
		) PURE;

	//////////////////////////////////////////////////////
	// DTS extensions.
	//////////////////////////////////////////////////////

	// This method first calls CanConvert() to determine if the conversion can succeed at all
	// given the source and destination datatypes, and if so, returns extended information about
	// how (or if) the conversion can proceed after that.
	// It uses the following fields for source and destination (S and D):
	//	DBCOLUMNINFO - validates all conversion info between columns.
	//		dwFlags					S,D
	//		ulColumnSize			S,D
	//		wType					S,D
	//		bPrecision				S,D
	//		bScale					S,D
	//	Fields other than dwFlags and wType can be zero'd and the output ConvertFlags
	//	tested for the Unsupported bit if length validation is not required.
	// Note that this does not set a flag for nontext <-> text if the text length is
	// sufficient to accommodate it; this is because all such conversions should be valid
	// If this level of exactness is required, simply compare the datatypes for equality.
	STDMETHOD(GetConvertFlags)(
			DP_IN const DBCOLUMNINFO *pSrcColumnInfo,		// Source column metadata
			DP_IN const DBCOLUMNINFO *pDestColumnInfo,		// Destination column metadata
			DP_OUT DTSConvertFlags *pConvertFlags			// Output conversion flags
		) PURE;

	// This method allows the Transform Server to convert source data (which may come from
	// the source binding directly, as in the comment examples, or from ad-hoc source data).
	// It uses the following fields in the destination binding (S is fields that are used
	// from a source binding if that is how the source data is stored):
	//	DBBINDING:
	//		obValue					S,D		-- must be bound
	//		obLength				S,D		-- must be bound
	//		obStatus				S,D		-- must be bound
	//		dwPart					S,D		-- must include length, value, status
	//		cbMaxLen				D
	//		wType					S,D
	//		bPrecision				D
	//		bScale					D
	//
	// The destination data is set according to eTransformFlags and pDestBind->dwMemOwner, which
	// is handled as follows:
	//
	// DBMEMOWNER_CLIENTOWNED: normal conversion is done; data is copied from source to destination,
	//		converted as needed, and allocations are done as needed.  Specifically:
	//			BSTR data is deep-copied
	//			BYREF destination data is copied into a CoTaskMemAlloc()'d pointer.
	//			IUnknown and IDispatch pointers are AddRef()'d.
	//		The destination binding data must always be free'd.  The foregoing lists what is freed
	//		(or Release()'d) by IDTSDataConvert::ClearBindingData.
	//
	// DBMEMOWNER_PROVIDEROWNED:  Conversion will attempt to shallow-copy data, avoiding allocations.
	//		This requires that the source and destination datatypes be identical (except for DBTYPE_BYREF).
	//		This is intended as a performance enhancement and requires that the source data remain stable
	//		for the lifetime of the Destination binding (such as while being inserted via the DataPump).
	//		It handles only the following cases:
	//			If the destination type includes DBTYPE_BYREF	// it must therefore be ((W)STR|BYTES)
	//				*pvDestData = pvSrcData (or *pvSrcData if source type is BYREF)
	//				StringTruncation is performed by adjusting destination datalength
	//			else if destination type is BSTR
	//				*pvDestData = *pvSrcData (or **pvSrcData if source type is BYREF)
	//				StringTruncation is NOT checked here as this is a fixed-length datatype
	//			else 
	//				Normal conversion is done, including:
	//					AddRefs of IDispatch/IUnknown pointers
	//					VariantCopy (OLEDB behaviour does not allow PROVIDEROWNED Variant binding).
	// DBMEMOWNER_PROVIDEROWNED binding data will not be freed by IDTSDataConvert::ClearBindingData.
	// If a custom allocator is used for BYREF destination data, then it must be freed by a corresponding
	// custom deallocator, rather than by ClearBindingData.  Therefore, it should be bound ProviderOwned;
	// the pointer will be shallow-copied into the binding by IDTSDataConvert::ConvertToBinding.
	//
	STDMETHOD(ConvertToBinding)(
			DP_IN DBTYPE wSrcType,							// Source datatype:  e.g. pSrcBind->wType
			DP_IN ULONG cbSrcLength,						// Source data length:  e.g. *(reinterpret_cast<ULONG *>(pSrcColumnInfo->pvRowData + pSrcBind->obLength));
			DP_IN DBSTATUS dbsSrcStatus,					// Source data status:  e.g. *(reinterpret_cast<DBSTATUS *>(pSrcColumnInfo->pvRowData + pSrcBind->obStatus));
			DP_IN const BYTE *pvSrcColData,					// Source column data: e.g. pSrcColumnInfo->pvRowData + pSrcBind->obValue;
			DP_IN const DBBINDING *pDestBind,				// Dest binding info
			DP_IN BYTE *pvDestRowData,						// Dest row data; NOT obValue-offset as the Binding will reference it 3 ways (obLength, obValue, obStatus)
			DP_IN DBCOLUMNFLAGS dwDestColumnFlags,			// Dest flags such as nullability
			DP_IN ULONG ulDestColumnSize,					// If nonzero and Dest is BYREF, tested for String Truncation
			DP_IN DTSTransformFlags eTransformFlags			// Transformation flags.  Currently considered:
															//		DTSTransformFlag_AllowStringTruncation
															//		DTSTransformFlag_ForceConvert as it applies to foregoing
		) PURE;

	// This method frees any CLIENTOWNED allocations in the Binding, as discussed in ConvertToBinding.
	// This method always sets length to 0 and status to DBSTATUS_S_ISNULL, and can zeroinit if specified.
	STDMETHOD(ClearBindingData)(
			DP_IN const DBBINDING *pDestBind,				// Dest binding info
			DP_IN BYTE *pvDestRowData,						// Dest row data; NOT obValue-offset as the Binding will reference it 3 ways (obLength, obValue, obStatus)
			DP_IN BOOL bZeroInit							// If TRUE, zero's the data value
		) PURE;
};

///////////////////////////////////////
// IDTSErrorRecords - Allows the caller to append OLEDB Error Records to the current
// thread's IErrorInfo.  The Error Lookup Service is CLSID_DTSErrorLookup.
// This interface is derived from IDispatch and may be used in ActiveX Scripts as
// well as from C/C++.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSErrorRecords
DECLARE_INTERFACE_(IDTSErrorRecords, DTSDataPump_IDispatch)
{
	DTSDataPump_Dispatch_Base(IDTSErrorRecords)

    STDMETHOD(Clear)(THIS) PURE;
	STDMETHOD(Add)(THIS_ DP_IN long Number,
				DP_IN long NativeError,
				DP_IN BSTR Description,
				DP_IN BSTR Source,
				DP_IN BSTR Helpfile,
				DP_IN long Helpid
			) PURE;
};

///////////////////////////////////////
// IDTSDataPumpColumns - Columns collection as exposed to AxScript.
// We expose DTSSource and DTSDestination collections.
// This interface is derived from IDispatch and may be used in ActiveX Scripts as
// well as from C/C++.  This is identical to the ADO.Field interface.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpColumns
DECLARE_INTERFACE_(IDTSDataPumpColumns, DTSDataPump_IDispatch)
{
	DTSDataPump_Dispatch_Base(IDTSDataPumpColumns)

	STDMETHOD(Item)(THIS_ DP_IN VARIANT Index, DP_OUT IDTSDataPumpColumn **pRetVal) PURE;
    STDMETHOD(get__NewEnum)(THIS_ DP_OUT IUnknown **ppEnum) PURE;
    STDMETHOD(get_Count)(THIS_ DP_OUT long *pRetVal) PURE;
};

///////////////////////////////////////
// IDTSDataPumpColumn - Column object as exposed to AxScript.
// These objects make up the DTSSource and DTSDestination collections.
// They provide access to the column value and its metadata
// This interface is derived from IDispatch and may be used in ActiveX Scripts as
// well as from C/C++.  This is identical to the ADO.Field interface.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpColumn
DECLARE_INTERFACE_(IDTSDataPumpColumn, DTSDataPump_IDispatch)
{
	DTSDataPump_Dispatch_Base(IDTSDataPumpColumn)

    STDMETHOD(get_Value)(THIS_ DP_OUT VARIANT *pRetVal) PURE;
    STDMETHOD(put_Value)(THIS_ DP_IN VARIANT NewValue) PURE;
    STDMETHOD(get_ActualSize)(THIS_ DP_OUT long  *pl) PURE;
    STDMETHOD(get_Attributes)(THIS_ DP_OUT long  *pl) PURE;
    STDMETHOD(get_DefinedSize)(THIS_ DP_OUT long  *pl) PURE;
    STDMETHOD(get_Name)(THIS_ DP_OUT BSTR  *pbstr) PURE;
    STDMETHOD(get_Type)(THIS_ DP_OUT long  *pDataType) PURE;
    STDMETHOD(get_Precision)(THIS_ DP_OUT BYTE  *pbPrecision) PURE;
    STDMETHOD(get_NumericScale)(THIS_ DP_OUT BYTE  *pbNumericScale) PURE;
    STDMETHOD(get_OriginalValue)(THIS_ DP_OUT VARIANT  *pvar) PURE;
    STDMETHOD(get_UnderlyingValue)(THIS_ DP_OUT VARIANT  *pvar) PURE;
    STDMETHOD(AppendChunk)(THIS_ DP_IN VARIANT Data) PURE;
    STDMETHOD(GetChunk)(THIS_ DP_IN long Length, DP_OUT VARIANT  *pvar) PURE;
};

///////////////////////////////////////
// IDTSDataPumpLookups - Lookups collection as exposed to AxScript.
// We expose DTSLookups as a collection.
// This interface is derived from IDispatch and may be used in ActiveX Scripts as
// well as from C/C++.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpLookups
DECLARE_INTERFACE_(IDTSDataPumpLookups, DTSDataPump_IDispatch)
{
	DTSDataPump_Dispatch_Base(IDTSDataPumpLookups)

	STDMETHOD(Item)(THIS_ DP_IN VARIANT Index, DP_OUT IDTSDataPumpLookup **pRetVal) PURE;
    STDMETHOD(Get_NewEnum)(THIS_ DP_OUT IUnknown **ppEnum) PURE;
    STDMETHOD(GetCount)(THIS_ DP_OUT long *pRetVal) PURE;
};

///////////////////////////////////////
// IDTSDataPumpLookup - Lookup object as exposed to AxScript.
// These objects make up the DTSLookups collection.
// This interface is derived from IDispatch and may be used in ActiveX Scripts as
// well as from C/C++.  The KeyValues input parameter to the methods is a SafeArray
// of Variant, using the vararg attribute on the methods, for best use in ActiveX
// scripts.  The return value is a variant (if single-valued) or an array of variants
// (if multi-valued) corresponding to the sequence of columns in the single output
// row resulting from execution of the query.  If multiple rows are returned, only
// the first is returned in the output variant.  LastRowCount is used in case an
// app wants to assert that only one row was returned.
///////////////////////////////////////

// This form is understood by scripting languages to take a variable number of
// arguments in the key values specification.  It can be used from C++ as well.
#undef INTERFACE
#define INTERFACE IDTSDataPumpLookup
DECLARE_INTERFACE_(IDTSDataPumpLookup, DTSDataPump_IDispatch)
{
	DTSDataPump_Dispatch_Base(IDTSDataPumpLookup)

    STDMETHOD(get_Name)(THIS_ DP_OUT BSTR  *pbstr) PURE;
	STDMETHOD(get_LastRowCount)(THIS_ LONG *pRetVal) PURE;
    STDMETHOD(Execute)(THIS_ DP_IN SAFEARRAY * KeyValues, DP_OUT VARIANT *pRetVal) PURE;
    STDMETHOD(AddToCache)(THIS_ DP_IN VARIANT DataValues, DP_IN SAFEARRAY * KeyValues) PURE;
    STDMETHOD(RemoveFromCache)(THIS_ DP_IN SAFEARRAY * KeyValues) PURE;
};

// This is a form of the interface which takes a single Variant, more convenient
// for C++ programs which know they'll only have a single key column.  The variant
// may be a single value or may itself contain a safearray.
#undef INTERFACE
#define INTERFACE IDTSDataPumpLookupVariant
DECLARE_INTERFACE_(IDTSDataPumpLookupVariant, IUnknown)
{
    STDMETHOD(Execute)(THIS_ DP_IN VARIANT KeyValues, DP_OUT VARIANT *pRetVal) PURE;
    STDMETHOD(AddToCache)(THIS_ DP_IN VARIANT DataValues, DP_IN VARIANT KeyValues) PURE;
    STDMETHOD(RemoveFromCache)(THIS_ DP_IN VARIANT KeyValues) PURE;
};

////////////////////////////////////////////////////////////////////////////////////////
//
//	Pump-supplied Transform custom-property interfaces.
//
////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////
// IDTSDataPumpTransformScriptProperties - Sets custom properties for the
// ActiveX scripting transformation server.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpTransformScriptProperties
DECLARE_INTERFACE_(IDTSDataPumpTransformScriptProperties, DTSDataPump_IDispatch)
{
	DTSDataPump_Dispatch_Base(IDTSDataPumpTransformScriptProperties)

	STDMETHOD(GetText)(THIS_ BSTR DP_OUT *pRetVal) PURE;
	STDMETHOD(SetText)(THIS_ BSTR DP_IN NewValue) PURE;
	STDMETHOD(GetLanguage)(THIS_ BSTR DP_OUT *pRetVal) PURE;
	STDMETHOD(SetLanguage)(THIS_ BSTR DP_IN NewValue) PURE;
	STDMETHOD(GetFunctionEntry)(THIS_ BSTR DP_OUT *pRetVal) PURE;
	STDMETHOD(SetFunctionEntry)(THIS_ BSTR DP_IN NewValue) PURE;
};

////////////////////////////////////////////////////////////////////////////////////////
//
//	Consumer-supplied interface definitions.
//
////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////
// IDTSDataPumpTransform - Required interface of the "COM Server" instantiated by ServerClsid
// passed to IDTSDataPump::AddTransform.  This interface is retrieved and its methods called
// by the Pump to perform individual transforms. 
//
// ServerParameters allows the DataPump Consumer to instantiate a single instance of an
// IDTSDataPumpTransform implementation and pass it to multiple IDTSDataPump::AddTransform calls.
// This is only useful for custom Transform Servers (the DTS-supplied ones ignore this), and may be
// helpful for internal summations etc.  If this is done, the TransformServer should track this in its
// pvTransformServerData to optimize operations such as AddVariable, On(Row|Transform)Complete, etc.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpTransform
DECLARE_INTERFACE_(IDTSDataPumpTransform, IUnknown)
{
	DTSDataPump_Unknown_Base()

	// Allows the TransformServer to initialize its state for the current Transform.  The output
	// LPBYTE is passed to all subsequent methods, so a single TransformServer instance may be
	// used to implement multiple separate transforms.
	STDMETHOD(Initialize)(THIS_
			DP_IN LPCOLESTR pwzName,							// Transform name
			DP_IN VARIANT ServerParameters,						// Parameters to server for this transform
			DP_OUT LPBYTE *ppvTransformServerData				// Transform server state data.
		) PURE;

	// Validates the schema that will be transformed.  Allows the TransformServer to specify
	// certain modifications to the default binding modes, such as for BLOBs.  The default 
	// p(Src|Dest)ColumnInfo->ppDTSColBinding[ii].eBindModes intialized by the DataPump are:
	//
	// All BLOBs must be ClientOwned by OLEDB spec, so Source and Destination BLOBs are always
	// DTSBindMode_Byref_ClientOwned.
	// 
	// Source:  For efficiency, nonBLOB ((W)STR|BYTES) binding defaults to _Byref_ProviderOwned
	// to avoid unnecessary copying.  BSTR defaults to ProviderOwned.  All other types must be
	// non-Byref ClientOwned by OLEDB spec and behaviour.
	//
	// Destination:  Because the destination data is likely to be the result of a transformation,
	// destination binding always defaults to ClientOwned for all datatypes.  All nonBLOB types are
	// allocated Inline; this includes ((W)STR|BYTES), to minimize per-row (re)allocation overhead.
	//
	// A Transformation which simply passes-thru nonBLOB ((W)STR|BYTES)s or BSTRs from the Source
	// IRowset to the destination (and doesn't use the TransformCopy server, which is supplied for
	// this purpose) should override this to ProviderOwned to avoid unnecessary (re)allocations.
	//
	STDMETHOD(ValidateSchema)(THIS_
			DP_IN LPBYTE pvTransformServerData,					// Transform server state data.
			DP_INOUT LPCDTSTransformColumnInfo pSrcColumnInfo, 	// Source columns and rowdata
			DP_INOUT LPCDTSTransformColumnInfo pDestColumnInfo, // Dest columns and rowdata
			DP_IN IDTSDataConvert *pIDTSDataConvert,			// Pointer to the data conversion interface
			DP_IN DTSTransformFlags eTransformFlags				// Input Flags for Transformation validation and execution
		) PURE;

	// Adds a variable to the TransformServer's execution context.  This is always called once before
	// ValidateSchema, in order to add the IDTSErrorRecords object.
	STDMETHOD(AddVariable)(THIS_ 
			DP_IN LPBYTE pvTransformServerData,					// Transform server state data.
			DP_IN LPCOLESTR pwzName,							// Variable name
			DP_IN BOOL bGlobal,									// For ActiveX scripts, indicates whether this variable's
																// methods must be qualified by the object name.
			DP_IN VARIANT Variable								// Variable value; passed to and updatable by Transform
		) PURE;

	// Executes the transformation for a single row.  This method should return a SUCCEED
	// hr except in catastrophic failure; a FAILED hr here will abort the Pump.  "Normal"
	// errors such as data violations should be handled as a returned pTransformStatus,
	// which will cause IDTSDataPumpErrorSink::OnTransformError to be called.
	//
	// Because some providers may have restrictions on the number of Storage Objects which
	// may be open, Execute() should release any Blob Storage Objects in the source upon
	// completion, rather than waiting for OnRowComplete.  The DataPump handles refcounting
	// for multiple transforms of its buffered Source objects.  If the Blob column is
	// buffered by the DataPump or the Transform has knowledge of the Source Provider, it
	// can defer Release()ing the Source Storage Object until OnRowComplete.  Note that
	// returning DTSTransformStat_SkipFetch (and therefore not releasing the Source Storage
	// Object) may require buffering of the source Blob data.
	STDMETHOD(Execute)(THIS_
			DP_IN LPBYTE pvTransformServerData,					// Transform server state data.
			DP_IN LPCDTSTransformColumnInfo pSrcColumnInfo, 	// Source columns and rowdata
			DP_INOUT LPDTSTransformColumnInfo pDestColumnInfo, 	// Dest columns and rowdata
			DP_IN IDTSDataConvert *pIDTSDataConvert,			// Pointer to the data conversion interface
			DP_OUT LPDTSTransformStatus peTransformStatus		// Result of transform
		) PURE;

	// After a successful Fetch, the pump calls Execute and then attempts to insert the row into the
	// destination IRowsetChange (if one is specified).  OnRowComplete is called for every successful
	// Fetch (whether the Execute() and InsertRow succeeded or failed); this allows the TransformServer
	// to free per-row allocations and CLIENTOWNED data in both source and destination rows (such as
	// by calling pIDTSDataConvert->ClearBindingData).  A FAILED return from OnRowComplete aborts the Pump.
	// hrInsert indicates whether the IRowsetChange::InsertRow() succeeded; eTransformStatus indicates
	// if errors occurred such that InsertRow was not called.
	//
	// Note that OLEDB specifies that IRowsetChange::InsertRow() Releases any contained Storage Objects
	// in the row (but not other types of "allocations"), so the Transform server must be careful not to 
	// call pIDTSDataConvert->ClearBindingData on an already final-released Storage Object (in the event
	// that InsertRow is not called due to a Transform returning an error, the DataPump will release any
	// Storage Objects in the dest row for any Transforms for which Execute was called prior to the erroring
	// Transform, to present a consistent refcounting interface to TransformServers:  If Execute() returned
	// a non-NULL Storage Object in the row, it will be released once before OnRowComplete is called).
	//
	STDMETHOD(OnRowComplete)(THIS_
			DP_IN LPBYTE pvTransformServerData,					// Transform server state data.
			DP_INOUT LPDTSTransformColumnInfo pSrcColumnInfo,	// Source columns and rowdata
			DP_INOUT LPDTSTransformColumnInfo pDestColumnInfo, 	// Dest columns and rowdata
			DP_IN IDTSDataConvert *pIDTSDataConvert,			// Pointer to the data conversion interface
			DP_IN DTSTransformStatus eTransformStatus,			// Result of Execute()
			DP_IN HRESULT hrInsert								// Result of IRowsetChange::InsertRow()
		) PURE;

	// After all rows have been transformed (or the pump has been shutdown due to errors),
	// OnTransformComplete is called to give the TransformServer a chance to clean up all
	// allocations made for the Transform.  OnTransformComplete is called only if ValidateSchema
	// returned successfully.
	STDMETHOD(OnTransformComplete)(THIS_
			DP_IN LPBYTE pvTransformServerData,					// Transform server state data.
			DP_INOUT LPDTSTransformColumnInfo pSrcColumnInfo,	// Source columns and rowdata
			DP_INOUT LPDTSTransformColumnInfo pDestColumnInfo, 	// Dest columns and rowdata
			DP_IN IDTSDataConvert *pIDTSDataConvert				// Pointer to the data conversion interface
		) PURE;
};


///////////////////////////////////////
// IDTSDataPumpErrorSink - Specifies pump error handler sink.  Only one method will
// be called for any row, and the method called indicates where the error was encountered:
// reading from source, transforming, or writing to destination.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpErrorSink
DECLARE_INTERFACE_(IDTSDataPumpErrorSink, IUnknown)
{
	DTSDataPump_Unknown_Base()

	// An error occurred on Binding in CreateAccessor.  This is only useful for designing custom Transform
	// Servers, primarily for diagnosing Blob difficulties.
	STDMETHOD(OnBindingError)(THIS_ 
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN HRESULT hrError,						// The errorcode from CreateAccessor; for Destination if pDestinationRow, else for Source.
			DP_IN LPCDTSTransformColumnInfo pSourceRow,	// Pointer to the source row and binding info.
			DP_IN const DBBINDSTATUS *pSourceDBBindStatus,		// Pointer to source binding status returns.
			DP_IN LPCDTSTransformColumnInfo pDestinationRow,	// Pointer to the destination row and binding info; NULL if from Source Binding error.
			DP_IN const DBBINDSTATUS *pDestinationDBBindStatus	// Pointer to destination binding status returns; NULL if from Source Binding error.
		) PURE;

	// An error occurred during GetNextRows or GetData.
	STDMETHOD(OnSourceError)(THIS_ 
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN LPDTSTransformColumnInfo pSourceRow,	// Pointer to the source row and binding info; NULL if GetNextRows or GetData failed.
			DP_IN HRESULT hrError,						// The errorcode from the OLEDB or system call.
			DP_IN ULARGE_INTEGER uliRow,				// Number of the row failing.
			DP_IN ULONG cErrors,						// Number of error rows encountered so far (including this one).
			DP_OUT BOOL *pbAbort						// Set TRUE by Sink if this error should abort IDTSDataPump::Execute.
														// Otherwise, Execute() continues until MaximumErrorRowCount is exceeded.
		) PURE;

	// An error occurred on one or more Transforms.
	STDMETHOD(OnTransformError)(THIS_ 
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN LPCOLESTR pwzName,					// Transform name
			DP_IN LPBYTE pvTransformUserData,			// User data pointer passed to IDTSDataPump::AddTransform
														// in LPCDTSTransformColumnsSpecification parameter.
			DP_IN IDTSDataPumpTransform *pTransformServer,	// The transform server raising the error; can be QI'd to custom interface for more info.
			DP_IN LPDTSTransformColumnInfo pSourceRow,	// Pointer to the source row and binding info.
			DP_IN DTSTransformStatus TransformStatus,	// Returned status code from the transformation.
			DP_IN HRESULT hrTransform,					// The HRESULT returned from DTSDataPumpTransform::Execute.
			DP_IN ULARGE_INTEGER uliRow,				// Number of the row failing.
			DP_IN ULONG cErrors,						// Number of error rows encountered so far (including this one).
			DP_OUT BOOL *pbAbort						// Set TRUE by Sink if this error should abort IDTSDataPump::Execute.
														// Otherwise, Execute() continues until MaximumErrorRowCount is exceeded.
		) PURE;

	// An error occurred during InsertRow.
	STDMETHOD(OnDestinationError)(THIS_ 
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN LPDTSTransformColumnInfo pSourceRow,	// Pointer to the source row.
			DP_IN LPDTSTransformColumnInfo pDestinationRow,	// Pointer to the destination row and binding info; NULL if prior to transform execution.
			DP_IN HRESULT hrError,						// The errorcode from the OLEDB or system call.
			DP_IN ULARGE_INTEGER uliRow,				// Number of the row failing.
			DP_IN ULONG cErrors,						// Number of error rows encountered so far (including this one).
			DP_OUT BOOL *pbAbort						// Set TRUE by Sink if this error should abort IDTSDataPump::Execute.
														// Otherwise, Execute() continues until MaximumErrorRowCount is exceeded.
		) PURE;
};

///////////////////////////////////////
// IDTSDataDrivenQuerySink - Specifies event sink for Data Driven Queries.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataDrivenQuerySink
DECLARE_INTERFACE_(IDTSDataDrivenQuerySink, IUnknown)
{
	DTSDataPump_Unknown_Base()

	STDMETHOD(OnDDQBindingError)(THIS_ 
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN DTSTransformStatus fQueryType,		// Insert, Update, Delete, or User Query.
			DP_IN HRESULT hrError,						// The errorcode from CreateAccessor for Command parameters
			DP_IN LPCDTSTransformColumnInfo pDestinationRow,	// Pointer to the destination row and transform binding info
			DP_IN ULONG cParameterColumns,				// Number of parameter columns
			DP_IN const DBBINDING *pParameterDBBinding,	// Pointer to destination parameter bindings
			DP_IN const DBBINDSTATUS *pParameterDBBindStatus	// Pointer to destination parameter binding status returns
		) PURE;

	STDMETHOD(OnDDQCommandError)(THIS_ 
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN DTSTransformStatus fQueryType,		// Insert, Update, Delete, or User Query.
			DP_IN LPDTSTransformColumnInfo pSourceRow,	// Pointer to the source row.
			DP_IN LPDTSTransformColumnInfo pDestinationRow,	// Pointer to the destination row and binding info.
			DP_IN HRESULT hrError,						// The errorcode from the OLEDB or system call.
			DP_IN ULARGE_INTEGER uliRow,				// Number of the row failing.
			DP_IN ULONG cErrors,						// Number of error rows encountered so far (including this one).
			DP_OUT BOOL *pbAbort						// Set TRUE by Sink if this error should abort IDTSDataPump::Execute.
														// Otherwise, Execute() continues until MaximumErrorRowCount is exceeded.
		) PURE;

	STDMETHOD(OnDDQCommandComplete)(THIS_ 
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN DTSTransformStatus fQueryType,		// Insert, Update, Delete, or User Query.
			DP_IN LPDTSTransformColumnInfo pSourceRow,	// Pointer to the source row.
			DP_IN LPDTSTransformColumnInfo pDestinationRow,	// Pointer to the destination row and binding info.
			DP_IN LONG cDestinationRowsAffected,		// Rows affected by Command; -1 if provider unable to determine.
			DP_IN ULARGE_INTEGER uliRow					// Number of the source row for which the Query was Execute()d.
		) PURE;
};

///////////////////////////////////////
// IDTSCustomTransformUI - 
// optional interface to be implemented by custom transform providers - used by DTS UI to configure the transforms
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSCustomTransformUI
DECLARE_INTERFACE_(IDTSCustomTransformUI, IUnknown)
{
	DTSDataPump_Unknown_Base()

	STDMETHOD(Initialize)(THIS_ DP_IN LPUNKNOWN pDTSPkgTransformObject) PURE;
	STDMETHOD(New)(THIS_ DP_IN long hwndParent) PURE;
	STDMETHOD(Edit)(THIS_ DP_IN long hwndParent) PURE;
	STDMETHOD(Delete)(THIS_ DP_IN long hwndParent) PURE;
	STDMETHOD(Help)(THIS_ DP_IN long hwndParent) PURE;
};

///////////////////////////////////////
// IDTSDataPumpProgressSink - Progress indicator event sink.
///////////////////////////////////////

#undef INTERFACE
#define INTERFACE IDTSDataPumpProgressSink
DECLARE_INTERFACE_(IDTSDataPumpProgressSink, IUnknown)
{
	DTSDataPump_Unknown_Base()

	STDMETHOD(OnIntervalComplete)(THIS_
			DP_IN LPBYTE pvExecUserData,				// User data pointer passed to IDTSDataPump::Execute
			DP_IN ULARGE_INTEGER uliRowsComplete,		// Total Source Rows processed at this interval (includes those skipped)
			DP_OUT BOOL *pbAbort						// Set TRUE by Sink to abort IDTSDataPump::Execute.
		) PURE;
};

/////////////////////////////////////////////////////////////////////////////////
// DTS Repository-support interfaces.
/////////////////////////////////////////////////////////////////////////////////

// Repository interfaces and definitions are shared between DTSDataPump and DTSPackage.

#ifdef OBJID_DtsTransformationTask

// A covering utility interface around a Repository object, provided by the DTS Package
// when requesting repository storage from a custom Task or Transformation.  This interface
// is passed to IDTSRepositoryStorage methods during DTSPackage.SaveToRepository.
#undef INTERFACE
#define INTERFACE IDTSRepositoryProvider
DECLARE_INTERFACE_(INTERFACE, IUnknown)
{
	DTSDataPump_Unknown_Base()

	// Return a reference to the Repository object.
	STDMETHOD(GetRepository)(THIS_
			DP_OUT IRepository **ppIRepository				// The repository object.
		) PURE;

	// Creates an object and sets its name.
	STDMETHOD(CreateObject)(THIS_
			DP_IN LPCOLESTR wzObjidClass					// Repository class to create
			, DP_IN LPCOLESTR wzObjidInstance				// class instance (object) id, or NULL
			, DP_IN LPCOLESTR wzInstanceName				// class instance (object) name, or NULL
			, DP_OUT IRepositoryObject **ppRepositoryObject	// created object
		) PURE;

	// Finds an IDbmConnection object for a DTS connection in the associated DTS Package.
	STDMETHOD(FindConnection)(THIS_
			DP_IN LPCOLESTR wzName							// DTSConnection.Name
			, DP_IN long lID								// DTSConnection.ID
			, DP_OUT IRepositoryDispatch **ppIDbmConnection	// output object
		) PURE;

	// When a custom Task or Transformation references a table or view, it should create a
	// relationship to that table or view if the appropriate datasource and catalog's metadata
	// has been scanned (by dbscanner) into the Repository.  To do so, the IDTSRepositoryStorage
	// implementation should call FindScannedObject, passing the name of the table or view
	// to be referenced.  Note that this name should be qualified as necessary to resolve
	// ambiguity, if multi-part names are supported by the connection provider.  This qualification
	// must be done according to DBPROP_CATALOGUSAGE and DBPROP_SCHEMAUSAGE, and the following
	// DBLITERALs:
	//		DBLITERAL_QUOTE_PREFIX
	//		DBLITERAL_QUOTE_SUFFIX
	//		DBLITERAL_CATALOG_SEPARATOR
	//		DBLITERAL_SCHEMA_SEPARATOR
	//
	// DTSPackage.SaveToRepository will search for a scanned catalog contained within any
	// IDbmDataSource with IsPublic TRUE.  A table or view resides in the repository as follows:
	//		Root(IUmlPackage).Elements
	//			... possibly some intervening level of package or system...
	//			IDbmDataSource(IUmlPackage).Elements
	//				IDbmDeployedCatalog(IUmlPackage).Elements
	//					IDbmSchema(IUmlPackage).Elements
	//						IDbmDeployedTable, IDbmDeployedView
	// The catalog in which wzObjectName is resolved is determined by the first name found in
	// the following order:
	//		A catalog name parsed from wzObjectName
	//		DBPROP_CURRENTCATALOG after IDTSConnection.OpenConnection; this may be set by either of:
	//			IDTSConnection.DefaultCatalog
	//			IDTSConnection.ConnectionProperties(DBPROP_INIT_CATALOG)
	//		If DBPROP_CURRENTCATALOG is not supported, a placeholder catalog is 
	//			created by the scanner; this catalog is used to resolve scanned object references.
	//		
	// The schema in which wzObjectName is resolved is determined by the first name found in
	// the following order:
	//		A schema name parsed from wzObjectName
	//		IDTSConnection.UserID
	//		IDTSConnection.ConnectionProperties(DBPROP_AUTH_USERID)
	//
	// Because the connection's UserID may be simply a login id and different from the actual
	// object owner, wzObjectName should be qualified.  Only one schema will be searched for the
	// object; that schema is determined by:
	//		If a Schema-qualified wzObjectName is passed, that Schema is searched.
	//		Else if only one Schema is specified, it is searched.
	//		Else if a UserID is specified, it is used.
	//		Else EREP_OBJ_NOTFOUND.
	//
	// FindScannedObject returns the following, in order:
	//		If the call to DTSPackage.SaveToRepository specified that no scanner resolution be done,
	//		FindScannedObject returns NULL and S_FALSE.  In this case, AddUnscannedObject should be
	//		called, to create an DTSPackage-level object for AddTransformationUses to relate to.
	//
	//		If the provider does not support SchemaRowsets (necessary for scan), FindScannedObject
	//		returns NULL and S_FALSE.
	//
	//		If the catalog has not been scanned, or if the call to DTSPackage.SaveToRepository
	//		specified to rescan, then the catalog is scanned.  Any error from the dbscanner (such as
	//		the catalog not being found) is returned.
	//
	//		If wzObjectName is not found, EREP_OBJ_NOTFOUND is returned.
	//
	//		If wzObjectName is not found uniquely, such as an unqualified name appearing in more than
	//		one schema, EREP_OBJ_NOTFOUND is returned.
	//
	//		If wzObjectName is found uniquely, the IDbmDeployedTable or IDbmDeployedView is placed in
	//		ppIScannedObject and S_OK is returned.
	//
	// Note that FindScannedObject should not be called for an IDbmQuery object, as these are not
	// scanned into the repository as part of a Catalog; they are owned by the connection consumer.
	// IDbmQuery objects should be added via AddUnscannedObject.
	//
	// Generally a custom Task or Transformation will do the following (with most error handling omitted
	// for brevity):
	//	pIRepositoryProvider->CreateObject(OBJID_MyCustomTaskOrTransform
	//			, NULL
	//			, wzObjectName
	//			, &pICustomTaskOrTransform);
	//	if (referencing a table or view) {
	//		if FAILED(pIRepositoryProvider->FindScannedObject(<name>
	//			, IID_IRepositoryObject
	//			, pIDbmConnection
	//			, &pINewObject))
	//			return error;
	//	}
	//	if (NULL == pUnk) {
	//		pIRepositoryProvider->CreateObject(<parameters for the table, view, query, or other object>,
	//			, &pINewObject);
	//		pIRepositoryProvider->AddUnscannedObject(pIDbmConnection
	//			, pINewObject);
	//	}
	//	pIRepositoryProvider->AddTransformationUses(L"Source Table"
	//			, pICustomTaskOrTransform
	//			, pINewObject);
	//
	STDMETHOD(FindScannedObject)(THIS_
			DP_IN LPCOLESTR wzObjectName					// Name of the object (may be qualified by catalog.schema.name)
			, DP_IN REFIID iidToGet							// an IID the object must support; ignored if IID_NULL
			, DP_IN IRepositoryDispatch *pIDbmConnection	// Connection object (e.g. from FindConnection)
			, DP_OUT IRepositoryObject **ppIScannedObject	// returns scanned object or NULL on error.
		) PURE;

	// This method adds an object to the repository as a way for AddTransformationUses to form a
	// relationship.  This object is not visible outside the scope of the saved DTSPackage.  pINewObject
	// is created (e.g. by CreateObject) and may be a table or view, or query, or a specialization (derived
	// class) of one, according to the following mapping:
	//		Object type		Must support		Added to
	//		-----------		------------		---------
	//		Query			ITfmQuery			ITfmTransformation(IUmlType).Members
	//											ITfmTransformationTask(IUmlType).Members
	//		Table			IDbmDeployedTable	Package-local DataSource/Catalog/Schema
	//		View			IDbmDeployedView	Package-local DataSource/Catalog/Schema
	//		other			IUmlMember			ITfmTransformation(IUmlType).Members
	//											ITfmTransformationTask(IUmlType).Members
	//
	STDMETHOD(AddUnscannedObject)(THIS_
			DP_IN IRepositoryDispatch *pIDbmConnection		// Connection object (e.g. from FindConnection)
			, DP_IN IRepositoryObject *pINewObject			// Task/Transform-created object.
		) PURE;

	// This method creates a relationship between an ITfmTransformation or ITfmTransformationTask
	// and an IDbmColumnSet specialization (such as an IDbmDeployedTable, IDbmDeployedView, or ITfmQuery)
	// via the ITfmTransformationUses specialization of IUmlDependency, where
	//		ITfmTransformationUses(IUmlDependency).SourceElement = pITaskOrTransform
	//		ITfmTransformationUses(IUmlDependency).TargetElement = pINewObject
	//
	// Any dependencies added in this manner can be retrieved during LoadFromRepository by:
	//		pITaskOrTransform(IID_IUmlElement).TargetDependencies
	//
	STDMETHOD(AddTransformationUses)(THIS_
			DP_IN LPCOLESTR wzDependencyType				// A string describing the dependency; e.g., L"Source Table".
			, DP_IN IRepositoryObject *pITaskOrTransform	// Task/Transform-created object.
			, DP_IN IRepositoryObject *pINewObject			// Task/Transform-created object.
		) PURE;

	// Creates a datatype object which maps the passed DBTYPE and other information to
	// its Repository equivalent, and creates and returns a matching object.
	STDMETHOD(CreateMappedDatatypeObject)(THIS_
			DP_IN DBTYPE dbType								// The OLEDB datatype
			, DP_IN LONG lSize								// Column size in characters (ignored if a fixed-length datatype)
			, DP_IN LONG lPrecision							// Column precision if DECIMAL or NUMERIC
			, DP_IN LONG lScale								// Column scale if DECIMAL or NUMERIC
			, DP_OUT IRepositoryObject **ppRepositoryObject	// output object
		) PURE;

	// Gets information from a datatype object created by CreateMappedDataTypeObject.
	STDMETHOD(GetMappedDatatypeInfo)(THIS_
			DP_IN IRepositoryObject *pRepositoryObject		// input object
			, DP_OUT DBTYPE *pdbType						// The OLEDB datatype
			, DP_OUT LONG *plSize							// Column size in characters (ignored if a fixed-length datatype)
			, DP_OUT LONG *plPrecision						// Column precision if DECIMAL or NUMERIC
			, DP_OUT LONG *plScale							// Column scale if DECIMAL or NUMERIC
		) PURE;
};

// If a custom task or custom transform server wants to manage its Repository persistence itself,
// it must implement IDTSRepositoryStorage.  Otherwise, the Package will simply enumerate the
// OleAutomation properties of the custom task/transform IDispatch and store all those which
// can be Set() as (Variant)TaggedValues of an IDtsCustomTask repository object.
#undef INTERFACE
#define INTERFACE IDTSRepositoryStorage
DECLARE_INTERFACE_(INTERFACE, IUnknown)
{
	DTSDataPump_Unknown_Base()

	// The implementation must create its own Repository object via pIRepositoryProvider->CreateObject,
	// and the returned ppIRepositoryObject must be fully populated and must support IDtsCustomTask
	// (if a custom DTSPackage Task) or IDts(Blob)Transformation (if a custom DTSPump Transform server).
	// After this method returns, the DTSPackage will set properties for Task Name via INamedObject::Name
	// and ServerID (the ProgID or string form of CLSID by which the custom task/transformation server is
	// CoCreateInstance()'d) and any other base-class values needed.  Custom objects should not set tagged
	// values in the base object classes, to avoid possible name conflicts.
	STDMETHOD(SaveToRepository)(THIS_
			DP_IN IDTSRepositoryProvider *pIRepositoryProvider
			, DP_OUT IRepositoryObject **ppIRepositoryObject
		) PURE;

	// The implementation loads its own properties from this object.  If access to the IRepository
	// object is necessary, use pIRepositoryObject->get_Repository().
	STDMETHOD(LoadFromRepository)(THIS_
			DP_IN IDTSRepositoryProvider *pIRepositoryProvider
			, DP_IN IRepositoryObject *pIRepositoryObject
		) PURE;
};

#endif // def OBJID_DtsTransformationTask

#endif // ndef DTSDataPump_VersionOnly

#endif // ndef DTSDataPump_ODL_

#pragma option pop /*P_O_Pop*/
#endif // DTSDataPump_H_
