2008-05-18 18:58 UTC+0100 Viktor Szakats (harbour.01 syenar hu)

+ contrib/rddads/tests/datad.prg
     + Added new test program for ADS DD/SQL functionality.
       Kindly sent by Brian Hays.
       NOTE: The code will show some errors on SQL execution.
       I couldn't investigate, but it does the same with older 
       versions of rddads, too.

   * contrib/rddads/ads1.c
     ! Two occurences of AdsShowError() calls guarded with 
       DEBUG. This call pops up a visual dialog box on screen 
       and halts execution until this is confirmed by the user. 
       Not very desirable inside RDD code in real life 
       environments. Proper error code were and are still 
       returned in these cases.

   * contrib/rddads/adsfunc.c
     * Final reformat and optimization.
     ! Fixed to not call AdsShowError() by default, only when 
       DEBUG is #define-d. For about the same reason as above. 
       Caller should use AdsGetLastError() to get the error 
       code and string and present it to the user as required.
     + QUESTIONs added.

   * contrib/rddads/adsmgmnt.c
     * ADSMGGETOPENTABLES() changed to return empty array 
       instead of error code in case of error. This way it 
       now behaves consistently with the rest of the mgmnt 
       functions. Error code and string can be get by 
       the caller using ADSGETLASTERROR().
     + ADSMGGETOPENTABLES2() added, which is similar to 
       ADSMGGETOPENTABLES(), but will also return lock type 
       for all tables, this way clearing a long standing 
       TODO in the source.
This commit is contained in:
Viktor Szakats
2008-05-18 17:01:15 +00:00
parent 522f5c7daf
commit 7fed843928
5 changed files with 430 additions and 667 deletions

View File

@@ -8,6 +8,42 @@
2008-12-31 13:59 UTC+0100 Foo Bar <foo.bar@foobar.org>
*/
2008-05-18 18:58 UTC+0100 Viktor Szakats (harbour.01 syenar hu)
+ contrib/rddads/tests/datad.prg
+ Added new test program for ADS DD/SQL functionality.
Kindly sent by Brian Hays.
NOTE: The code will show some errors on SQL execution.
I couldn't investigate, but it does the same with older
versions of rddads, too.
* contrib/rddads/ads1.c
! Two occurences of AdsShowError() calls guarded with
DEBUG. This call pops up a visual dialog box on screen
and halts execution until this is confirmed by the user.
Not very desirable inside RDD code in real life
environments. Proper error code were and are still
returned in these cases.
* contrib/rddads/adsfunc.c
* Final reformat and optimization.
! Fixed to not call AdsShowError() by default, only when
DEBUG is #define-d. For about the same reason as above.
Caller should use AdsGetLastError() to get the error
code and string and present it to the user as required.
+ QUESTIONs added.
* contrib/rddads/adsmgmnt.c
* ADSMGGETOPENTABLES() changed to return empty array
instead of error code in case of error. This way it
now behaves consistently with the rest of the mgmnt
functions. Error code and string can be get by
the caller using ADSGETLASTERROR().
+ ADSMGGETOPENTABLES2() added, which is similar to
ADSMGGETOPENTABLES(), but will also return lock type
for all tables, this way clearing a long standing
TODO in the source.
2008-05-18 09:22 UTC+0100 Viktor Szakats (harbour.01 syenar hu)
* contrib/rddads/adsfunc.c
+ QUESTION added.

View File

@@ -2710,7 +2710,9 @@ static ERRCODE adsCreate( ADSAREAP pArea, LPDBOPENINFO pCreateInfo )
if( uRetVal != AE_SUCCESS )
{
#ifdef DEBUG
AdsShowError( ( UNSIGNED8 * ) "Error" );
#endif
return FAILURE;
}
/*
@@ -4485,7 +4487,9 @@ static ERRCODE adsLock( ADSAREAP pArea, LPDBLOCKINFO pLockInfo )
default :
/* This should probably throw a real error... */
#ifdef DEBUG
AdsShowError( ( UNSIGNED8 * ) "Error in pLockInfo->uiMethod" );
#endif
pLockInfo->fResult = FALSE;
return FAILURE;
}

File diff suppressed because it is too large Load Diff

View File

@@ -439,21 +439,18 @@ HB_FUNC( ADSMGGETUSERNAMES )
*/
HB_FUNC( ADSMGGETLOCKOWNER )
{
UNSIGNED32 ulRetVal;
UNSIGNED16 pusLockType;
UNSIGNED16 pusLockType = 0;
UNSIGNED16 usStructSize = sizeof( ADS_MGMT_USER_INFO );
ADS_MGMT_USER_INFO * pstUserInfo;
pstUserInfo = ( ADS_MGMT_USER_INFO * ) hb_xgrab( sizeof( ADS_MGMT_USER_INFO ) );
ulRetVal = AdsMgGetLockOwner( s_hMgmtHandle,
( UNSIGNED8 * ) hb_parcx( 1 ) /* pucTableName */,
( UNSIGNED32 ) hb_parnl( 2 ) /* ulRecordNumber */,
pstUserInfo,
&usStructSize,
&pusLockType );
if( ulRetVal == AE_SUCCESS )
if( AdsMgGetLockOwner( s_hMgmtHandle,
( UNSIGNED8 * ) hb_parcx( 1 ) /* pucTableName */,
( UNSIGNED32 ) hb_parnl( 2 ) /* ulRecordNumber */,
pstUserInfo,
&usStructSize,
&pusLockType ) == AE_SUCCESS )
{
hb_reta( 5 );
hb_storc( ( char * ) pstUserInfo->aucUserName , -1, 1 ); /* Machine name under NT */
@@ -468,7 +465,7 @@ HB_FUNC( ADSMGGETLOCKOWNER )
hb_stornl( pusLockType, -1, 5 ); /* type of lock */
}
else
hb_retnl( ulRetVal );
hb_reta( 0 );
hb_xfree( pstUserInfo );
@@ -478,11 +475,8 @@ HB_FUNC( ADSMGGETLOCKOWNER )
#endif
}
/* TODO: We're throwing away the locktype info. First edition
* should have returned a 2-dim array. Perhaps see if a 4th arg
* is passed as an (empty) array, if so populate parallel array
* of locktypes. OR pass a logical to tell it to return 2-dim array.
*/
/* NOTE: For a newer edition of this function, which also returns locktype
info, see ADSMGGETOPENTABLES2(). */
HB_FUNC( ADSMGGETOPENTABLES ) /* nMaxNumberOfFilesToReturn, cUserName, nConnection */
{
UNSIGNED16 usArrayLen = ISNUM( 1 ) ? ( UNSIGNED16 ) hb_parni( 1 ) : 300;
@@ -502,10 +496,50 @@ HB_FUNC( ADSMGGETOPENTABLES ) /* nMaxNumberOfFilesToReturn, cUserName, nConnecti
UNSIGNED16 ulCount;
for( ulCount = 1; ulCount <= usArrayLen; ulCount++ )
{
hb_itemPutC( hb_arrayGetItemPtr( pArray, ( ULONG ) ulCount ), ( char * ) astOpenTableInfo[ ulCount - 1 ].aucTableName );
/* UNSIGNED16 astOpenTableInfo[ ulCount - 1 ].usLockType; */ /* Advantage locking mode */
hb_itemReturnRelease( pArray );
}
else
hb_reta( 0 );
hb_xfree( astOpenTableInfo );
#if HB_TR_LEVEL >= HB_TR_INFO
if( usStructSize > sizeof( ADS_MGMT_TABLE_INFO ) )
HB_TRACE(HB_TR_INFO, ("%s returned extra data; available with newer client lib.", "AdsMgGetOpenTables()"));
#endif
}
HB_FUNC( ADSMGGETOPENTABLES2 ) /* nMaxNumberOfFilesToReturn, cUserName, nConnection */
{
UNSIGNED16 usArrayLen = ISNUM( 1 ) ? ( UNSIGNED16 ) hb_parni( 1 ) : 300;
UNSIGNED16 usStructSize = sizeof( ADS_MGMT_TABLE_INFO );
ADS_MGMT_TABLE_INFO * astOpenTableInfo;
astOpenTableInfo = ( ADS_MGMT_TABLE_INFO * ) hb_xgrab( sizeof( ADS_MGMT_TABLE_INFO ) * usArrayLen );
if( AdsMgGetOpenTables( s_hMgmtHandle,
( UNSIGNED8 * ) ( hb_parclen( 2 ) > 0 ? hb_parc( 2 ) : NULL ) /* pucUserName */,
( UNSIGNED16 ) hb_parni( 3 ) /* usConnNumber */, /* = HB_ADS_PARCONNECTION( 3 ) only valid for netware so don't default to current, only take a passed value */
astOpenTableInfo,
&usArrayLen,
&usStructSize ) == AE_SUCCESS )
{
PHB_ITEM pArray = hb_itemArrayNew( usArrayLen );
UNSIGNED16 ulCount;
for( ulCount = 1; ulCount <= usArrayLen; ulCount++ )
{
PHB_ITEM pArrayItm = hb_arrayGetItemPtr( pArray, ulCount );
hb_arrayNew( pArrayItm, 2 );
hb_itemPutC( hb_arrayGetItemPtr( pArrayItm, 3 ),
( char * ) astOpenTableInfo[ ulCount - 1 ].aucTableName );
hb_itemPutNI( hb_arrayGetItemPtr( pArrayItm, 2 ),
astOpenTableInfo[ ulCount - 1 ].usLockType ); /* Advantage locking mode */
}
hb_itemReturnRelease( pArray );
}
else

View File

@@ -0,0 +1,152 @@
/*
* $Id$
*/
/*
Demo of ADS Connection handling and Data Dictionaries
*/
#include "ads.ch"
REQUEST ADS
FUNCTION MAIN
local n
local cErr, cStr
local aStru := {{ "ID", "A", 1, 0}, {"Name", "C", 50, 0}, {"address", "C", 50, 0}, {"city", "C", 30, 0}, {"Age", "n", 3, 0}}
local hConnection1, hConnection2
local lIsDict := .f.
CLS
RddSetDefault("ADT")
AdsSetServerType ( 7 )
SET Filetype to ADT
? "Default connection is 0:", adsConnection()
fErase("harbour.add")
fErase("harbour.ai")
fErase("harbour.am")
fErase("Table1.adt")
fErase("Table1.adi")
fErase("Table2.adt")
fErase("Table2.adi")
// now Create a Data dictionary and the files if not exist
IF !File("harbour.add")
ADSDDCREATE("harbour.add",, "(x)Harbour ADS demo for data dictionary")
// This also creates an Administrative Handle that is set as the default
? "Default connection is now this admin handle:", adsConnection()
AdsDisconnect() // disconnect current default.
// if you wanted to retain this connection for later, you could use
// hAdminCon := adsConnection(0)
// This get/set call would return the current connection, then set it to 0
? "Default connection is now this handle (zero):", adsConnection()
// now create two free tables with same structure
DbCreate("Table1", aStru)
DbCreate("Table2", aStru)
//now create an index
USE table1 new
INDEX ON id TAG codigo
USE
USE table2 new
INDEX ON id TAG codigo
USE
ENDIF
// now the magic
IF adsConnect60("harbour.add", 7/* All types of connection*/, "ADSSYS", "", , @hConnection1 )
// The connection handle to harbour.add is now stored in hConnection1,
// and this is now the default connection
? "Default connection is now this handle:", adsConnection()
? " Is it a Data Dict connection? (ADS_DATABASE_CONNECTION=6, "
? " ADS_SYS_ADMIN_CONNECTION=7):", AdsGetHandleType()
// Add one user
AdsDDCreateUser(, "Luiz", "papael", "This is user Luiz")
IF adsddGetUserProperty("Luiz", ADS_DD_COMMENT, @cStr, hConnection1)
? "User comment:", cStr
ELSE
? "Error retrieving User comment"
ENDIF
? "Add the tables"
AdsDDaddTable("Table1", "table1.adt", "table1.adi")
?
IF ! AdsDDaddTable("Customer Data", "table2.adt", "table2.adi")
// notice the "long table name" for file Table2.adt. Later open it with "Customer Data" as the table name
? "Error adding table:", adsGetLastError(@cErr), cErr
ENDIF
? "Set new admin pword on default connection:", AdsDDSetDatabaseProperty( ADS_DD_ADMIN_PASSWORD, "newPWord" )
? "Set new admin pword on explicit connection:", AdsDDSetDatabaseProperty( ADS_DD_ADMIN_PASSWORD, "newPWord", hConnection1 )
? "Clear admin pword:", AdsDDSetDatabaseProperty( ADS_DD_ADMIN_PASSWORD, "" )
ELSE
? "Error connecting to harbour.add!"
ENDIF
AdsDisconnect(hConnection1)
hConnection1 := nil // you should always reset a variable holding a handle that is no longer valid
? "Default connection is back to 0:", adsConnection()
? "Is a Data Dict connection? (AE_INVALID_HANDLE = 5018):", AdsGetHandleType()
// now open the tables and put some data
IF AdsConnect60("harbour.add", 7/* All types of connection*/, "Luiz", "papael", , @hConnection1)
? "Default connection is now this handle:", adsConnection()
? "Connection type?", AdsGetHandleType()
FOR n := 1 TO 100
IF AdsCreateSqlStatement("Data2", 3)
IF !AdsExecuteSqlDirect(" insert into Table1( name,address,city,age) VALUES( '" + strzero(n)+"','"+strzero(n)+"','"+strzero(n)+"'," +str(n)+ ")" )
ShowAdsError()
ENDIF
USE
ENDIF
NEXT
FOR n := 1 TO 100
IF AdsCreateSqlStatement("Data1", 3)
IF !AdsExecuteSqlDirect(" insert into " +'"Customer Data"'+"( name,address,city,age) VALUES( '"+ strzero(n)+"','"+strzero(n)+"','"+strzero(n)+"'," +str(n)+")" )
ShowAdsError()
ENDIF
USE
ENDIF
NEXT
// AdsUseDictionary(.t.) this function no longer is needed; the system knows if it's using a Data Dictionary connection
// Open the "long table name" for Table2
DbUseArea(.t.,, "Customer Data", "custom", .t., .f.)
? "Press a key to browse", alias()
inkey(0)
Browse()
USE
USE table1 new
Browse()
USE
ENDIF
AdsDisconnect(hConnection1)
@ 24, 0 say ""
RETURN NIL
PROC ShowAdsError()
LOCAL cMsg
AdsGetLastError( @cMsg )
Alert( cMsg )
RETURN