The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "text_ext.h"

csv_t *csv_init( csv_t *csv ) {
	if( csv == NULL ) {
		Newxz( csv, 1, csv_t );
		csv->flags = CSV_ISALLOC;
	}
	else {
		Zero( csv, 1, csv_t );
	}
	csv->backend = BACKEND_CSV;
	csv->flags |= CSV_COLNAMEHEADER | CSV_USESCHEMA;
	csv->quote = DEFAULT_QUOTECHAR;
	csv->delimiter = DEFAULT_DELIMITER;
	csv->max_scan_rows = DEFAULT_MAXSCANROWS;
	csv->decimal_symbol = '.';
	csv->table_charset = CS_ANSI;
	csv->client_charset = CS_ANSI;
	return csv;
}

void csv_free( csv_t *csv ) {
	if( csv == NULL )
		return;
	Safefree( csv->path );
	if( csv->flags & CSV_ISALLOC )
		Safefree( csv );
}

int csv_prepare( csv_t *csv, const char *sql, size_t sql_len, csv_stmt_t **pstmt ) {
	csv_stmt_t *stmt;
	Newxz( stmt, 1, csv_stmt_t );
	stmt->csv = csv;
	stmt->parse.csv = csv;
	stmt->parse.stmt = stmt;
	if( run_parser( &stmt->parse, sql, sql_len ) != 0 || csv->last_errno ) {
		csv_stmt_free( stmt );
		return CSV_ERROR;
	}
	(*pstmt) = stmt;
	return CSV_OK;
}

int csv_execute( csv_stmt_t *stmt ) {
	int r;
	if( stmt == NULL )
		return CSV_ERROR;
	switch( stmt->csv->backend ) {
	case BACKEND_CSV:
		switch( stmt->parse.type ) {
		case PARSE_TYPE_SELECT:
			if( stmt->result != NULL ) {
				csv_result_free( stmt->result );
				stmt->result = NULL;
			}
			stmt->result = csv_select_run( &stmt->parse );
			if( stmt->result == NULL )
				return CSV_ERROR;
			break;
		case PARSE_TYPE_CREATE_TABLE:
			r = csv_create_table( &stmt->parse );
			if( r != CSV_OK )
				return CSV_ERROR;
			break;
		case PARSE_TYPE_DROP_TABLE:
			r = csv_drop_table( &stmt->parse );
			if( r != CSV_OK )
				return CSV_ERROR;
			break;
		case PARSE_TYPE_INSERT:
			r = csv_insert_run( &stmt->parse );
			if( r != CSV_OK )
				return CSV_ERROR;
			break;
		case PARSE_TYPE_UPDATE:
			r = csv_update_run( &stmt->parse );
			if( r != CSV_OK )
				return CSV_ERROR;
			break;
		case PARSE_TYPE_DELETE:
			r = csv_delete_run( &stmt->parse );
			if( r != CSV_OK )
				return CSV_ERROR;
			break;
		case PARSE_TYPE_SET:
			r = csv_set_run( &stmt->parse );
			if( r != CSV_OK )
				return CSV_ERROR;
			break;
		case PARSE_TYPE_SHOW_VARS:
			if( stmt->result != NULL ) {
				csv_result_free( stmt->result );
				stmt->result = NULL;
			}
			stmt->result = csv_run_show_variables( &stmt->parse );
			if( stmt->result == NULL )
				return CSV_ERROR;
			break;
		}
		break;
	}
	return CSV_OK;
}

void csv_stmt_free( csv_stmt_t *stmt ) {
	if( stmt == NULL )
		return;
	switch( stmt->csv->backend ) {
	case BACKEND_CSV:
		switch( stmt->parse.type ) {
		case PARSE_TYPE_SELECT:
			if( stmt->result != NULL )
				csv_result_free( stmt->result );
			csv_select_free( stmt->parse.select );
			break;
		case PARSE_TYPE_CREATE_TABLE:
			csv_table_def_free( stmt->parse.table );
			break;
		case PARSE_TYPE_DROP_TABLE:
			csv_table_def_free( stmt->parse.table );
			break;
		case PARSE_TYPE_INSERT:
			csv_insert_free( stmt->parse.insert );
			break;
		case PARSE_TYPE_UPDATE:
			csv_update_free( stmt->parse.update );
			break;
		case PARSE_TYPE_DELETE:
			csv_delete_free( stmt->parse.delete );
			break;
		case PARSE_TYPE_SET:
			csv_expr_free( stmt->parse.expr );
			break;
		case PARSE_TYPE_SHOW_VARS:
			csv_expr_free( stmt->parse.expr );
			break;
		}
		break;
	}
	Safefree( stmt->parse.qmark );
	Safefree( stmt->parse.sql );
	Safefree( stmt );
}

int csv_bind_param_sv(
	csv_stmt_t *stmt, WORD p_num, const char *val, size_t len
) {
	Expr *x;
	if( stmt == NULL )
		return CSV_OK;
	if( p_num < 1 || p_num > stmt->parse.qmark_count ) {
		csv_error_msg( &stmt->parse, CSV_ERR_BINDCOLUMN,
			"Parameter %u out of range %u", p_num, stmt->parse.qmark_count );
		return CSV_ERROR;
	}
	x = stmt->parse.qmark[p_num - 1];
	Renew( x->var.sv, len + 1, char );
	Copy( val, x->var.sv, len, char );
	x->var.sv[len] = '\0';
	x->var.sv_len = len;
	x->var.flags = (x->var.flags & (~(VAR_HAS_IV + VAR_HAS_NV))) | VAR_HAS_SV;
	if( x->flags & EXPR_USE_PATTERN ) {
		if( x->pat != NULL )
			g_dbe->regexp_free( x->pat );
		x->pat = g_dbe->regexp_from_pattern( x->var.sv, x->var.sv_len, 1 );
	}
	return CSV_OK;
}

int csv_bind_param_iv( csv_stmt_t *stmt, WORD p_num, int val ) {
	Expr *x;
	if( stmt == NULL )
		return CSV_OK;
	if( p_num < 1 || p_num > stmt->parse.qmark_count ) {
		csv_error_msg( &stmt->parse, CSV_ERR_BINDCOLUMN,
			"Parameter %u out of range %u", p_num, stmt->parse.qmark_count );
		return CSV_ERROR;
	}
	x = stmt->parse.qmark[p_num - 1];
	x->var.iv = val;
	x->var.flags = (x->var.flags & (~(VAR_HAS_SV + VAR_HAS_NV))) | VAR_HAS_IV;
	if( x->flags & EXPR_USE_PATTERN ) {
		char tmp[22], *p1;
		p1 = my_itoa( tmp, val, 10 );
		if( x->pat != NULL )
			g_dbe->regexp_free( x->pat );
		x->pat = g_dbe->regexp_from_pattern( tmp, p1 - tmp, 1 );
	}
	return CSV_OK;
}

int csv_bind_param_nv( csv_stmt_t *stmt, WORD p_num, double val ) {
	Expr *x;
	if( stmt == NULL )
		return CSV_OK;
	if( p_num < 1 || p_num > stmt->parse.qmark_count ) {
		csv_error_msg( &stmt->parse, CSV_ERR_BINDCOLUMN,
			"Parameter %u out of range %u", p_num, stmt->parse.qmark_count );
		return CSV_ERROR;
	}
	x = stmt->parse.qmark[p_num - 1];
	x->var.nv = val;
	x->var.flags = (x->var.flags & (~(VAR_HAS_SV + VAR_HAS_IV))) | VAR_HAS_NV;
	if( x->flags & EXPR_USE_PATTERN ) {
		char tmp[41], *p1;
		p1 = my_ftoa( tmp, val );
		if( x->pat != NULL )
			g_dbe->regexp_free( x->pat );
		x->pat = g_dbe->regexp_from_pattern( tmp, p1 - tmp, 1 );
	}
	return CSV_OK;
}

csv_result_t *csv_get_result( csv_stmt_t *stmt ) {
	csv_result_t *result = stmt->result;
	stmt->result = NULL;
	return result;
}