~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/handler.cc

  • Committer: Brian Aker
  • Date: 2009-04-09 15:03:26 UTC
  • mfrom: (971.1.44 mordred)
  • Revision ID: brian@gaz-20090409150326-cu50yn12esijpy1c
Merge Monty

Show diffs side-by-side

added added

removed removed

Lines of Context:
63
63
TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
64
64
                               tx_isolation_names, NULL};
65
65
 
66
 
static TYPELIB known_extensions= {0,"known_exts", NULL, NULL};
67
 
uint32_t known_extensions_id= 0;
68
 
 
69
66
 
70
67
/**
71
68
  Register handler error messages for use with my_error().
183
180
  return(error);
184
181
}
185
182
 
186
 
static bool dropdb_storage_engine(Session *,
187
 
                                  st_plugin_int *plugin,
188
 
                                  void *path)
189
 
{
190
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
191
 
  if (engine->is_enabled())
192
 
    engine->drop_database((char *)path);
193
 
  return false;
194
 
}
195
 
 
196
 
 
197
 
void ha_drop_database(char* path)
198
 
{
199
 
  plugin_foreach(NULL, dropdb_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN, path);
200
 
}
201
 
 
202
 
 
203
 
static bool closecon_storage_engine(Session *session, st_plugin_int *plugin,
204
 
                                void *)
205
 
{
206
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
207
 
  /*
208
 
    there's no need to rollback here as all transactions must
209
 
    be rolled back already
210
 
  */
211
 
  if (engine->is_enabled() && 
212
 
      session_get_ha_data(session, engine))
213
 
    engine->close_connection(session);
214
 
  return false;
215
 
}
216
 
 
217
 
 
218
 
/**
219
 
  @note
220
 
    don't bother to rollback here, it's done already
221
 
*/
222
 
void ha_close_connection(Session* session)
223
 
{
224
 
  plugin_foreach(session, closecon_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN, 0);
225
 
}
 
183
 
226
184
 
227
185
/* ========================================================================
228
186
 ======================= TRANSACTIONS ===================================*/
864
822
}
865
823
 
866
824
 
867
 
struct xaengine_st {
868
 
  XID *xid;
869
 
  int result;
870
 
};
871
 
 
872
 
static bool xacommit_storage_engine(Session *,
873
 
                                    st_plugin_int *plugin,
874
 
                                    void *arg)
875
 
{
876
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
877
 
  if (engine->is_enabled())
878
 
  {
879
 
    engine->commit_by_xid(((struct xaengine_st *)arg)->xid);
880
 
    ((struct xaengine_st *)arg)->result= 0;
881
 
  }
882
 
  return false;
883
 
}
884
 
 
885
 
static bool xarollback_storage_engine(Session *,
886
 
                                      st_plugin_int *plugin,
887
 
                                  void *arg)
888
 
{
889
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
890
 
  if (engine->is_enabled())
891
 
  {
892
 
    engine->rollback_by_xid(((struct xaengine_st *)arg)->xid);
893
 
    ((struct xaengine_st *)arg)->result= 0;
894
 
  }
895
 
  return false;
896
 
}
897
 
 
898
 
 
899
 
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
900
 
{
901
 
  struct xaengine_st xaop;
902
 
  xaop.xid= xid;
903
 
  xaop.result= 1;
904
 
 
905
 
  plugin_foreach(NULL, commit ? xacommit_storage_engine : xarollback_storage_engine,
906
 
                 DRIZZLE_STORAGE_ENGINE_PLUGIN, &xaop);
907
 
 
908
 
  return xaop.result;
909
 
}
910
 
 
911
 
/**
912
 
  recover() step of xa.
913
 
 
914
 
  @note
915
 
    there are three modes of operation:
916
 
    - automatic recover after a crash
917
 
    in this case commit_list != 0, tc_heuristic_recover==0
918
 
    all xids from commit_list are committed, others are rolled back
919
 
    - manual (heuristic) recover
920
 
    in this case commit_list==0, tc_heuristic_recover != 0
921
 
    DBA has explicitly specified that all prepared transactions should
922
 
    be committed (or rolled back).
923
 
    - no recovery (MySQL did not detect a crash)
924
 
    in this case commit_list==0, tc_heuristic_recover == 0
925
 
    there should be no prepared transactions in this case.
926
 
*/
927
 
struct xarecover_st
928
 
{
929
 
  int len, found_foreign_xids, found_my_xids;
930
 
  XID *list;
931
 
  HASH *commit_list;
932
 
  bool dry_run;
933
 
};
934
 
 
935
 
static bool xarecover_storage_engine(Session *,
936
 
                                     st_plugin_int *plugin,
937
 
                                     void *arg)
938
 
{
939
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
940
 
  struct xarecover_st *info= (struct xarecover_st *) arg;
941
 
  int got;
942
 
 
943
 
  if (engine->is_enabled())
944
 
  {
945
 
    while ((got= engine->recover(info->list, info->len)) > 0 )
946
 
    {
947
 
      errmsg_printf(ERRMSG_LVL_INFO,
948
 
                    _("Found %d prepared transaction(s) in %s"),
949
 
                    got, engine->getName().c_str());
950
 
      for (int i=0; i < got; i ++)
951
 
      {
952
 
        my_xid x=info->list[i].get_my_xid();
953
 
        if (!x) // not "mine" - that is generated by external TM
954
 
        {
955
 
          xid_cache_insert(info->list+i, XA_PREPARED);
956
 
          info->found_foreign_xids++;
957
 
          continue;
958
 
        }
959
 
        if (info->dry_run)
960
 
        {
961
 
          info->found_my_xids++;
962
 
          continue;
963
 
        }
964
 
        // recovery mode
965
 
        if (info->commit_list ?
966
 
            hash_search(info->commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
967
 
            tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
968
 
        {
969
 
          engine->commit_by_xid(info->list+i);
970
 
        }
971
 
        else
972
 
        {
973
 
          engine->rollback_by_xid(info->list+i);
974
 
        }
975
 
      }
976
 
      if (got < info->len)
977
 
        break;
978
 
    }
979
 
  }
980
 
  return false;
981
 
}
982
 
 
983
 
int ha_recover(HASH *commit_list)
984
 
{
985
 
  struct xarecover_st info;
986
 
  info.found_foreign_xids= info.found_my_xids= 0;
987
 
  info.commit_list= commit_list;
988
 
  info.dry_run= (info.commit_list==0 && tc_heuristic_recover==0);
989
 
  info.list= NULL;
990
 
 
991
 
  /* commit_list and tc_heuristic_recover cannot be set both */
992
 
  assert(info.commit_list==0 || tc_heuristic_recover==0);
993
 
  /* if either is set, total_ha_2pc must be set too */
994
 
  assert(info.dry_run);
995
 
 
996
 
  if (total_ha_2pc <= 1)
997
 
    return 0;
998
 
 
999
 
  if (info.commit_list)
1000
 
    errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
1001
 
 
1002
 
 
1003
 
#ifndef WILL_BE_DELETED_LATER
1004
 
 
1005
 
  /*
1006
 
    for now, only InnoDB supports 2pc. It means we can always safely
1007
 
    rollback all pending transactions, without risking inconsistent data
1008
 
  */
1009
 
 
1010
 
  assert(total_ha_2pc == 2); // only InnoDB and binlog
1011
 
  tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
1012
 
  info.dry_run=false;
1013
 
#endif
1014
 
 
1015
 
 
1016
 
  for (info.len= MAX_XID_LIST_SIZE ;
1017
 
       info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2)
1018
 
  {
1019
 
    info.list=(XID *)malloc(info.len*sizeof(XID));
1020
 
  }
1021
 
  if (!info.list)
1022
 
  {
1023
 
    errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), info.len*sizeof(XID));
1024
 
    return(1);
1025
 
  }
1026
 
 
1027
 
  plugin_foreach(NULL, xarecover_storage_engine,
1028
 
                 DRIZZLE_STORAGE_ENGINE_PLUGIN, &info);
1029
 
 
1030
 
  free((unsigned char*)info.list);
1031
 
  if (info.found_foreign_xids)
1032
 
    errmsg_printf(ERRMSG_LVL_WARN, _("Found %d prepared XA transactions"),
1033
 
                  info.found_foreign_xids);
1034
 
  if (info.dry_run && info.found_my_xids)
1035
 
  {
1036
 
    errmsg_printf(ERRMSG_LVL_ERROR,
1037
 
                  _("Found %d prepared transactions! It means that drizzled "
1038
 
                    "was not shut down properly last time and critical "
1039
 
                    "recovery information (last binlog or %s file) was "
1040
 
                    "manually deleted after a crash. You have to start "
1041
 
                    "drizzled with the --tc-heuristic-recover switch to "
1042
 
                    "commit or rollback pending transactions."),
1043
 
                    info.found_my_xids, opt_tc_log_file);
1044
 
    return(1);
1045
 
  }
1046
 
  if (info.commit_list)
1047
 
    errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
1048
 
  return(0);
1049
 
}
 
825
 
1050
826
 
1051
827
/**
1052
828
  return the list of XID's to a client, the same way SHOW commands do.
1096
872
  return(0);
1097
873
}
1098
874
 
1099
 
/**
1100
 
  @details
1101
 
  This function should be called when MySQL sends rows of a SELECT result set
1102
 
  or the EOF mark to the client. It releases a possible adaptive hash index
1103
 
  S-latch held by session in InnoDB and also releases a possible InnoDB query
1104
 
  FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
1105
 
  keep them over several calls of the InnoDB handler interface when a join
1106
 
  is executed. But when we let the control to pass to the client they have
1107
 
  to be released because if the application program uses mysql_use_result(),
1108
 
  it may deadlock on the S-latch if the application on another connection
1109
 
  performs another SQL query. In MySQL-4.1 this is even more important because
1110
 
  there a connection can have several SELECT queries open at the same time.
1111
 
 
1112
 
  @param session           the thread handle of the current connection
1113
 
 
1114
 
  @return
1115
 
    always 0
1116
 
*/
1117
 
static bool release_temporary_latches(Session *session, st_plugin_int *plugin,
1118
 
                                      void *)
1119
 
{
1120
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1121
 
 
1122
 
  if (engine->is_enabled())
1123
 
    engine->release_temporary_latches(session);
1124
 
 
1125
 
  return false;
1126
 
}
1127
 
 
1128
 
 
1129
 
int ha_release_temporary_latches(Session *session)
1130
 
{
1131
 
  plugin_foreach(session, release_temporary_latches, DRIZZLE_STORAGE_ENGINE_PLUGIN,
1132
 
                 NULL);
1133
 
 
1134
 
  return 0;
1135
 
}
1136
875
 
1137
876
int ha_rollback_to_savepoint(Session *session, SAVEPOINT *sv)
1138
877
{
1240
979
}
1241
980
 
1242
981
 
1243
 
static bool snapshot_storage_engine(Session *session, st_plugin_int *plugin, void *arg)
1244
 
{
1245
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1246
 
  if (engine->is_enabled())
1247
 
  {
1248
 
    engine->start_consistent_snapshot(session);
1249
 
    *((bool *)arg)= false;
1250
 
  }
1251
 
  return false;
1252
 
}
1253
 
 
1254
 
int ha_start_consistent_snapshot(Session *session)
1255
 
{
1256
 
  bool warn= true;
1257
 
 
1258
 
  plugin_foreach(session, snapshot_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN, &warn);
1259
 
 
1260
 
  /*
1261
 
    Same idea as when one wants to CREATE TABLE in one engine which does not
1262
 
    exist:
1263
 
  */
1264
 
  if (warn)
1265
 
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1266
 
                 "This Drizzle server does not support any "
1267
 
                 "consistent-read capable storage engine");
1268
 
  return 0;
1269
 
}
1270
 
 
1271
 
 
1272
 
static bool flush_storage_engine(Session *,
1273
 
                             st_plugin_int *plugin,
1274
 
                             void *)
1275
 
{
1276
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1277
 
  if (engine->is_enabled() &&
1278
 
      engine->flush_logs())
1279
 
    return true;
1280
 
  return false;
1281
 
}
1282
 
 
1283
 
 
1284
 
bool ha_flush_logs(StorageEngine *engine)
1285
 
{
1286
 
  if (engine == NULL)
1287
 
  {
1288
 
    if (plugin_foreach(NULL, flush_storage_engine,
1289
 
                          DRIZZLE_STORAGE_ENGINE_PLUGIN, 0))
1290
 
      return true;
1291
 
  }
1292
 
  else
1293
 
  {
1294
 
    if ((!engine->is_enabled()) ||
1295
 
        (engine->flush_logs()))
1296
 
      return true;
1297
 
  }
1298
 
  return false;
1299
 
}
1300
 
 
1301
 
static const char *check_lowercase_names(handler *file, const char *path,
1302
 
                                         char *tmp_path)
1303
 
{
1304
 
  if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
1305
 
    return path;
1306
 
 
1307
 
  /* Ensure that table handler get path in lower case */
1308
 
  if (tmp_path != path)
1309
 
    strcpy(tmp_path, path);
1310
 
 
1311
 
  /*
1312
 
    we only should turn into lowercase database/table part
1313
 
    so start the process after homedirectory
1314
 
  */
1315
 
  my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
1316
 
  return tmp_path;
1317
 
}
1318
 
 
1319
 
 
1320
 
/**
1321
 
  An interceptor to hijack the text of the error message without
1322
 
  setting an error in the thread. We need the text to present it
1323
 
  in the form of a warning to the user.
1324
 
*/
1325
 
 
1326
 
struct Ha_delete_table_error_handler: public Internal_error_handler
1327
 
{
1328
 
public:
1329
 
  Ha_delete_table_error_handler() : Internal_error_handler() {}
1330
 
  virtual bool handle_error(uint32_t sql_errno,
1331
 
                            const char *message,
1332
 
                            DRIZZLE_ERROR::enum_warning_level level,
1333
 
                            Session *session);
1334
 
  char buff[DRIZZLE_ERRMSG_SIZE];
1335
 
};
1336
 
 
1337
 
 
1338
 
bool
1339
 
Ha_delete_table_error_handler::
1340
 
handle_error(uint32_t ,
1341
 
             const char *message,
1342
 
             DRIZZLE_ERROR::enum_warning_level ,
1343
 
             Session *)
1344
 
{
1345
 
  /* Grab the error message */
1346
 
  strncpy(buff, message, sizeof(buff)-1);
1347
 
  return true;
1348
 
}
1349
 
 
1350
 
 
1351
 
struct storage_engine_delete_table_args {
1352
 
  Session *session;
1353
 
  const char *path;
1354
 
  handler *file;
1355
 
  int error;
1356
 
};
1357
 
 
1358
 
static bool deletetable_storage_engine(Session *,
1359
 
                                       st_plugin_int *plugin,
1360
 
                                       void *args)
1361
 
{
1362
 
  struct storage_engine_delete_table_args *dtargs= (struct storage_engine_delete_table_args *) args;
1363
 
 
1364
 
  Session *session= dtargs->session;
1365
 
  const char *path= dtargs->path;
1366
 
 
1367
 
  handler *file;
1368
 
  char tmp_path[FN_REFLEN];
1369
 
 
1370
 
  if(dtargs->error!=ENOENT) /* already deleted table */
1371
 
    return false;
1372
 
 
1373
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1374
 
 
1375
 
  if (!engine)
1376
 
    return false;
1377
 
 
1378
 
  if (!engine->is_enabled())
1379
 
    return false;
1380
 
 
1381
 
  if ((file= engine->create(NULL, session->mem_root)))
1382
 
    file->init();
1383
 
  else
1384
 
    return false;
1385
 
 
1386
 
  path= check_lowercase_names(file, path, tmp_path);
1387
 
  int error= file->ha_delete_table(path);
1388
 
 
1389
 
  if(error!=ENOENT)
1390
 
  {
1391
 
    dtargs->error= error;
1392
 
    if(dtargs->file)
1393
 
      delete dtargs->file;
1394
 
    dtargs->file= file;
1395
 
    return true;
1396
 
  }
1397
 
  else
1398
 
    delete file;
1399
 
 
1400
 
  return false;
1401
 
}
1402
 
 
1403
 
/**
1404
 
  This should return ENOENT if the file doesn't exists.
1405
 
  The .frm file will be deleted only if we return 0 or ENOENT
1406
 
*/
1407
 
int ha_delete_table(Session *session, const char *path,
1408
 
                    const char *db, const char *alias, bool generate_warning)
1409
 
{
1410
 
  TABLE_SHARE dummy_share;
1411
 
  Table dummy_table;
1412
 
 
1413
 
  struct storage_engine_delete_table_args dtargs;
1414
 
  dtargs.error= ENOENT;
1415
 
  dtargs.session= session;
1416
 
  dtargs.path= path;
1417
 
  dtargs.file= NULL;
1418
 
 
1419
 
  plugin_foreach(NULL, deletetable_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN,
1420
 
                 &dtargs);
1421
 
 
1422
 
  memset(&dummy_table, 0, sizeof(dummy_table));
1423
 
  memset(&dummy_share, 0, sizeof(dummy_share));
1424
 
  dummy_table.s= &dummy_share;
1425
 
 
1426
 
  if (dtargs.error && generate_warning)
1427
 
  {
1428
 
    /*
1429
 
      Because file->print_error() use my_error() to generate the error message
1430
 
      we use an internal error handler to intercept it and store the text
1431
 
      in a temporary buffer. Later the message will be presented to user
1432
 
      as a warning.
1433
 
    */
1434
 
    Ha_delete_table_error_handler ha_delete_table_error_handler;
1435
 
 
1436
 
    /* Fill up strucutures that print_error may need */
1437
 
    dummy_share.path.str= (char*) path;
1438
 
    dummy_share.path.length= strlen(path);
1439
 
    dummy_share.db.str= (char*) db;
1440
 
    dummy_share.db.length= strlen(db);
1441
 
    dummy_share.table_name.str= (char*) alias;
1442
 
    dummy_share.table_name.length= strlen(alias);
1443
 
    dummy_table.alias= alias;
1444
 
 
1445
 
    if(dtargs.file)
1446
 
    {
1447
 
      handler *file= dtargs.file;
1448
 
      file->change_table_ptr(&dummy_table, &dummy_share);
1449
 
 
1450
 
      session->push_internal_handler(&ha_delete_table_error_handler);
1451
 
      file->print_error(dtargs.error, 0);
1452
 
 
1453
 
      session->pop_internal_handler();
1454
 
    }
1455
 
    else
1456
 
      dtargs.error= -1; /* General form of fail. maybe bad FRM */
1457
 
 
1458
 
    /*
1459
 
      XXX: should we convert *all* errors to warnings here?
1460
 
      What if the error is fatal?
1461
 
    */
1462
 
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, dtargs.error,
1463
 
                ha_delete_table_error_handler.buff);
1464
 
  }
1465
 
 
1466
 
  if(dtargs.file)
1467
 
    delete dtargs.file;
1468
 
 
1469
 
  return dtargs.error;
1470
 
}
 
982
 
 
983
 
1471
984
 
1472
985
/****************************************************************************
1473
986
** General handler functions
2825
2338
** Some general functions that isn't in the handler class
2826
2339
****************************************************************************/
2827
2340
 
2828
 
/**
2829
 
  Initiates table-file and calls appropriate database-creator.
2830
 
 
2831
 
  @retval
2832
 
   0  ok
2833
 
  @retval
2834
 
   1  error
2835
 
*/
2836
 
int ha_create_table(Session *session, const char *path,
2837
 
                    const char *db, const char *table_name,
2838
 
                    HA_CREATE_INFO *create_info,
2839
 
                    bool update_create_info)
2840
 
{
2841
 
  int error= 1;
2842
 
  Table table;
2843
 
  char name_buff[FN_REFLEN];
2844
 
  const char *name;
2845
 
  TABLE_SHARE share;
2846
 
 
2847
 
  init_tmp_table_share(session, &share, db, 0, table_name, path);
2848
 
  if (open_table_def(session, &share, 0) ||
2849
 
      open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0, &table,
2850
 
                            OTM_CREATE))
2851
 
    goto err;
2852
 
 
2853
 
  if (update_create_info)
2854
 
    table.updateCreateInfo(create_info);
2855
 
 
2856
 
  name= check_lowercase_names(table.file, share.path.str, name_buff);
2857
 
 
2858
 
  error= table.file->ha_create(name, &table, create_info);
2859
 
  table.closefrm(false);
2860
 
  if (error)
2861
 
  {
2862
 
    sprintf(name_buff,"%s.%s",db,table_name);
2863
 
    my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
2864
 
  }
2865
 
err:
2866
 
  free_table_share(&share);
2867
 
  return(error != 0);
2868
 
}
2869
2341
 
2870
2342
void st_ha_check_opt::init()
2871
2343
{
2963
2435
  return 0;
2964
2436
}
2965
2437
 
2966
 
/**
2967
 
  Call this function in order to give the handler the possiblity
2968
 
  to ask engine if there are any new tables that should be written to disk
2969
 
  or any dropped tables that need to be removed from disk
2970
 
*/
2971
 
struct st_find_files_args
2972
 
{
2973
 
  const char *db;
2974
 
  const char *path;
2975
 
  const char *wild;
2976
 
  bool dir;
2977
 
  List<LEX_STRING> *files;
2978
 
};
2979
 
 
2980
 
/**
2981
 
  Ask handler if the table exists in engine.
2982
 
  @retval
2983
 
    HA_ERR_NO_SUCH_TABLE     Table does not exist
2984
 
  @retval
2985
 
    HA_ERR_TABLE_EXIST       Table exists
2986
 
  @retval
2987
 
    \#                  Error code
2988
 
*/
2989
 
struct st_table_exists_in_storage_engine_args
2990
 
{
2991
 
  const char *db;
2992
 
  const char *name;
2993
 
  int err;
2994
 
  StorageEngine* engine;
2995
 
};
2996
 
 
2997
 
static bool table_exists_in_storage_engine(Session *session,
2998
 
                                           st_plugin_int *plugin,
2999
 
                                           void *arg)
3000
 
{
3001
 
  st_table_exists_in_storage_engine_args *vargs= (st_table_exists_in_storage_engine_args *)arg;
3002
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
3003
 
 
3004
 
  int err= HA_ERR_NO_SUCH_TABLE;
3005
 
 
3006
 
  if (engine->is_enabled())
3007
 
    err = engine->table_exists_in_engine(session, vargs->db, vargs->name);
3008
 
 
3009
 
  vargs->err = err;
3010
 
  if (vargs->err == HA_ERR_TABLE_EXIST)
3011
 
  {
3012
 
    vargs->engine= engine;
3013
 
    return true;
3014
 
  }
3015
 
 
3016
 
  return false;
3017
 
}
3018
 
 
3019
 
int ha_table_exists_in_engine(Session* session,
3020
 
                              const char* db, const char* name,
3021
 
                              StorageEngine **engine)
3022
 
{
3023
 
  st_table_exists_in_storage_engine_args args= {db, name, HA_ERR_NO_SUCH_TABLE, NULL};
3024
 
  plugin_foreach(session, table_exists_in_storage_engine,
3025
 
                 DRIZZLE_STORAGE_ENGINE_PLUGIN, &args);
3026
 
 
3027
 
  if(args.err==HA_ERR_NO_SUCH_TABLE)
3028
 
  {
3029
 
    /* Default way of knowing if a table exists. (checking .frm exists) */
3030
 
 
3031
 
    char path[FN_REFLEN];
3032
 
    build_table_filename(path, sizeof(path),
3033
 
                         db, name, "", 0);
3034
 
    if (table_proto_exists(path)==EEXIST)
3035
 
      args.err= HA_ERR_TABLE_EXIST;
3036
 
    else
3037
 
      args.err= HA_ERR_NO_SUCH_TABLE;
3038
 
 
3039
 
    if(args.err==HA_ERR_TABLE_EXIST)
3040
 
    {
3041
 
      drizzle::Table table;
3042
 
      build_table_filename(path, sizeof(path),
3043
 
                           db, name, ".dfe", 0);
3044
 
      if(drizzle_read_table_proto(path, &table)==0)
3045
 
      {
3046
 
        LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
3047
 
                                 strlen(table.engine().name().c_str()) };
3048
 
        st_plugin_int *plugin= ha_resolve_by_name(session, &engine_name);
3049
 
        if(plugin)
3050
 
          args.engine= static_cast<StorageEngine *>(plugin->data);
3051
 
      }
3052
 
    }
3053
 
  }
3054
 
 
3055
 
  if(engine)
3056
 
    *engine= args.engine;
3057
 
 
3058
 
  return(args.err);
3059
 
}
3060
2438
 
3061
2439
/**
3062
2440
  Calculate cost of 'index only' scan for given index and number of records
4071
3449
}
4072
3450
 
4073
3451
 
4074
 
/**
4075
 
  Returns a list of all known extensions.
4076
 
 
4077
 
    No mutexes, worst case race is a minor surplus memory allocation
4078
 
    We have to recreate the extension map if mysqld is restarted (for example
4079
 
    within libmysqld)
4080
 
 
4081
 
  @retval
4082
 
    pointer             pointer to TYPELIB structure
4083
 
*/
4084
 
static bool exts_handlerton(Session *,
4085
 
                            st_plugin_int *plugin,
4086
 
                            void *arg)
4087
 
{
4088
 
  List<char> *found_exts= (List<char> *) arg;
4089
 
  StorageEngine *engine= plugin_data(plugin, StorageEngine *);
4090
 
  handler *file;
4091
 
  if (engine->is_enabled() &&
4092
 
      (file= engine->create((TABLE_SHARE*) 0, current_session->mem_root)))
4093
 
  {
4094
 
    List_iterator_fast<char> it(*found_exts);
4095
 
    const char **ext, *old_ext;
4096
 
 
4097
 
    for (ext= file->bas_ext(); *ext; ext++)
4098
 
    {
4099
 
      while ((old_ext= it++))
4100
 
      {
4101
 
        if (!strcmp(old_ext, *ext))
4102
 
          break;
4103
 
      }
4104
 
      if (!old_ext)
4105
 
        found_exts->push_back((char *) *ext);
4106
 
 
4107
 
      it.rewind();
4108
 
    }
4109
 
    delete file;
4110
 
  }
4111
 
  return false;
4112
 
}
4113
 
 
4114
 
TYPELIB *ha_known_exts(void)
4115
 
{
4116
 
  if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
4117
 
  {
4118
 
    List<char> found_exts;
4119
 
    const char **ext, *old_ext;
4120
 
 
4121
 
    known_extensions_id= mysys_usage_id;
4122
 
 
4123
 
    plugin_foreach(NULL, exts_handlerton,
4124
 
                   DRIZZLE_STORAGE_ENGINE_PLUGIN, &found_exts);
4125
 
 
4126
 
    ext= (const char **) malloc(sizeof(char *)*
4127
 
                                (found_exts.elements+1));
4128
 
                              
4129
 
 
4130
 
    assert(ext != 0);
4131
 
    known_extensions.count= found_exts.elements;
4132
 
    known_extensions.type_names= ext;
4133
 
 
4134
 
    List_iterator_fast<char> it(found_exts);
4135
 
    while ((old_ext= it++))
4136
 
      *ext++= old_ext;
4137
 
    *ext= 0;
4138
 
  }
4139
 
  return &known_extensions;
4140
 
}
4141
 
 
4142
 
 
4143
3452
static bool stat_print(Session *session, const char *type, uint32_t type_len,
4144
3453
                       const char *file, uint32_t file_len,
4145
3454
                       const char *status, uint32_t status_len)