/* Allocating data and length arrays, if needed, and initing them in certain cases.
   DataPtr should be ensured to be not NULL */
SQLRETURN MADB_InitBulkOperBuffers(MADB_Stmt *Stmt, MADB_DescRecord *CRec, void *DataPtr, SQLLEN *OctetLengthPtr,
                                   SQLLEN *IndicatorPtr, SQLSMALLINT SqlType, MYSQL_BIND *MaBind)
{
  BOOL VariableLengthMadbType= TRUE;

  MaBind->buffer_length= 0;
  MaBind->buffer_type= MADB_GetMaDBTypeAndLength(CRec->ConciseType, &MaBind->is_unsigned, &MaBind->buffer_length);

  /* For fixed length types MADB_GetMaDBTypeAndLength has set buffer_length */
  if (MaBind->buffer_length != 0)
  {
    VariableLengthMadbType= FALSE;
  }
  switch (CRec->ConciseType)
  {
  case CHAR_BINARY_TYPES:
    if (SqlType == SQL_BIT)
    {
      CRec->InternalBuffer= MADB_CALLOC(Stmt->Bulk.ArraySize);
      MaBind->buffer_length= 1;
      break;
    }
  case DATETIME_TYPES:
    if (CanUseStructArrForDatetime(Stmt) == TRUE)
    {
      CRec->InternalBuffer= MADB_ALLOC(Stmt->Bulk.ArraySize*sizeof(MYSQL_TIME));
      MaBind->buffer_length= sizeof(MYSQL_TIME);
      break;
    }
    /* Otherwise falling thru and allocating array of pointers */
  case WCHAR_TYPES:
  case SQL_C_NUMERIC:
    CRec->InternalBuffer= MADB_CALLOC(Stmt->Bulk.ArraySize*sizeof(char*));
    MaBind->buffer_length= sizeof(char*);
    break;
  default:
    MaBind->buffer= DataPtr;
    if (MaBind->buffer_length == 0)
    {
      MaBind->buffer_length= sizeof(char*);
    }
  }

  if (MaBind->buffer != DataPtr)
  {
    MaBind->buffer= CRec->InternalBuffer;
    if (MaBind->buffer == NULL)
    {
      return MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
    }
    CRec->InternalBuffer= NULL; /* Need to reset this pointer, so the memory won't be freed (accidentally) */
  }

  return MADB_SetBulkOperLengthArr(Stmt, CRec, OctetLengthPtr, IndicatorPtr, DataPtr, MaBind, VariableLengthMadbType);
}
unsigned int GetMultiStatements(MADB_Stmt *Stmt, BOOL ExecDirect)
{
  int          i= 0;
  unsigned int MaxParams= 0;
  char        *p= Stmt->Query.RefinedText;

  Stmt->MultiStmtNr= 0;
  Stmt->MultiStmts= (MYSQL_STMT **)MADB_CALLOC(sizeof(MYSQL_STMT) * STMT_COUNT(Stmt->Query));

  while (p < Stmt->Query.RefinedText + Stmt->Query.RefinedLength)
  {
    Stmt->MultiStmts[i]= i == 0 ? Stmt->stmt : MADB_NewStmtHandle(Stmt);
    MDBUG_C_PRINT(Stmt->Connection, "-->inited&preparing %0x(%d,%s)", Stmt->MultiStmts[i], i, p);

    if (mysql_stmt_prepare(Stmt->MultiStmts[i], p, (unsigned long)strlen(p)))
    {
      MADB_SetNativeError(&Stmt->Error, SQL_HANDLE_STMT, Stmt->MultiStmts[i]);
      CloseMultiStatements(Stmt);

      /* Last paranoid attempt make sure that we did not have a parsing error.
         More to preserve "backward-compatimility" - we did this before, but before trying to
         prepare "multi-statement". */
      if (i == 0 && Stmt->Error.NativeError !=1295 /*ER_UNSUPPORTED_PS*/)
      {
        Stmt->stmt= MADB_NewStmtHandle(Stmt);
        if (mysql_stmt_prepare(Stmt->stmt, STMT_STRING(Stmt), (unsigned long)strlen(STMT_STRING(Stmt))))
        {
          mysql_stmt_close(Stmt->stmt);
          Stmt->stmt= NULL;
        }
        else
        {
          MADB_DeleteSubqueries(&Stmt->Query);
          return 0;
        }
      }
      return 1;
    }
    if (mysql_stmt_param_count(Stmt->MultiStmts[i]) > MaxParams)
    {
      MaxParams= mysql_stmt_param_count(Stmt->MultiStmts[i]);
    }
    p+= strlen(p) + 1;
    ++i;
  }

  if (MaxParams)
  {
    Stmt->params= (MYSQL_BIND *)MADB_CALLOC(sizeof(MYSQL_BIND) * MaxParams);
  }

  return 0;
}
/* {{{ MADB_Dsn_Init() */
MADB_Dsn *MADB_DSN_Init()
{
  MADB_Dsn *Dsn;

  if ((Dsn= (MADB_Dsn *)MADB_CALLOC(sizeof(MADB_Dsn))))
  {
    Dsn->FreeMe= TRUE;
    Dsn->Keys= (MADB_DsnKey *)&DsnKeys;
  }
  return Dsn;
}
char *GetFieldStrVal(int Dialog, int Field, char* (*allocator)(size_t))
{
  int rc;
  size_t len= Edit_GetTextLength(GetDlgItem(hwndTab[Dialog], Field));
  char *p;

  if (allocator)
  {
    p= allocator(len * sizeof(char) + 2);
  }
  else
  {
    p= (char *)MADB_CALLOC(len * sizeof(char) + 2);
  }

  if (p)
    rc= Edit_GetText(GetDlgItem(hwndTab[Dialog], Field), p, len+1);
  return p;      
}
/* {{{ MADB_DescInit */
MADB_Desc *MADB_DescInit(MADB_Dbc *Dbc,enum enum_madb_desc_type DescType, my_bool isExternal)
{
  MADB_Desc *Desc;
  
  if (!(Desc= (MADB_Desc *)MADB_CALLOC(sizeof(MADB_Desc))))
    return NULL;

  Desc->DescType= DescType;

  if (my_init_dynamic_array(&Desc->Records, sizeof(MADB_DescRecord), 0, 0))
  {
    MADB_FREE(Desc);
    Desc= NULL;
  }
  if (isExternal)
  {
    if (my_init_dynamic_array(&Desc->Stmts, sizeof(MADB_Stmt**), 0, 0))
    {
      MADB_DescFree(Desc, FALSE);
      Desc= NULL;
    }
    else
    {
      Desc->Dbc= Dbc;
      EnterCriticalSection(&Dbc->cs);
      Desc->ListItem.data= (void *)Desc;
      Dbc->Descrs= list_add(Dbc->Descrs, &Desc->ListItem);
      LeaveCriticalSection(&Dbc->cs);
    }
  }
  if (Desc)
    Desc->AppType= isExternal;

  Desc->Header.ArraySize= 1;
 
  return Desc;
}
unsigned int GetMultiStatements(MADB_Stmt *Stmt, char *StmtStr, size_t Length)
{
  char *p, *last, *prev= NULL;
  unsigned int statements= 1;
  int quote[2]= {0,0}, comment= 0;
  char *end;
  MYSQL_STMT *stmt;
  p= last= StmtStr;

  stmt= mysql_stmt_init(Stmt->Connection->mariadb);

  /* if the entire stmt string passes, we don't have multistatement */
  if (stmt && !mysql_stmt_prepare(stmt, StmtStr, Length))
  {
    mysql_stmt_close(stmt);
    return 1;
  }
  mysql_stmt_close(stmt);
  /* make sure we don't have trailing whitespace or semicolon */
  if (Length)
  {
    end= StmtStr + Length - 1;
    while (end > StmtStr && (isspace(*end) || *end == ';'))
      end--;
    Length= end - StmtStr;
  }

  while (p < StmtStr + Length)
  {
    switch (*p) {
    case ';':
      if (!quote[0] && !quote[1] && !comment)
      {
        statements++;
        last= p + 1;
        *p= 0;
      }
      break;
    case '/':
      if (!comment && (p < StmtStr + Length + 1) && (char)*(p+1) ==  '*')
        comment= 1;
      else if (comment && (p > StmtStr) && (char)*(p-1) == '*')
        comment= 0;
      break;
    case '\"':
      if (prev && *prev != '\\')
        quote[0] = !quote[0];
      break;
    case 39:
      if (prev && *prev != '\\')
        quote[1] = !quote[1];
      break;
    default:
      break;
    }
    prev= p;
    p++;
  }

  if (statements > 1)
  {
    int i=0;
    unsigned int MaxParams= 0;

    p= StmtStr;
    Stmt->MultiStmtCount= 0;
    Stmt->MultiStmtNr= 0;
    Stmt->MultiStmts= (MYSQL_STMT **)MADB_CALLOC(sizeof(MYSQL_STMT) * statements);

    while (p < StmtStr + Length)
    {
      Stmt->MultiStmts[i]= mysql_stmt_init(Stmt->Connection->mariadb);
      if (mysql_stmt_prepare(Stmt->MultiStmts[i], p, strlen(p)))
      {
        MADB_SetNativeError(&Stmt->Error, SQL_HANDLE_STMT, Stmt->MultiStmts[i]);
        CloseMultiStatements(Stmt);
        return 0;
      }
      if (mysql_stmt_param_count(Stmt->MultiStmts[i]) > MaxParams)
        MaxParams= mysql_stmt_param_count(Stmt->MultiStmts[i]);
      p+= strlen(p) + 1;
      ++i;
      ++Stmt->MultiStmtCount;
    }
    if (MaxParams)
      Stmt->params= (MYSQL_BIND *)MADB_CALLOC(sizeof(MYSQL_BIND) * MaxParams);
  }

  return statements;
}