PAB3-DB-Driver-Mysql

 view release on metacpan or  search on metacpan

Mysql.xs  view on Meta::CPAN



#/******************************************************************************
# * num_rows( resid )
# ******************************************************************************/

void
num_rows( resid )
	void * resid;
PREINIT:
	dMY_CXT;
#ifndef HAS_UV64
	char tmp[21], *p1;
#endif
CODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
#ifdef HAS_UV64
		ST(0) = sv_2mortal( newSVuv( ( (MY_RES *) resid )->numrows ) );
#else
		if( ( (MY_RES *) resid )->numrows <= 0xffffffff ) {
			ST(0) = sv_2mortal( newSVuv( ( (MY_RES *) resid )->numrows ) );
		}
		else {
			p1 = my_ltoa( tmp, ( (MY_RES *) resid )->numrows, 10 );
			ST(0) = sv_2mortal( newSVpvn( tmp, p1 - tmp ) );
		}
#endif
		break;
	case MY_TYPE_STMT:
#ifdef HAS_UV64
		ST(0) = sv_2mortal( newSVuv( ( (MY_STMT *) resid )->numrows ) );
#else
		if( ( (MY_STMT *) resid )->numrows <= 0xffffffff ) {
			ST(0) = sv_2mortal( newSVuv( ( (MY_STMT *) resid )->numrows ) );
		}
		else {
			p1 = my_ltoa( tmp, ( (MY_STMT *) resid )->numrows, 10 );
			ST(0) = sv_2mortal( newSVpvn( tmp, p1 - tmp ) );
		}
#endif
		break;
	default:
		ST(0) = &PL_sv_undef;
		break;
	}


#/******************************************************************************
# * fetch_names( resid )
# ******************************************************************************/

void
fetch_names( resid )
	void * resid;
PREINIT:
	dMY_CXT;
	MYSQL_RES *res = NULL;
	MYSQL_FIELD *fields;
	int num_fields, i;
PPCODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		res = ( (MY_RES *) resid )->res;
		break;
	case MY_TYPE_STMT:
		res = ( (MY_STMT *) resid )->meta;
		break;
	default:
		goto exit;
	}
	fields = mysql_fetch_fields( res );
	num_fields = mysql_num_fields( res );
	for( i = 0; i < num_fields; i ++ ) {
		XPUSHs( sv_2mortal(
			newSVpvn( fields[i].name, fields[i].name_length )
		) );	
	}
exit:
	{}


#/******************************************************************************
# * fetch_field( resid [, offset] )
# ******************************************************************************/

void
fetch_field( resid, offset = -1 )
	void * resid;
	long offset;
PREINIT:
	dMY_CXT;
	MYSQL_RES *res;
	MYSQL_FIELD *field;
	unsigned int flags;
PPCODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		res = ( (MY_RES *) resid )->res;
		break;
	case MY_TYPE_STMT:
		res = ( (MY_STMT *) resid )->meta;
		break;
	default:
		goto exit;
	}
	if( offset >= 0 )
		mysql_field_seek( res, offset );
	field = mysql_fetch_field( res );
	if( field == NULL ) goto exit;
	XPUSHs( sv_2mortal( newSVpvn( "name", 4 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( field->name, field->name_length ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "table", 5 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( field->table, field->table_length ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "catalog", 7 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( field->catalog, field->catalog_length ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "length", 6 ) ) );
	XPUSHs( sv_2mortal( newSVuv( field->length ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "default", 7 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( field->def, field->def_length ) ) );
	flags = field->flags;
	XPUSHs( sv_2mortal( newSVpvn( "nullable", 8 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & NOT_NULL_FLAG ) == 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "primary", 6 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & PRI_KEY_FLAG ) != 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "unique", 6 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & UNIQUE_KEY_FLAG ) != 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "index", 5 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & MULTIPLE_KEY_FLAG ) != 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "identity", 8 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & AUTO_INCREMENT_FLAG ) != 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "numeric", 7 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & NUM_FLAG ) != 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "binary", 6 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & BINARY_FLAG ) != 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "zerofill", 8 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & ZEROFILL_FLAG ) != 0 ) ) );
	XPUSHs( sv_2mortal( newSVpvn( "unsigned", 8 ) ) );
	XPUSHs( sv_2mortal( newSViv( ( flags & UNSIGNED_FLAG ) != 0 ) ) );
exit:
	{}


#/******************************************************************************
# * field_seek( resid [, offset] )
# ******************************************************************************/

U32
field_seek( resid, offset = 0 )
	void * resid;
	U32 offset;
PREINIT:
	dMY_CXT;
CODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		RETVAL = mysql_field_seek( ( (MY_RES *) resid )->res, offset );
		break;
	case MY_TYPE_STMT:
		RETVAL = mysql_field_seek( ( (MY_STMT *) resid )->meta, offset );
		break;
	default:
		RETVAL = 0;
		break;
	}
OUTPUT:
	RETVAL


#/******************************************************************************
# * field_tell( resid )
# ******************************************************************************/

U32
field_tell( resid )
	void * resid;
PREINIT:
	dMY_CXT;
CODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		RETVAL = mysql_field_tell( ( (MY_RES *) resid )->res );
		break;
	case MY_TYPE_STMT:
		RETVAL = mysql_field_tell( ( (MY_STMT *) resid )->meta );
		break;
	default:
		RETVAL = 0;
		break;
	}
OUTPUT:
	RETVAL


#/******************************************************************************
# * fetch_row( resid )
# ******************************************************************************/

void
fetch_row( resid )
	void * resid;
PREINIT:
	dMY_CXT;
	MY_RES *res;
	MYSQL_ROW row;
	DWORD *lengths;
	MY_STMT *stmt;
	MYSQL_BIND *result;
	DWORD num_fields, i;
PPCODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		res = (MY_RES *) resid;
		row = mysql_fetch_row( res->res );
		if( ! row ) goto error;
		num_fields = mysql_num_fields( res->res );
		lengths = mysql_fetch_lengths( res->res );
		EXTEND( SP, num_fields );
		for( i = 0; i < num_fields; i ++ ) {
			if( row[i] )
				XPUSHs( sv_2mortal( newSVpvn( row[i], lengths[i] ) ) );
			else
				XPUSHs( &PL_sv_undef );	
		}
		res->rowpos ++;
		break;
	case MY_TYPE_STMT:
		stmt = (MY_STMT *) resid;
		if( mysql_stmt_fetch( stmt->stmt ) != 0 ) goto error;
		EXTEND( SP, stmt->field_count );
		for( i = 0; i < stmt->field_count; i ++ ) {
			result = &stmt->result[i];
			if( *(result->is_null) )
				XPUSHs( &PL_sv_undef );	
			else
			switch( result->buffer_type ) {
			case MYSQL_TYPE_TINY:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((char *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((char *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_SHORT:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((short *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((short *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_LONG:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((long *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((long *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_DOUBLE:
				XPUSHs( sv_2mortal( newSVnv( *((double *) result->buffer) ) ) );
				break;
			default:
				XPUSHs( sv_2mortal( newSVpvn( result->buffer, *(result->length) ) ) );
				break;
			}
		}
		stmt->rowpos ++;
		break;
	}
error:
	{}


#/******************************************************************************
# * fetch_col( resid )
# ******************************************************************************/

void
fetch_col( resid )
	void * resid;
PREINIT:
	dMY_CXT;
	MY_RES *res;
	MYSQL_ROW row;
	DWORD *lengths;
	MY_STMT *stmt;
	MYSQL_BIND *result;
PPCODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		res = (MY_RES *) resid;
		EXTEND( SP, res->numrows );
		while( ( row = mysql_fetch_row( res->res ) ) ) {
			lengths = mysql_fetch_lengths( res->res );
			if( lengths[0] > 0 )
				XPUSHs( sv_2mortal( newSVpvn( row[0], lengths[0] ) ) );	
			else
				XPUSHs( &PL_sv_undef );	
		}
		res->rowpos = res->numrows;
		break;
	case MY_TYPE_STMT:
		stmt = (MY_STMT *) resid;
		EXTEND( SP, stmt->numrows );
		while( mysql_stmt_fetch( stmt->stmt ) == 0 ) {
			result = &stmt->result[0];
			if( *(result->is_null) )
				XPUSHs( &PL_sv_undef );	
			else
			switch( result->buffer_type ) {
			case MYSQL_TYPE_TINY:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((char *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((char *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_SHORT:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((short *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((short *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_LONG:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((long *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((long *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_DOUBLE:
				XPUSHs( sv_2mortal( newSVnv( *((double *) result->buffer) ) ) );
				break;
			default:
				XPUSHs( sv_2mortal( newSVpvn( result->buffer, *(result->length) ) ) );
				break;
			}
		}
		stmt->rowpos = stmt->numrows;
		break;
	}


#/******************************************************************************
# * fetch_hash( resid )
# ******************************************************************************/

void
fetch_hash( resid )
	void * resid;
PREINIT:
	dMY_CXT;
	MY_RES *res;
	MYSQL_ROW row;
	MYSQL_FIELD *fields;
	MY_STMT *stmt;
	MYSQL_BIND *result;
	DWORD *lengths;
	DWORD num_fields, i;
PPCODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		res = (MY_RES *) resid;
		row = mysql_fetch_row( res->res );
		if( ! row ) goto error;
		num_fields = mysql_num_fields( res->res );
		lengths = mysql_fetch_lengths( res->res );
		fields = mysql_fetch_fields( res->res );
		EXTEND( SP, num_fields * 2 );
		for( i = 0; i < num_fields; i ++ ) {
			XPUSHs( sv_2mortal(
				newSVpvn( fields[i].name, fields[i].name_length )
			) );	
			if( row[i] )
				XPUSHs( sv_2mortal( newSVpvn( row[i], lengths[i] ) ) );	
			else
				XPUSHs( &PL_sv_undef );	
		}
		res->rowpos ++;
		break;
	case MY_TYPE_STMT:
		stmt = (MY_STMT *) resid;
		if( mysql_stmt_fetch( stmt->stmt ) != 0 ) goto error;
		fields = mysql_fetch_fields( stmt->meta );
		EXTEND( SP, stmt->field_count * 2 );
		for( i = 0; i < stmt->field_count; i ++ ) {
			XPUSHs( sv_2mortal(
				newSVpvn( fields[i].name, fields[i].name_length )
			) );	
			result = &stmt->result[i];
			if( *(result->is_null) )
				XPUSHs( &PL_sv_undef );	
			else
			switch( result->buffer_type ) {
			case MYSQL_TYPE_TINY:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((char *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((char *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_SHORT:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((short *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((short *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_LONG:
				if( result->is_unsigned )
					XPUSHs( sv_2mortal( newSVuv( *((long *) result->buffer) ) ) );
				else
					XPUSHs( sv_2mortal( newSViv( *((long *) result->buffer) ) ) );
				break;
			case MYSQL_TYPE_DOUBLE:
				XPUSHs( sv_2mortal( newSVnv( *((double *) result->buffer) ) ) );
				break;
			default:
				XPUSHs( sv_2mortal( newSVpvn( result->buffer, *(result->length) ) ) );
				break;
			}
		}
		stmt->rowpos ++;
		break;
	}
error:
	{}


#/******************************************************************************
# * fetch_lengths( resid )
# ******************************************************************************/

void
fetch_lengths( resid )
	void * resid;
PREINIT:
	dMY_CXT;
	DWORD *lengths;
	DWORD num_fields, i;
	MY_STMT *stmt;
PPCODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		lengths = mysql_fetch_lengths( ( (MY_RES *) resid )->res );
		if( lengths ) {
			num_fields = mysql_num_fields( ( (MY_RES *) resid )->res );
			EXTEND( SP, num_fields );
			for( i = 0; i < num_fields; i ++ ) {
				XPUSHs( sv_2mortal( newSVuv( lengths[i] ) ) );	
			}
		}
		break;
	case MY_TYPE_STMT:
		stmt = (MY_STMT *) resid;
		EXTEND( SP, stmt->field_count );
		for( i = 0; i < stmt->field_count; i ++ ) {
			XPUSHs( sv_2mortal( newSVuv( *(stmt->result[i].length) ) ) );	
		}
	}


#/******************************************************************************
# * row_seek( resid, offset )
# ******************************************************************************/

int
row_seek( resid, offset = 0 )
	void * resid;
	UV offset;
PREINIT:
	dMY_CXT;
	MY_RES *res;
	MY_STMT *stmt;
CODE:
	switch( my_mysql_stmt_or_res( &MY_CXT, resid ) ) {
	case MY_TYPE_RES:
		res = (MY_RES *) resid;
		if( offset >= (UV) res->numrows )
			offset = (UV) res->numrows - 1;
		mysql_data_seek( res->res, offset );
		res->rowpos = offset;
		RETVAL = 1;
		break;
	case MY_TYPE_STMT:
		stmt = (MY_STMT *) resid;
		if( offset >= (UV) stmt->numrows )
			offset = (UV) stmt->numrows - 1;
		mysql_stmt_data_seek( stmt->stmt, offset );
		stmt->rowpos = offset;
		RETVAL = 1;
		break;
	default:
		RETVAL = 0;
	}
OUTPUT:
	RETVAL


#/******************************************************************************
# * row_tell( resid )
# ******************************************************************************/

Mysql.xs  view on Meta::CPAN

		if( r != 0  ) goto error;
		con->my_flags ^= MYCF_TRANSACTION;
		if( ( con->my_flags & MYCF_AUTOCOMMIT ) != 0 ) {
			r = mysql_autocommit( con->conid, TRUE );
			if( r != 0 ) goto error;
		}
	}
	RETVAL = 1;
	goto exit;
error:
	RETVAL = 0;
exit:
OUTPUT:
	RETVAL


#/******************************************************************************
# * rollback( [linkid] )
# ******************************************************************************/

int
rollback( linkid = 0 )
	void * linkid;
PREINIT:
	dMY_CXT;
	MY_CON *con;
CODE:
	if( ! ( linkid = my_verify_linkid( &MY_CXT, linkid ) ) ) goto error;
	con = (MY_CON *) linkid;
	if( ( con->my_flags & MYCF_TRANSACTION ) != 0 ) {
		int r = mysql_rollback( con->conid );
		if( r != 0 ) goto error;
		con->my_flags ^= MYCF_TRANSACTION;
		if( ( con->my_flags & MYCF_AUTOCOMMIT ) != 0 ) {
			r = mysql_autocommit( con->conid, TRUE );
			if( r != 0 ) goto error;
		}
	}
	RETVAL = 1;
	goto exit;
error:
	RETVAL = 0;
exit:
OUTPUT:
	RETVAL


#/******************************************************************************
# * show_catalogs( [linkid, [wild]] )
# ******************************************************************************/

void
show_catalogs( linkid = 0, wild = NULL )
	void * linkid;
	const char *wild;
PREINIT:
	dMY_CXT;
	MY_CON *con;
	MYSQL_RES *res;
	MYSQL_ROW row;
PPCODE:
	if( ! ( linkid = my_verify_linkid( &MY_CXT, linkid ) ) ) goto error;
	con = (MY_CON *) linkid;
	res = mysql_list_dbs( con->conid, wild );
	if( res ) {
		while( ( row = mysql_fetch_row( res ) ) ) {
			if( row[0] != 0 ) {
				XPUSHs( sv_2mortal( newSVpvn( row[0], strlen( row[0] ) ) ) );
			}
		}
		mysql_free_result( res );
	}
error:
	{}


#/******************************************************************************
# * show_tables( [linkid [, schema [, db [, wild]]]] )
# ******************************************************************************/

void
show_tables( linkid = 0, schema = NULL, db = NULL, wild = NULL )
	void * linkid;
	const char *db;
	const char *schema;
	const char *wild;
PREINIT:
	dMY_CXT;
	MY_CON *con;
	MYSQL_RES *res;
	MYSQL_ROW row;
	char sql[512], *p1;
	AV *av;
PPCODE:
	if( ! ( linkid = my_verify_linkid( &MY_CXT, linkid ) ) ) goto error;
	con = (MY_CON *) linkid;
	if( db && db[0] != '\0' ) {
		p1 = my_strcpy( sql, "SHOW TABLES FROM `" );
		p1 = my_strcpy( p1, db );
		p1 = my_strcpy( p1, "`" );
		if( wild && wild[0] != '\0' ) {
			p1 = my_strcpy( p1, " LIKE " );
			p1 = my_strcpy( p1, wild );
		}
		if( mysql_real_query( con->conid, sql, (DWORD) (p1 - sql) ) == 0 ) {
			res = mysql_store_result( con->conid );
		}
		else {
			res = 0;
		}
	}
	else {
		res = mysql_list_tables( con->conid, wild );
	}
	if( res ) {
		while( ( row = mysql_fetch_row( res ) ) ) {
			if( row[0] != 0 ) {
				// TABLE, SCHEMA, DB, TYPE
				av = (AV *) sv_2mortal( (SV *) newAV() );
				av_push( av, newSVpvn( row[0], strlen( row[0] ) ) );
				av_push( av, &PL_sv_undef );
				av_push( av, newSVpv( db, 0 ) );
				// todo: add, detect "views"
				av_push( av, newSVpvn( "table", 5 ) );
				XPUSHs( sv_2mortal( newRV( (SV *) av ) ) );
			}
		}
		mysql_free_result( res );
	}
error:
	{}


#/******************************************************************************
# * show_fields( [linkid, ] table [, schema [, db, [wild]]]] )
# ******************************************************************************/

void
show_fields( ... )
PREINIT:
	dMY_CXT;
	void * linkid = 0;
	const char *table = NULL;
	const char *schema = NULL;
	const char *db = NULL;
	const char *wild = NULL;
	int itemp = 0;
	MY_CON *con;
	MYSQL_RES *res;
	MYSQL_ROW row;
	int numfields, numrows, r;
	char sql[512], *p1;
	AV *av;
PPCODE:
    if( items < ( SvIOK( ST(0) ) ? 2 : 1 ) || items > 5 )
		Perl_croak( aTHX_ "Usage: " __PACKAGE__ "::show_fields(linkid = 0, table, schema = NULL, db = NULL, wild = NULL)" );
	if( SvIOK( ST( itemp ) ) ) {
		linkid = INT2PTR( void *, SvIV( ST( itemp ) ) );
		itemp ++;
	}
	table = (const char *) SvPV_nolen( ST( itemp ) );
	itemp ++;
	if( itemp < items ) {
		schema = (const char *) SvPV_nolen( ST( itemp ) );
		itemp ++;
	}
	if( itemp < items ) {
		db = (const char *) SvPV_nolen( ST( itemp ) );
		itemp ++;
	}
	if( itemp < items )
		wild = (const char *) SvPV_nolen( ST( itemp ) );
	con = (MY_CON *) my_verify_linkid( &MY_CXT, linkid );
	if( con == NULL ) goto error;
	p1 = my_strcpy( sql, "SHOW COLUMNS FROM `" );
	p1 = my_strcpy( p1, table );
	p1 = my_strcpy( p1, "`" );
	if( wild && wild[0] != '\0' ) {
		p1 = my_strcpy( p1, " LIKE '" );
		p1 = my_strcpy( p1, wild );
		p1 = my_strcpy( p1, "'" );
	}
	r = mysql_real_query( con->conid, sql, (DWORD) (p1 - sql) );
	if( r == 0 ) {
		res = mysql_store_result( con->conid );
		numrows = (DWORD) mysql_num_rows( res );
		numfields = mysql_num_fields( res );
		EXTEND( SP, numrows );
		// COLUMN, NULLABLE, DEFAULT, IS_PRIMARY, IS_UNIQUE, TYPENAME, AUTOINC
		while( ( row = mysql_fetch_row( res ) ) ) {
			av = (AV *) sv_2mortal( (SV *) newAV() );
			av_push( av, newSVpvn( row[0], strlen( row[0] ) ) );
			av_push( av, newSViv( strcmp( row[2], "NO" ) == 0 ? 0 : 1 ) );
			if( row[4] != 0 )
				av_push( av, newSVpvn( row[4], strlen( row[4] ) ) );
			else
				av_push( av, &PL_sv_undef );
			av_push( av, newSViv( strcmp( row[3], "PRI" ) == 0 ? 1 : 0 ) );
			av_push( av, newSViv( strcmp( row[3], "UNI" ) == 0 ? 1 : 0 ) );
			av_push( av, newSVpvn( row[1], strlen( row[1] ) ) );
			av_push( av, newSViv( strstr( row[5], "auto_increment" ) != 0 ? 1 : 0 ) );
			XPUSHs( sv_2mortal( newRV( (SV *) av ) ) );
		}
		mysql_free_result( res );
	}
error:
	{}


#/******************************************************************************
# * show_index( [linkid, ] table [, schema [, db]] )
# ******************************************************************************/

void
show_index( ... )
PREINIT:
	dMY_CXT;
	void * linkid = 0;
	const char *table = NULL;
	const char *schema = NULL;
	const char *db = NULL;
	MY_CON *con;
	MYSQL_RES *res;
	MYSQL_ROW row;
	char sql[512], *p1;
	int step, num_fields, num_rows, itemp = 0;
	long r;
	AV *av;
PPCODE:
    if( items < ( SvIOK( ST(0) ) ? 2 : 1 ) || items > 4 )
		Perl_croak( aTHX_ "Usage: " __PACKAGE__ "::show_index(linkid = 0, table, schema = NULL, db = NULL)" );
	if( SvIOK( ST( itemp ) ) ) {
		linkid = INT2PTR( void *, SvIV( ST( itemp ) ) );
		itemp ++;
	}
	table = (const char *) SvPV_nolen( ST( itemp ) );
	itemp ++;
	if( itemp < items ) {
		schema = (const char *) SvPV_nolen( ST( itemp ) );
		itemp ++;
	}
	if( itemp < items )
		db = (const char *) SvPV_nolen( ST( itemp ) );
	con = (MY_CON *) my_verify_linkid( &MY_CXT, linkid );
	if( con == NULL ) goto error;
	// SHOW INDEX FROM table FROM db
	p1 = my_strcpy( sql, "SHOW INDEX FROM `" );
	p1 = my_strcpy( p1, table );
	p1 = my_strcpy( p1, "`" );
	if( db != 0 && db[0] != '\0' ) {
		p1 = my_strcpy( p1, " FROM `" );
		p1 = my_strcpy( p1, db );
		p1 = my_strcpy( p1, "`" );
	}
	step = 0;
retry:
	r = mysql_real_query( con->conid, sql, (DWORD) (p1 - sql) );
	switch( r ) {
	case 0:
		break;
	case 1:
	case CR_SERVER_GONE_ERROR:
	case CR_SERVER_LOST:
		if( ( con->client_flag & CLIENT_RECONNECT ) != 0 && step == 0 ) {
			step ++;
			r = my_mysql_reconnect( con );
			if( ! r ) goto error;
			goto retry;
		}
	default:
		goto error;
	}
	res = mysql_store_result( con->conid );
	num_fields = mysql_num_fields( res );
	num_rows = (DWORD) mysql_num_rows( res );
	EXTEND( SP, num_rows );
	// NAME, COLUMN, TYPE
	while( ( row = mysql_fetch_row( res ) ) ) {
		av = (AV *) sv_2mortal( (SV *) newAV() );
		av_push( av, newSVpvn( row[2], strlen( row[2] ) ) );
		av_push( av, newSVpvn( row[4], strlen( row[4] ) ) );
		if( strcmp( row[2], "PRIMARY" ) == 0 )
			av_push( av, newSViv( 1 ) );
		else if( row[1][0] == '0' )
			av_push( av, newSViv( 2 ) );
		else
			av_push( av, newSViv( 3 ) );
		XPUSHs( sv_2mortal( newRV( (SV *) av ) ) );
	}



( run in 0.881 second using v1.01-cache-2.11-cpan-5511b514fd6 )